Fix Crystal test class variables and V implementation syntax

- Crystal: Wrap class variables in TestCounter class (top-level @@ not allowed)
- V: Fix deprecated const() syntax to individual const declarations
- V: Fix os.execute or-blocks to use exit_code checks
- V: Fix shell variable escaping (use $ for literal $ in shell strings)
- README: Add unit test documentation and CI badge

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Russell Ballestrini 2026-01-06 09:57:49 -05:00
parent 160740e1ea
commit 9329d9365f
3 changed files with 94 additions and 38 deletions

View file

@ -179,6 +179,36 @@ Each implementation supports:
./tests/run_all_tests.sh
```
### Unit Tests
Every implementation has unit tests that verify core functionality without requiring API calls:
```bash
# Run unit tests for any language
python3 tests/unit/test_python.py
node tests/unit/test_javascript.js
ruby tests/unit/test_ruby.rb
go test -v tests/unit/test_go.go
julia tests/unit/test_julia.jl
elixir tests/unit/test_elixir.exs
```
Unit tests cover:
- **Extension mapping** - File extensions map to correct languages
- **HMAC signatures** - SHA256 signing produces valid 64-char hex strings
- **Signature format** - Message format is `timestamp:METHOD:path:body`
- **Language detection** - Shebang parsing and extension detection
- **Argument parsing** - `-e KEY=VALUE` format handling
- **File operations** - Base64 encoding, path extraction
### CI/CD
GitHub Actions runs the full test matrix on every push:
[![Inception Matrix](https://github.com/russellballestrini/un-inception/actions/workflows/inception-matrix.yml/badge.svg)](https://github.com/russellballestrini/un-inception/actions/workflows/inception-matrix.yml)
The workflow tests all 42 implementations across their respective runtimes.
## The Inception Matrix
**Use un to run un inside un!** Don't have a language installed locally? Run its implementation through unsandbox using `un` (the C implementation):

View file

@ -11,9 +11,27 @@ RED = "\033[31m"
BLUE = "\033[34m"
RESET = "\033[0m"
# Test counters
@@passed = 0
@@failed = 0
# Test counters - use class with class variables
class TestCounter
@@passed = 0
@@failed = 0
def self.passed
@@passed
end
def self.failed
@@failed
end
def self.inc_passed
@@passed += 1
end
def self.inc_failed
@@failed += 1
end
end
# Extension to language mapping (from un.cr)
EXT_MAP = {
@ -44,10 +62,10 @@ end
def print_test(name : String, result : Bool)
if result
puts "#{GREEN}✓ PASS#{RESET}: #{name}"
@@passed += 1
TestCounter.inc_passed
else
puts "#{RED}✗ FAIL#{RESET}: #{name}"
@@failed += 1
TestCounter.inc_failed
end
end
@ -143,11 +161,11 @@ print_test("Multiple dots in filename", detect_language("my.test.py") == "python
puts "\n#{BLUE}========================================#{RESET}"
puts "#{BLUE}Test Summary#{RESET}"
puts "#{BLUE}========================================#{RESET}"
puts "#{GREEN}Passed: #{@@passed}#{RESET}"
puts "#{RED}Failed: #{@@failed}#{RESET}"
puts "#{BLUE}Total: #{@@passed + @@failed}#{RESET}"
puts "#{GREEN}Passed: #{TestCounter.passed}#{RESET}"
puts "#{RED}Failed: #{TestCounter.failed}#{RESET}"
puts "#{BLUE}Total: #{TestCounter.passed + TestCounter.failed}#{RESET}"
if @@failed > 0
if TestCounter.failed > 0
puts "\n#{RED}TESTS FAILED#{RESET}"
exit 1
else

66
un.v
View file

@ -45,15 +45,13 @@
import os
const (
api_base = 'https://api.unsandbox.com'
portal_base = 'https://unsandbox.com'
blue = '\x1b[34m'
red = '\x1b[31m'
green = '\x1b[32m'
yellow = '\x1b[33m'
reset = '\x1b[0m'
)
const api_base = 'https://api.unsandbox.com'
const portal_base = 'https://unsandbox.com'
const blue = '\x1b[34m'
const red = '\x1b[31m'
const green = '\x1b[32m'
const yellow = '\x1b[33m'
const reset = '\x1b[0m'
fn detect_language(filename string) !string {
ext := os.file_ext(filename)
@ -162,7 +160,7 @@ fn cmd_key(extend bool, api_key string) {
pub_key := get_public_key()
secret_key := get_secret_key()
body := '{}'
cmd := "BODY='${body}'; TIMESTAMP=\\$(date +%s); MESSAGE=\"\\$TIMESTAMP:POST:/keys/validate:\\$BODY\"; SIGNATURE=\\$(echo -n \"\\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${portal_base}/keys/validate' -H 'Content-Type: application/json' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \\$TIMESTAMP\" -H \"X-Signature: \\$SIGNATURE\" -d \"\\$BODY\""
cmd := "BODY='${body}'; TIMESTAMP=\$\$(date +%s); MESSAGE=\"\$\$TIMESTAMP:POST:/keys/validate:\$\$BODY\"; SIGNATURE=\$\$(echo -n \"\$\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${portal_base}/keys/validate' -H 'Content-Type: application/json' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \$\$TIMESTAMP\" -H \"X-Signature: \$\$SIGNATURE\" -d \"\$\$BODY\""
result := exec_curl(cmd)
public_key := extract_json_string(result, 'public_key')
@ -180,11 +178,21 @@ fn cmd_key(extend bool, api_key string) {
println('${blue}Opening browser to extend key...${reset}')
// Try xdg-open (Linux), open (macOS), or start (Windows)
os.execute('xdg-open "${url}"') or {
os.execute('open "${url}"') or {
os.execute('cmd /c start "${url}"') or {
eprintln('${red}Error: Could not open browser${reset}')
}
mut opened := false
result := os.execute('xdg-open "${url}"')
if result.exit_code == 0 {
opened = true
}
if !opened {
result2 := os.execute('open "${url}"')
if result2.exit_code == 0 {
opened = true
}
}
if !opened {
result3 := os.execute('cmd /c start "${url}"')
if result3.exit_code != 0 {
eprintln('${red}Error: Could not open browser${reset}')
}
}
return
@ -267,7 +275,7 @@ fn cmd_execute(source_file string, envs []string, artifacts bool, network string
pub_key := get_public_key()
secret_key := get_secret_key()
cmd := "BODY='${json}'; TIMESTAMP=\\$(date +%s); MESSAGE=\"\\$TIMESTAMP:POST:/execute:\\$BODY\"; SIGNATURE=\\$(echo -n \"\\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/execute' -H 'Content-Type: application/json' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \\$TIMESTAMP\" -H \"X-Signature: \\$SIGNATURE\" -d \"\\$BODY\""
cmd := "BODY='${json}'; TIMESTAMP=\$\$(date +%s); MESSAGE=\"\$\$TIMESTAMP:POST:/execute:\$\$BODY\"; SIGNATURE=\$\$(echo -n \"\$\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/execute' -H 'Content-Type: application/json' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \$\$TIMESTAMP\" -H \"X-Signature: \$\$SIGNATURE\" -d \"\$\$BODY\""
println(exec_curl(cmd))
}
@ -276,13 +284,13 @@ fn cmd_session(list bool, kill string, shell string, network string, vcpu int, t
secret_key := get_secret_key()
if list {
cmd := "TIMESTAMP=\\$(date +%s); MESSAGE=\"\\$TIMESTAMP:GET:/sessions:\"; SIGNATURE=\\$(echo -n \"\\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X GET '${api_base}/sessions' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \\$TIMESTAMP\" -H \"X-Signature: \\$SIGNATURE\""
cmd := "TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:GET:/sessions:\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X GET '${api_base}/sessions' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\""
println(exec_curl(cmd))
return
}
if kill != '' {
cmd := "TIMESTAMP=\\$(date +%s); MESSAGE=\"\\$TIMESTAMP:DELETE:/sessions/${kill}:\"; SIGNATURE=\\$(echo -n \"\\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X DELETE '${api_base}/sessions/${kill}' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \\$TIMESTAMP\" -H \"X-Signature: \\$SIGNATURE\""
cmd := "TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:DELETE:/sessions/${kill}:\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X DELETE '${api_base}/sessions/${kill}' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\""
exec_curl(cmd)
println('${green}Session terminated: ${kill}${reset}')
return
@ -306,7 +314,7 @@ fn cmd_session(list bool, kill string, shell string, network string, vcpu int, t
json += '}'
println('${yellow}Creating session...${reset}')
cmd := "BODY='${json}'; TIMESTAMP=\\$(date +%s); MESSAGE=\"\\$TIMESTAMP:POST:/sessions:\\$BODY\"; SIGNATURE=\\$(echo -n \"\\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/sessions' -H 'Content-Type: application/json' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \\$TIMESTAMP\" -H \"X-Signature: \\$SIGNATURE\" -d \"\\$BODY\""
cmd := "BODY='${json}'; TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:POST:/sessions:$$BODY\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/sessions' -H 'Content-Type: application/json' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\" -d \"$$BODY\""
println(exec_curl(cmd))
}
@ -315,45 +323,45 @@ fn cmd_service(name string, ports string, service_type string, bootstrap string,
secret_key := get_secret_key()
if list {
cmd := "TIMESTAMP=\\$(date +%s); MESSAGE=\"\\$TIMESTAMP:GET:/services:\"; SIGNATURE=\\$(echo -n \"\\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X GET '${api_base}/services' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \\$TIMESTAMP\" -H \"X-Signature: \\$SIGNATURE\""
cmd := "TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:GET:/services:\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X GET '${api_base}/services' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\""
println(exec_curl(cmd))
return
}
if info != '' {
cmd := "TIMESTAMP=\\$(date +%s); MESSAGE=\"\\$TIMESTAMP:GET:/services/${info}:\"; SIGNATURE=\\$(echo -n \"\\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X GET '${api_base}/services/${info}' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \\$TIMESTAMP\" -H \"X-Signature: \\$SIGNATURE\""
cmd := "TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:GET:/services/${info}:\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X GET '${api_base}/services/${info}' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\""
println(exec_curl(cmd))
return
}
if logs != '' {
cmd := "TIMESTAMP=\\$(date +%s); MESSAGE=\"\\$TIMESTAMP:GET:/services/${logs}/logs:\"; SIGNATURE=\\$(echo -n \"\\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X GET '${api_base}/services/${logs}/logs' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \\$TIMESTAMP\" -H \"X-Signature: \\$SIGNATURE\""
cmd := "TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:GET:/services/${logs}/logs:\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X GET '${api_base}/services/${logs}/logs' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\""
print(exec_curl(cmd))
return
}
if tail != '' {
cmd := "TIMESTAMP=\\$(date +%s); MESSAGE=\"\\$TIMESTAMP:GET:/services/${tail}/logs:\"; SIGNATURE=\\$(echo -n \"\\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X GET '${api_base}/services/${tail}/logs?lines=9000' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \\$TIMESTAMP\" -H \"X-Signature: \\$SIGNATURE\""
cmd := "TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:GET:/services/${tail}/logs:\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X GET '${api_base}/services/${tail}/logs?lines=9000' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\""
print(exec_curl(cmd))
return
}
if sleep != '' {
cmd := "TIMESTAMP=\\$(date +%s); MESSAGE=\"\\$TIMESTAMP:POST:/services/${sleep}/sleep:\"; SIGNATURE=\\$(echo -n \"\\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/services/${sleep}/sleep' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \\$TIMESTAMP\" -H \"X-Signature: \\$SIGNATURE\""
cmd := "TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:POST:/services/${sleep}/sleep:\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/services/${sleep}/sleep' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\""
exec_curl(cmd)
println('${green}Service sleeping: ${sleep}${reset}')
return
}
if wake != '' {
cmd := "TIMESTAMP=\\$(date +%s); MESSAGE=\"\\$TIMESTAMP:POST:/services/${wake}/wake:\"; SIGNATURE=\\$(echo -n \"\\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/services/${wake}/wake' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \\$TIMESTAMP\" -H \"X-Signature: \\$SIGNATURE\""
cmd := "TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:POST:/services/${wake}/wake:\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/services/${wake}/wake' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\""
exec_curl(cmd)
println('${green}Service waking: ${wake}${reset}')
return
}
if destroy != '' {
cmd := "TIMESTAMP=\\$(date +%s); MESSAGE=\"\\$TIMESTAMP:DELETE:/services/${destroy}:\"; SIGNATURE=\\$(echo -n \"\\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X DELETE '${api_base}/services/${destroy}' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \\$TIMESTAMP\" -H \"X-Signature: \\$SIGNATURE\""
cmd := "TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:DELETE:/services/${destroy}:\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X DELETE '${api_base}/services/${destroy}' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\""
exec_curl(cmd)
println('${green}Service destroyed: ${destroy}${reset}')
return
@ -361,7 +369,7 @@ fn cmd_service(name string, ports string, service_type string, bootstrap string,
if execute != '' {
json := '{"command":"${escape_json(command)}"}'
cmd := "BODY='${json}'; TIMESTAMP=\\$(date +%s); MESSAGE=\"\\$TIMESTAMP:POST:/services/${execute}/execute:\\$BODY\"; SIGNATURE=\\$(echo -n \"\\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/services/${execute}/execute' -H 'Content-Type: application/json' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \\$TIMESTAMP\" -H \"X-Signature: \\$SIGNATURE\" -d \"\\$BODY\""
cmd := "BODY='${json}'; TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:POST:/services/${execute}/execute:$$BODY\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/services/${execute}/execute' -H 'Content-Type: application/json' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\" -d \"$$BODY\""
result := exec_curl(cmd)
stdout_str := extract_json_string(result, 'stdout')
@ -378,7 +386,7 @@ fn cmd_service(name string, ports string, service_type string, bootstrap string,
if dump_bootstrap != '' {
eprintln('Fetching bootstrap script from ${dump_bootstrap}...')
json := '{"command":"cat /tmp/bootstrap.sh"}'
cmd := "BODY='${json}'; TIMESTAMP=\\$(date +%s); MESSAGE=\"\\$TIMESTAMP:POST:/services/${dump_bootstrap}/execute:\\$BODY\"; SIGNATURE=\\$(echo -n \"\\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/services/${dump_bootstrap}/execute' -H 'Content-Type: application/json' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \\$TIMESTAMP\" -H \"X-Signature: \\$SIGNATURE\" -d \"\\$BODY\""
cmd := "BODY='${json}'; TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:POST:/services/${dump_bootstrap}/execute:$$BODY\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/services/${dump_bootstrap}/execute' -H 'Content-Type: application/json' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\" -d \"$$BODY\""
result := exec_curl(cmd)
bootstrap_script := extract_json_string(result, 'stdout')
@ -433,7 +441,7 @@ fn cmd_service(name string, ports string, service_type string, bootstrap string,
json += '}'
println('${yellow}Creating service...${reset}')
cmd := "BODY='${json}'; TIMESTAMP=\\$(date +%s); MESSAGE=\"\\$TIMESTAMP:POST:/services:\\$BODY\"; SIGNATURE=\\$(echo -n \"\\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/services' -H 'Content-Type: application/json' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \\$TIMESTAMP\" -H \"X-Signature: \\$SIGNATURE\" -d \"\\$BODY\""
cmd := "BODY='${json}'; TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:POST:/services:$$BODY\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/services' -H 'Content-Type: application/json' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\" -d \"$$BODY\""
println(exec_curl(cmd))
return
}