Add comprehensive testing infrastructure for UN clients: 1. Smart Change Detection (detect-changes.sh) - Detects changes in BOTH root-level (un.py, un.go) AND clients/ directory - Maps file extensions and directory names to languages - Triggers test_all when infrastructure changes 2. Language-Specific CI Matrix (generate-matrix.sh compatible) - Only runs tests for languages with changes - Example: modify clients/python/ → pytest runs, Go/Ruby skipped 3. Testing Strategy Document (TESTING-STRATEGY.md) - Complete testing matrix by language tier (compiled, interpreted, inception) - Unit, integration, embedding, and parity tests - Inception pattern for languages without local interpreters - Common failures and fixes - Rollout schedule for client/ migration 4. Makefile Targets - 'make test-python', 'make test-go', etc. for local development - 'make test-all' for comprehensive testing - 'make test-integration' for API contract validation - 'make test-ci-locally' to simulate CI pipeline 5. Updated CLAUDE.md - Documents SDK architecture (in growth state) - Explains three purposes: CLI, library, embeddable - References TESTING-STRATEGY.md for details This enables: ✓ Per-language testing (only run what changed) ✓ Local developer workflow (make test-LANG) ✓ 42+ language feature parity validation ✓ Cross-language integration testing
407 lines
10 KiB
Markdown
407 lines
10 KiB
Markdown
# Testing Strategy for Multi-Language UN Clients
|
|
|
|
## Overview
|
|
|
|
UN Inception implements the UN CLI in 42+ languages. Each implementation serves as:
|
|
1. **Standalone CLI** - Full featured command-line tool
|
|
2. **Client Library** - Importable SDK for other projects
|
|
3. **Embeddable** - Can be bundled/copied into other projects
|
|
|
|
**Goal**: Ensure all clients work correctly as the codebase evolves while only running necessary tests.
|
|
|
|
---
|
|
|
|
## Smart Change Detection
|
|
|
|
The CI pipeline uses **smart change detection** to run only relevant tests:
|
|
|
|
### How it Works
|
|
|
|
1. **Pre-stage: detect-changes.sh**
|
|
- Compares HEAD with origin/main
|
|
- Identifies which languages/clients changed
|
|
- Generates `changes.json` with affected languages
|
|
|
|
2. **Pre-stage: generate-matrix.sh**
|
|
- Reads `changes.json`
|
|
- Generates `test-matrix.yml` with only needed test jobs
|
|
- Includes cross-language validation for all clients
|
|
|
|
3. **Test Stage**
|
|
- Dynamic job inclusion from `test-matrix.yml`
|
|
- Only language-specific tests run when that language changed
|
|
- Always includes integration tests (API contract validation)
|
|
|
|
### Example: Changes in clients/python/
|
|
|
|
```json
|
|
{
|
|
"changed_clients": ["python"],
|
|
"root_implementations": [],
|
|
"test_matrix": {
|
|
"python": {
|
|
"test_script": "pytest tests/test_un_py.py -v",
|
|
"environment": ["python3"],
|
|
"should_run": true
|
|
},
|
|
"integration": {
|
|
"test_script": "bash tests/integration-all-clients.sh",
|
|
"should_run": true
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Supported Change Patterns
|
|
|
|
| Changed File | Triggered Tests |
|
|
|---|---|
|
|
| `clients/python/*` | Python tests + integration |
|
|
| `clients/go/*` | Go tests + integration |
|
|
| `clients/javascript/*` | Node.js/TypeScript tests + integration |
|
|
| `clients/*/tests/*` | Language tests + integration |
|
|
| `test/` (shared tests) | All language tests + integration |
|
|
| `un.c` (root) | C tests + integration + all clients (fundamental change) |
|
|
| `un.py` (root) | Python tests + integration |
|
|
| `CLAUDE.md` | Documentation validation only |
|
|
|
|
---
|
|
|
|
## Testing Matrix by Language
|
|
|
|
### Tier 1: Compiled Languages (Fast)
|
|
|
|
These languages have fast compilation and test cycles.
|
|
|
|
#### Go
|
|
- **File**: `clients/go/un.go`
|
|
- **Tests**: `go test ./...`
|
|
- **Integration**: `bash tests/integration-go-client.sh`
|
|
- **Time**: ~5 seconds
|
|
|
|
```bash
|
|
cd clients/go
|
|
go test -v
|
|
go run un.go test/fib.py
|
|
```
|
|
|
|
#### Rust
|
|
- **File**: `clients/rust/un.rs`
|
|
- **Tests**: `cargo test`
|
|
- **Integration**: `bash tests/integration-rust-client.sh`
|
|
- **Time**: ~10 seconds (cached)
|
|
|
|
```bash
|
|
cd clients/rust
|
|
cargo test --release
|
|
cargo run -- test/fib.py
|
|
```
|
|
|
|
#### C/C++
|
|
- **File**: `clients/c/un.c` OR `clients/cpp/un.cpp`
|
|
- **Build**: `gcc un.c -o un -lssl -lcrypto` OR `g++ un.cpp -o un`
|
|
- **Tests**: `bash tests/test_un_c.sh`
|
|
- **Integration**: `./un test/fib.py`
|
|
- **Time**: ~2 seconds
|
|
|
|
#### Java
|
|
- **File**: `clients/java/Un.java`
|
|
- **Compile**: `javac Un.java`
|
|
- **Tests**: `java -cp . Un test/fib.py`
|
|
- **Integration**: Full feature test suite
|
|
- **Time**: ~8 seconds (warm JVM)
|
|
|
|
### Tier 2: Interpreted Languages (Medium)
|
|
|
|
These have runtime interpretation but fast test cycles.
|
|
|
|
#### Python
|
|
- **File**: `clients/python/un.py`
|
|
- **Tests**:
|
|
```bash
|
|
pytest tests/test_un_py.py -v
|
|
python3 -m py_compile clients/python/un.py # Syntax check
|
|
python3 clients/python/un.py test/fib.py # Integration
|
|
```
|
|
- **Async Support**: Tests both sync and async client modes
|
|
- **Time**: ~3 seconds
|
|
|
|
#### JavaScript/TypeScript
|
|
- **File**: `clients/javascript/un.js` (Node.js)
|
|
- **Tests**:
|
|
```bash
|
|
node tests/test_un_js.js
|
|
npx eslint clients/javascript/un.js # Linting
|
|
node clients/javascript/un.js test/fib.py
|
|
```
|
|
- **Time**: ~2 seconds
|
|
|
|
#### Ruby
|
|
- **File**: `clients/ruby/un.rb`
|
|
- **Tests**:
|
|
```bash
|
|
ruby -w clients/ruby/un.rb test/fib.py # Syntax + execution
|
|
ruby tests/test_un_rb.rb
|
|
```
|
|
- **Time**: ~2 seconds
|
|
|
|
#### PHP
|
|
- **File**: `clients/php/un.php`
|
|
- **Tests**:
|
|
```bash
|
|
php -l clients/php/un.php # Syntax check
|
|
php clients/php/un.php test/fib.py # Integration
|
|
php -d display_errors=1 tests/test_un_php.php
|
|
```
|
|
- **Time**: ~2 seconds
|
|
|
|
#### Bash/Shell
|
|
- **File**: `clients/bash/un.sh`
|
|
- **Tests**:
|
|
```bash
|
|
bash -n clients/bash/un.sh # Syntax check
|
|
shellcheck clients/bash/un.sh # Linting
|
|
bash clients/bash/un.sh test/fib.py
|
|
```
|
|
- **Time**: ~1 second
|
|
|
|
### Tier 3: Languages Requiring Inception
|
|
|
|
These languages may not be installed locally. Use the **Inception Pattern** to test via unsandbox itself.
|
|
|
|
#### Haskell, Julia, Clojure, Erlang, etc.
|
|
- **Pattern**: Use `un` (C implementation) to execute the language implementation through unsandbox
|
|
- **Command**:
|
|
```bash
|
|
un -n semitrusted \
|
|
-e UNSANDBOX_PUBLIC_KEY=$UNSANDBOX_PUBLIC_KEY \
|
|
-e UNSANDBOX_SECRET_KEY=$UNSANDBOX_SECRET_KEY \
|
|
clients/haskell/un.hs test/fib.py
|
|
```
|
|
- **Time**: ~6 seconds (network + unsandbox execution)
|
|
|
|
---
|
|
|
|
## Test Categories
|
|
|
|
### 1. Unit Tests
|
|
**Test**: Language-specific syntax and core logic
|
|
|
|
```bash
|
|
# Each language tests its specific features
|
|
pytest tests/test_un_py.py
|
|
go test ./clients/go/...
|
|
cargo test -p un_client
|
|
ruby tests/test_un_rb.rb
|
|
```
|
|
|
|
**What fails here**: Syntax errors, missing dependencies, core logic bugs
|
|
|
|
### 2. Integration Tests (API Contract)
|
|
**Test**: All clients communicate correctly with the API
|
|
|
|
```bash
|
|
# Test EVERY client can:
|
|
# ✓ Authenticate (HMAC signature generation)
|
|
# ✓ Execute code (run test/fib.py via API)
|
|
# ✓ Handle responses
|
|
# ✓ Respect error codes
|
|
|
|
bash tests/integration-all-clients.sh
|
|
```
|
|
|
|
**What fails here**: Authentication issues, API schema changes, network problems
|
|
|
|
### 3. Embedding Tests
|
|
**Test**: Client can be imported/embedded in other code
|
|
|
|
```python
|
|
# Python: Can import the client
|
|
from clients.python.un import UnsandboxClient
|
|
client = UnsandboxClient()
|
|
```
|
|
|
|
```javascript
|
|
// JavaScript: Can require the module
|
|
const { UnsandboxClient } = require('./clients/javascript/un.js');
|
|
```
|
|
|
|
**What fails here**: Export/import structure, module API incompatibility
|
|
|
|
### 4. Parity Tests (CI/Feature Checklist)
|
|
**Test**: All clients have feature parity
|
|
|
|
Verify all 42+ clients support:
|
|
- ✓ Execute: `un file.py`
|
|
- ✓ Session: `un session`
|
|
- ✓ Service: `un service`
|
|
- ✓ All flags: `-e`, `-f`, `-n`, `-a`, `--tmux`, `--screen`, etc.
|
|
|
|
```bash
|
|
bash tests/feature-parity-matrix.sh
|
|
```
|
|
|
|
**What fails here**: Missing features, argument parsing bugs, logic differences
|
|
|
|
---
|
|
|
|
## CI Pipeline Structure
|
|
|
|
### Stage: Pre (Change Detection)
|
|
```
|
|
detect-changes.sh → changes.json
|
|
generate-matrix.sh → test-matrix.yml (dynamic jobs)
|
|
```
|
|
|
|
### Stage: Build
|
|
```
|
|
build-clients.sh → Compile/prepare all changed clients
|
|
```
|
|
|
|
### Stage: Test (Dynamic)
|
|
```
|
|
include: test-matrix.yml ← Dynamically generated per-language jobs
|
|
test-python.sh (only if clients/python/* changed)
|
|
test-go.sh (only if clients/go/* changed)
|
|
test-javascript.sh (only if clients/javascript/* changed)
|
|
...
|
|
integration-all.sh (always runs - validates all clients)
|
|
```
|
|
|
|
### Stage: Science (Pool Burning)
|
|
```
|
|
lint-all-sdks.sh → Code quality for all clients
|
|
benchmark-clients.sh → Performance comparison
|
|
validate-examples.sh → Real-world examples work
|
|
```
|
|
|
|
### Stage: Validate & Report
|
|
```
|
|
Summary of test results, coverage, and quality metrics
|
|
```
|
|
|
|
---
|
|
|
|
## Local Development
|
|
|
|
### Running All Tests Locally
|
|
|
|
```bash
|
|
# Set environment
|
|
export UNSANDBOX_PUBLIC_KEY="unsb-pk-..."
|
|
export UNSANDBOX_SECRET_KEY="unsb-sk-..."
|
|
|
|
# Run everything
|
|
./tests/run_all_tests.sh
|
|
|
|
# Or run specific language
|
|
make test-python
|
|
make test-go
|
|
make test-javascript
|
|
make test-ruby
|
|
make test-php
|
|
```
|
|
|
|
### Testing a Specific Client After Changes
|
|
|
|
```bash
|
|
# After editing clients/python/un.py
|
|
cd clients/python
|
|
pytest -v
|
|
python3 -m py_compile un.py
|
|
python3 un.py test/fib.py
|
|
python3 un.py session # Interactive test
|
|
python3 un.py service --help
|
|
```
|
|
|
|
### Testing Without Local Interpreter (Inception)
|
|
|
|
```bash
|
|
# Don't have Haskell installed? Test it via unsandbox
|
|
un -n semitrusted \
|
|
-e UNSANDBOX_PUBLIC_KEY=$UNSANDBOX_PUBLIC_KEY \
|
|
-e UNSANDBOX_SECRET_KEY=$UNSANDBOX_SECRET_KEY \
|
|
clients/haskell/un.hs test/fib.py
|
|
|
|
# Test ALL languages via inception (if needed)
|
|
bash tests/inception-test-all.sh
|
|
```
|
|
|
|
---
|
|
|
|
## Common Failures & Fixes
|
|
|
|
### Python Tests Fail
|
|
```
|
|
❌ ModuleNotFoundError: No module named 'X'
|
|
✓ Fix: pip install -r clients/python/requirements.txt
|
|
|
|
❌ HMAC signature mismatch
|
|
✓ Fix: Verify authentication code in un.py matches other clients
|
|
|
|
❌ Import error when embedded
|
|
✓ Fix: Ensure no absolute imports, use relative imports for bundling
|
|
```
|
|
|
|
### Go Tests Fail
|
|
```
|
|
❌ go.mod not found
|
|
✓ Fix: cd clients/go && go mod init clients/go
|
|
|
|
❌ Module not found after changes
|
|
✓ Fix: go mod tidy
|
|
|
|
❌ Compilation error with crypto
|
|
✓ Fix: Ensure Go 1.16+ (crypto/hmac in stdlib)
|
|
```
|
|
|
|
### JavaScript Tests Fail
|
|
```
|
|
❌ Cannot find module
|
|
✓ Fix: npm install in clients/javascript
|
|
|
|
❌ Async/await not working
|
|
✓ Fix: Ensure Node.js version supports async/await (>7.6.0)
|
|
```
|
|
|
|
### Integration Fails (All Languages)
|
|
```
|
|
❌ 401 Unauthorized
|
|
✓ Fix: HMAC signature generation - compare with C reference (un.c)
|
|
|
|
❌ 503 API unavailable
|
|
✓ Fix: Check api.unsandbox.com is up and accessible
|
|
|
|
❌ Client hangs/timeout
|
|
✓ Fix: Check network access, proxy settings, firewall rules
|
|
```
|
|
|
|
---
|
|
|
|
## Rollout Schedule
|
|
|
|
| Phase | Goal | Timeline |
|
|
|---|---|---|
|
|
| Phase 1 (Now) | Setup clients/ structure, smart CI | This week |
|
|
| Phase 2 | Migrate top 10 languages to clients/ | 2 weeks |
|
|
| Phase 3 | Migrate remaining 32 languages | 4 weeks |
|
|
| Phase 4 | Deprecate root un.* files | 8 weeks |
|
|
| Phase 5 | Archive/document legacy implementations | Optional |
|
|
|
|
---
|
|
|
|
## Metrics & Coverage
|
|
|
|
**Success Criteria**:
|
|
- ✓ All test jobs pass
|
|
- ✓ Each language has unit tests
|
|
- ✓ Each language has integration tests
|
|
- ✓ Feature parity matrix 100% (all 42 features in all 42 languages)
|
|
- ✓ CI matrix correctly detects changes and skips irrelevant tests
|
|
- ✓ No false positives (unrelated changes don't trigger irrelevant tests)
|
|
|
|
**Tracking**:
|
|
- Build time by language (identify slow tests)
|
|
- Test coverage by client
|
|
- Feature parity matrix (visual dashboard)
|
|
- Inception test success rate (languages tested via unsandbox)
|