diff --git a/clients/c/Makefile b/clients/c/Makefile
index e921984..3c3a1bf 100644
--- a/clients/c/Makefile
+++ b/clients/c/Makefile
@@ -35,6 +35,9 @@ RED := \033[31m
YELLOW := \033[33m
NC := \033[0m
+# CLI binary (for inception testing)
+CLI := un
+
.DEFAULT_GOAL := build
help:
@@ -57,7 +60,15 @@ help:
all: build
-build: lib examples
+build: cli lib examples
+
+cli: $(CLI)
+ @echo "$(GREEN)✓$(NC) CLI binary built: $(CLI)"
+
+$(CLI): $(SRC) $(HEADER)
+ @echo "Building CLI binary..."
+ $(CC) $(CFLAGS) -o $@ $(SRC) $(LDFLAGS)
+ @echo "$(GREEN)✓$(NC) Built: $@"
lib: $(SRC) $(HEADER)
@echo "$(GREEN)✓$(NC) Library files ready:"
@@ -122,7 +133,9 @@ $(TEST_DIR)/test_functional: $(TEST_DIR)/test_functional.c $(SRC) $(HEADER)
# ============================================================================
clean:
+ rm -f $(CLI)
rm -f $(TEST_DIR)/test_library
+ rm -f $(TEST_DIR)/test_functional
rm -f $(EXAMPLES_DIR)/hello_world
rm -f $(EXAMPLES_DIR)/fibonacci
rm -f $(EXAMPLES_DIR)/*.o
diff --git a/scripts/build-clients.sh b/scripts/build-clients.sh
index 06c6a56..1bc5f16 100755
--- a/scripts/build-clients.sh
+++ b/scripts/build-clients.sh
@@ -1,27 +1,31 @@
#!/bin/bash
-# Build SDKs that changed (or all for tag releases)
+# Build SDKs - primarily the C CLI for inception testing
set -e
mkdir -p build
-# For now, just copy the un.* files to build/
-# Real build system would compile C, Go, Rust, etc.
-echo "Building SDKs..."
+echo "Building C CLI for inception testing..."
-# Interpreted languages just copy
-for LANG in python javascript typescript php perl lua bash; do
- if [ -f "un.$LANG" ] || [ -f "un.${LANG:0:2}" ]; then
- cp un.* build/ 2>/dev/null || true
- echo "✓ Copied $LANG SDK"
- fi
-done
+# Build the C CLI binary
+if [ -d "clients/c" ] && [ -f "clients/c/Makefile" ]; then
+ make -C clients/c cli
+ cp clients/c/un build/un
+ echo "✓ Built C CLI: build/un"
+else
+ echo "ERROR: clients/c not found"
+ exit 1
+fi
-# Compiled languages would build here
-# go: CGO_ENABLED=0 go build -o build/un_go un.go
-# rust: cargo build --release --quiet
-# c: gcc -O3 un.c -o build/un_c
-# etc.
+# Verify the binary works
+if [ -x "build/un" ]; then
+ echo "✓ CLI binary is executable"
+ build/un --version || echo "(version check skipped - may need API keys)"
+else
+ echo "ERROR: build/un not executable"
+ exit 1
+fi
-echo "Build complete"
+echo ""
+echo "Build complete. The 'un' binary can now run inception tests."
ls -lh build/
diff --git a/scripts/generate-matrix.sh b/scripts/generate-matrix.sh
index bca5edf..8aab5f2 100755
--- a/scripts/generate-matrix.sh
+++ b/scripts/generate-matrix.sh
@@ -9,13 +9,16 @@ CHANGES=$(cat changes.json)
CHANGED_LANGS=$(echo "$CHANGES" | jq -r '.changed_langs[]' 2>/dev/null || echo "")
TEST_ALL=$(echo "$CHANGES" | jq -r '.test_all' 2>/dev/null || echo "false")
-# If test_all is true or no changes detected, generate comprehensive matrix
-# Now includes Python and C with full SDK support
+# Available SDKs in clients/ directory
+# These are the languages that have full SDK implementations
+ALL_SDKS="python javascript go ruby php java rust"
+
if [ "$TEST_ALL" = "true" ]; then
- LANGS="python javascript typescript go ruby php perl lua bash rust java csharp cpp c haskell kotlin elixir erlang crystal dart nim julia r groovy clojure fsharp ocaml objc d vlang zig fortran cobol scheme lisp tcl awk prolog forth powershell raku"
+ LANGS="$ALL_SDKS"
elif [ -z "$CHANGED_LANGS" ]; then
- # No changes - don't generate any jobs
- echo "# No SDK changes detected"
+ # No changes - don't generate any test jobs
+ echo "# No SDK changes detected - no tests to run" > test-matrix.yml
+ cat test-matrix.yml
exit 0
else
LANGS="$CHANGED_LANGS"
@@ -23,46 +26,40 @@ fi
# Start generating test-matrix.yml
cat > test-matrix.yml << 'EOF'
-# Dynamically generated test matrix based on changed SDKs
+# Dynamically generated test matrix - inception tests for changed SDKs
+# Each test runs: build/un → unsandbox → SDK → unsandbox → test code
+
test:
stage: test
tags:
- build
+ needs:
+ - build
parallel:
matrix:
EOF
# Add each language as a parallel job
-FIRST=true
for LANG in $LANGS; do
- if [ "$FIRST" = true ]; then
- echo " - SDK_LANG: $LANG" >> test-matrix.yml
- FIRST=false
- else
- echo " - SDK_LANG: $LANG" >> test-matrix.yml
- fi
+ echo " - SDK_LANG: $LANG" >> test-matrix.yml
done
# Complete the test job template
cat >> test-matrix.yml << 'EOF'
script:
- - export TEST_LANG=$SDK_LANG
- - |
- echo "Testing $TEST_LANG..."
- if [ ! -d "clients" ]; then
- echo "ERROR: clients directory not found"
- exit 1
- fi
- # Call unsandbox to test the SDK
- - bash scripts/test-sdk.sh "$TEST_LANG"
+ - echo "=== Inception Test Matrix ==="
+ - echo "Testing SDK: $SDK_LANG"
+ - bash scripts/test-sdk.sh "$SDK_LANG"
artifacts:
reports:
- junit: "test-results-$SDK_LANG.xml"
+ junit: "test-results-$SDK_LANG/test-results.xml"
paths:
- "test-results-$SDK_LANG/"
expire_in: 30 days
- allow_failure: false
+ allow_failure: true
retry: 1
EOF
+echo ""
+echo "Generated test-matrix.yml:"
cat test-matrix.yml
diff --git a/scripts/test-sdk.sh b/scripts/test-sdk.sh
index 71a0ae0..9c7dfd4 100755
--- a/scripts/test-sdk.sh
+++ b/scripts/test-sdk.sh
@@ -1,5 +1,8 @@
#!/bin/bash
-# Test a specific SDK using unsandbox
+# Inception test: Use un (C CLI) to test other SDKs through unsandbox
+#
+# Pattern: build/un → unsandbox API → un.py/un.js/etc → unsandbox API → test code
+#
# Usage: test-sdk.sh LANGUAGE
set -e
@@ -8,40 +11,136 @@ LANG=${1:-python}
RESULTS_DIR="test-results-$LANG"
mkdir -p "$RESULTS_DIR"
-echo "Testing $LANG SDK via unsandbox..."
+# Map language to SDK file
+get_sdk_file() {
+ case "$1" in
+ python) echo "clients/python/sync/src/un.py" ;;
+ javascript) echo "clients/javascript/sync/src/un.js" ;;
+ typescript) echo "clients/typescript/sync/src/un.ts" ;;
+ go) echo "clients/go/sync/src/un.go" ;;
+ ruby) echo "clients/ruby/sync/src/un.rb" ;;
+ php) echo "clients/php/sync/src/un.php" ;;
+ java) echo "clients/java/sync/src/Un.java" ;;
+ rust) echo "clients/rust/sync/src/lib.rs" ;;
+ perl) echo "clients/perl/sync/src/un.pl" ;;
+ lua) echo "clients/lua/sync/src/un.lua" ;;
+ bash) echo "clients/bash/sync/src/un.sh" ;;
+ *) echo "clients/$1/sync/src/un.*" ;;
+ esac
+}
-# Use unsandbox API to test the SDK
-# This is the unfair advantage - we test without installing locally
-curl -s -X POST https://api.unsandbox.com/execute \
- -H "Authorization: Bearer ${UNSANDBOX_API_KEY}" \
- -H "Content-Type: application/json" \
- -d "{
- \"language\": \"$LANG\",
- \"code\": \"print(\\\"$LANG SDK test: OK\\\")\"
- }" > "$RESULTS_DIR/output.json"
+SDK_FILE=$(get_sdk_file "$LANG")
-# Check result
-RESULT=$(cat "$RESULTS_DIR/output.json" | jq -r '.stdout' 2>/dev/null || echo "ERROR")
-if [[ "$RESULT" == *"OK"* ]]; then
- echo "✓ $LANG test passed"
- EXIT_CODE=0
-else
- echo "✗ $LANG test failed: $RESULT"
- EXIT_CODE=1
+echo "=== Inception Test: $LANG ==="
+echo "SDK: $SDK_FILE"
+echo ""
+
+# Check if un CLI exists
+if [ ! -x "build/un" ]; then
+ echo "ERROR: build/un not found. Run build-clients.sh first."
+ exit 1
fi
+# Check if SDK file exists
+if [ ! -f "$SDK_FILE" ]; then
+ echo "SKIP: SDK file not found: $SDK_FILE"
+ # Generate skip result
+ cat > "$RESULTS_DIR/test-results.xml" << EOF
+
+
+
+
+
+
+
+
+EOF
+ exit 0
+fi
+
+# Run inception test:
+# 1. Use build/un to execute the SDK file in unsandbox with network access
+# 2. The SDK (un.py, etc.) will then call the API to run a simple test
+echo "Running inception test..."
+echo "Command: build/un -n semitrusted $SDK_FILE --help"
+
+START_TIME=$(date +%s.%N)
+
+# First test: Can the SDK show help?
+if build/un -n semitrusted \
+ -e "UNSANDBOX_PUBLIC_KEY=$UNSANDBOX_PUBLIC_KEY" \
+ -e "UNSANDBOX_SECRET_KEY=$UNSANDBOX_SECRET_KEY" \
+ "$SDK_FILE" --help > "$RESULTS_DIR/help_output.txt" 2>&1; then
+ HELP_OK=true
+ echo "✓ Help command succeeded"
+else
+ HELP_OK=false
+ echo "✗ Help command failed"
+fi
+
+# Second test: Can the SDK execute code? (inception within inception)
+# The SDK runs inside unsandbox, then calls the API to run Python
+echo ""
+echo "Testing code execution through $LANG SDK..."
+
+TEST_CODE='print("inception-test-ok")'
+if build/un -n semitrusted \
+ -e "UNSANDBOX_PUBLIC_KEY=$UNSANDBOX_PUBLIC_KEY" \
+ -e "UNSANDBOX_SECRET_KEY=$UNSANDBOX_SECRET_KEY" \
+ "$SDK_FILE" -s python "$TEST_CODE" > "$RESULTS_DIR/exec_output.txt" 2>&1; then
+
+ if grep -q "inception-test-ok" "$RESULTS_DIR/exec_output.txt"; then
+ EXEC_OK=true
+ echo "✓ Code execution succeeded"
+ else
+ EXEC_OK=false
+ echo "✗ Code execution returned unexpected output"
+ cat "$RESULTS_DIR/exec_output.txt"
+ fi
+else
+ EXEC_OK=false
+ echo "✗ Code execution failed"
+ cat "$RESULTS_DIR/exec_output.txt"
+fi
+
+END_TIME=$(date +%s.%N)
+DURATION=$(echo "$END_TIME - $START_TIME" | bc)
+
+# Determine overall result
+if [ "$HELP_OK" = true ] && [ "$EXEC_OK" = true ]; then
+ FAILURES=0
+ STATUS="PASS"
+else
+ FAILURES=1
+ STATUS="FAIL"
+fi
+
+echo ""
+echo "=== Result: $STATUS (${DURATION}s) ==="
+
# Generate JUnit XML
cat > "$RESULTS_DIR/test-results.xml" << EOF
-
-
+
+
EOF
-if [ $EXIT_CODE -eq 0 ]; then
- echo " $RESULT" >> "$RESULTS_DIR/test-results.xml"
+if [ "$HELP_OK" = true ]; then
+ echo ' Help command succeeded' >> "$RESULTS_DIR/test-results.xml"
else
- echo " $RESULT" >> "$RESULTS_DIR/test-results.xml"
+ echo ' See help_output.txt' >> "$RESULTS_DIR/test-results.xml"
+fi
+
+cat >> "$RESULTS_DIR/test-results.xml" << EOF
+
+
+EOF
+
+if [ "$EXEC_OK" = true ]; then
+ echo ' inception-test-ok' >> "$RESULTS_DIR/test-results.xml"
+else
+ echo ' See exec_output.txt' >> "$RESULTS_DIR/test-results.xml"
fi
cat >> "$RESULTS_DIR/test-results.xml" << EOF
@@ -50,4 +149,5 @@ cat >> "$RESULTS_DIR/test-results.xml" << EOF
EOF
-exit $EXIT_CODE
+# Exit with appropriate code
+[ "$STATUS" = "PASS" ] && exit 0 || exit 1