yao/.github/workflows/unit-test-v1.yml
Max 7a5c573f10 fix(workflows): update sandbox-v2 env loading to exclude comments and empty lines
- Modified the workflow to use grep for loading the sandbox-v2 environment variables, ensuring that comments and empty lines are excluded from the environment file.
2026-03-12 20:38:00 +08:00

329 lines
12 KiB
YAML

name: Unit Test V1
on:
workflow_dispatch:
inputs:
tags:
description: "Version"
env:
CI_VERSION: "1.0.0"
REPO_KUN: ${{ github.repository_owner }}/kun
REPO_XUN: ${{ github.repository_owner }}/xun
REPO_GOU: ${{ github.repository_owner }}/gou
YAO_DEV: ${{ github.WORKSPACE }}
YAO_ENV: development
YAO_ROOT: ${{ github.WORKSPACE }}/../app
YAO_HOST: 0.0.0.0
YAO_PORT: 5099
YAO_SESSION: "memory"
YAO_LOG: "./logs/application.log"
YAO_LOG_MODE: "TEXT"
YAO_JWT_SECRET: "bLp@bi!oqo-2U+hoTRUG"
YAO_DB_AESKEY: "ZLX=T&f6refeCh-ro*r@"
YAO_EXTENSION_ROOT: ${{ github.WORKSPACE }}/../extension
YAO_TEST_APPLICATION: ${{ github.WORKSPACE }}/../app
YAO_RUNTIME_MIN: 3
YAO_RUNTIME_MAX: 6
YAO_RUNTIME_HEAP_LIMIT: 1500000000
YAO_RUNTIME_HEAP_RELEASE: 10000000
YAO_RUNTIME_HEAP_AVAILABLE: 550000000
YAO_RUNTIME_PRECOMPILE: true
REDIS_TEST_HOST: "127.0.0.1"
REDIS_TEST_PORT: "6379"
REDIS_TEST_DB: "2"
MONGO_TEST_HOST: "127.0.0.1"
MONGO_TEST_PORT: "27017"
MONGO_TEST_USER: "root"
MONGO_TEST_PASS: "123456"
jobs:
# =============================================================================
# Environment Setup & Verification
# Build Yao, start services, connect Tai via gRPC tunnel, verify everything.
# No tests are run — this job validates the CI environment is healthy.
# =============================================================================
setup-and-verify:
runs-on: ubuntu-latest
services:
mongodb:
image: mongo:6.0
ports:
- 27017:27017
env:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: 123456
MONGO_INITDB_DATABASE: test
strategy:
matrix:
go: ["1.25"]
steps:
# ==== Phase 1: Checkout & Setup ====
- name: Checkout Yao
uses: actions/checkout@v4
- name: Setup Build Environment
uses: ./.github/actions/setup-yao
with:
repo-kun: ${{ env.REPO_KUN }}
repo-xun: ${{ env.REPO_XUN }}
repo-gou: ${{ env.REPO_GOU }}
checkout-init: "true"
apple-private-key: ${{ secrets.APPLE_PRIVATE_KEY_USER }}
- name: Load sandbox-v2 env
run: grep -vE '^\s*#|^\s*$' .github/env/sandbox-v2.env >> $GITHUB_ENV
- name: Setup SQLite
run: |
mkdir -p ${{ github.WORKSPACE }}/../app/db
echo "YAO_DB_PRIMARY=${{ github.WORKSPACE }}/../app/db/yao.db" >> $GITHUB_ENV
- name: Start Redis
run: docker run --name redis -d -p 6379:6379 redis:6
# ==== Phase 2: Build Yao & ci-token ====
- name: Build Yao
run: go build -v -o $RUNNER_TEMP/yao .
- name: Build ci-token
run: go build -tags ci -v -o $RUNNER_TEMP/ci-token ./cmd/ci-token
# ==== Phase 3: Prepare & Start Yao ====
- name: Prepare test app directory
run: |
cp -r ${{ github.WORKSPACE }}/../yao-init $RUNNER_TEMP/yao-test-app
mkdir -p $RUNNER_TEMP/yao-test-app/db
- name: Start Yao server
run: |
cd $RUNNER_TEMP/yao-test-app
YAO_ROOT=$(pwd) \
YAO_HOST=0.0.0.0 \
YAO_PORT=5099 \
YAO_GRPC_HOST=0.0.0.0 \
YAO_GRPC_PORT=9099 \
YAO_DB_DRIVER=sqlite3 \
YAO_DB_PRIMARY=$(pwd)/db/yao.db \
YAO_SESSION=memory \
YAO_ENV=development \
YAO_JWT_SECRET="${{ env.YAO_JWT_SECRET }}" \
YAO_DB_AESKEY="${{ env.YAO_DB_AESKEY }}" \
$RUNNER_TEMP/yao start &
# Wait for Yao HTTP to be ready (up to 120s)
for i in $(seq 1 60); do
if curl -sf http://127.0.0.1:5099/.well-known/yao > /dev/null 2>&1; then
echo "Yao HTTP ready"
curl -s http://127.0.0.1:5099/.well-known/yao | jq .
break
fi
echo "Waiting for Yao... ($i/60)"
sleep 2
done
curl -sf http://127.0.0.1:5099/.well-known/yao > /dev/null 2>&1 || {
echo "::error::Yao HTTP failed to start"
exit 1
}
# ==== Phase 4: Generate Tai credentials ====
- name: Generate Tai credentials
run: |
gen_cred() {
local CID=$1 TID=$2 OUT=$3
local TOKEN
TOKEN=$($RUNNER_TEMP/ci-token \
--app $RUNNER_TEMP/yao-test-app \
--client-id "$CID" \
--subject "${YAO_CI_OAUTH_SUBJECT:-ci-tai}" \
--user-id "${YAO_CI_OAUTH_USER_ID}" \
--team-id "${YAO_CI_OAUTH_TEAM_ID}" \
--scope "${YAO_CI_OAUTH_SCOPE:-tai:tunnel}" \
--ttl "${YAO_CI_OAUTH_TTL:-24h}")
echo -n "{\"client_id\":\"$CID\",\"tai_id\":\"$TID\",\"machine_id\":\"ci-runner\",\"server\":\"http://${YAO_CI_BRIDGE_IP}:${YAO_CI_HTTP_PORT}\",\"yao_grpc_addr\":\"${YAO_CI_BRIDGE_IP}:${YAO_CI_GRPC_PORT}\",\"access_token\":\"$TOKEN\",\"scope\":\"${YAO_CI_OAUTH_SCOPE}\",\"expires_at\":\"2099-01-01T00:00:00Z\",\"registered\":true}" \
| base64 > "$OUT"
echo "Generated credentials for $CID → $OUT"
}
gen_cred tai-ci-docker tai-docker-001 $RUNNER_TEMP/tai-docker-credentials
gen_cred tai-ci-k8s tai-k8s-001 $RUNNER_TEMP/tai-k8s-credentials
# ==== Phase 5: Pull images & Setup K8s ====
- name: Pull test images
run: |
docker pull yaoapp/tai-sandbox-test:latest || true
docker pull yaoapp/tai:latest
docker pull alpine:latest
- name: Install k3d & create cluster
run: |
curl -s https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash
k3d cluster create tai-test --no-lb --wait --api-port 16443
kubectl wait --for=condition=Ready node --all --timeout=60s
k3d image import alpine:latest -c tai-test
- name: Generate kubeconfig
run: |
K3D_IP=$(docker inspect k3d-tai-test-server-0 | jq -r '.[0].NetworkSettings.Networks["k3d-tai-test"].IPAddress')
echo "k3d server IP: ${K3D_IP}"
k3d kubeconfig get tai-test > /tmp/kubeconfig-k3d.yml
# For tai-k8s container (uses k3d internal IP)
sed "s|server: .*|server: https://${K3D_IP}:6443|" /tmp/kubeconfig-k3d.yml \
> /tmp/kubeconfig-tai-k8s.yml
echo "Container kubeconfig server:"
grep server: /tmp/kubeconfig-tai-k8s.yml
# For test runner (uses localhost via port-mapped 6443)
sed 's|server: .*|server: https://127.0.0.1:6443|' /tmp/kubeconfig-k3d.yml \
> $RUNNER_TEMP/kubeconfig-tai.yml
echo "Test runner kubeconfig server:"
grep server: $RUNNER_TEMP/kubeconfig-tai.yml
# Export for later steps
echo "TAI_TEST_KUBECONFIG=$RUNNER_TEMP/kubeconfig-tai.yml" >> $GITHUB_ENV
echo "YAO_CI_TAI_KUBECONFIG=$RUNNER_TEMP/kubeconfig-tai.yml" >> $GITHUB_ENV
# ==== Phase 6: Start Tai instances ====
- name: Start tai-docker
run: |
docker run -d --name tai-docker \
-v /var/run/docker.sock:/var/run/docker.sock \
-v $RUNNER_TEMP/tai-docker-credentials:/root/.tai/credentials:ro \
-e TAI_YAO_SERVER=http://${YAO_CI_BRIDGE_IP}:${YAO_CI_HTTP_PORT} \
-p ${YAO_CI_TAI_GRPC_PORT}:19100 \
-p ${YAO_CI_TAI_HTTP_PORT}:8099 \
-p ${YAO_CI_TAI_DOCKER_PORT}:12375 \
-p ${YAO_CI_TAI_VNC_PORT}:16080 \
yaoapp/tai:latest server \
-grpc 0.0.0.0:19100 -http 0.0.0.0:8099 -vnc 0.0.0.0:16080 -docker 0.0.0.0:12375
for i in $(seq 1 30); do
if curl -sf http://127.0.0.1:${YAO_CI_TAI_HTTP_PORT}/healthz > /dev/null 2>&1; then
echo "tai-docker HTTP ready"
break
fi
echo "Waiting for tai-docker HTTP... ($i/30)"
sleep 1
done
- name: Start tai-k8s
run: |
K3D_IP=$(docker inspect k3d-tai-test-server-0 | jq -r '.[0].NetworkSettings.Networks["k3d-tai-test"].IPAddress')
docker run -d --name tai-k8s \
--network k3d-tai-test \
-v $RUNNER_TEMP/tai-k8s-credentials:/root/.tai/credentials:ro \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
-v /tmp/kubeconfig-tai-k8s.yml:/etc/tai/kubeconfig.yml:ro \
-e TAI_YAO_SERVER=http://${YAO_CI_BRIDGE_IP}:${YAO_CI_HTTP_PORT} \
-e TAI_K8S_UPSTREAM="tcp://${K3D_IP}:6443" \
-e TAI_KUBECONFIG=/etc/tai/kubeconfig.yml \
-p ${YAO_CI_TAI_K8S_GRPC_PORT}:19100 \
-p 8100:8099 \
-p ${YAO_CI_TAI_K8S_PORT}:16443 \
-p 16081:16080 \
yaoapp/tai:latest server \
-grpc 0.0.0.0:19100 -http 0.0.0.0:8099 -vnc 0.0.0.0:16080 -k8s 0.0.0.0:16443
for i in $(seq 1 30); do
if curl -sf http://127.0.0.1:8100/healthz > /dev/null 2>&1; then
echo "tai-k8s HTTP ready"
break
fi
echo "Waiting for tai-k8s HTTP... ($i/30)"
sleep 1
done
# ==== Phase 7: Environment Verification (fail fast) ====
- name: Verify Environment
run: |
echo "CI Environment v${CI_VERSION}"
echo ""
FAILED=0
check() {
local name=$1; shift
if "$@" > /dev/null 2>&1; then
echo " [PASS] $name"
else
echo " [FAIL] $name"
FAILED=$((FAILED + 1))
fi
}
echo "=== Environment Verification ==="
echo ""
echo "--- Yao ---"
check "Yao HTTP (/.well-known/yao)" curl -sf http://127.0.0.1:5099/.well-known/yao
check "Yao gRPC port" nc -z 127.0.0.1 9099
echo ""
echo "--- tai-docker ---"
check "tai-docker HTTP (/healthz)" curl -sf http://127.0.0.1:${YAO_CI_TAI_HTTP_PORT}/healthz
check "tai-docker gRPC port" nc -z 127.0.0.1 ${YAO_CI_TAI_GRPC_PORT}
echo ""
echo "--- tai-k8s ---"
check "tai-k8s HTTP (/healthz)" curl -sf http://127.0.0.1:8100/healthz
check "tai-k8s gRPC port" nc -z 127.0.0.1 ${YAO_CI_TAI_K8S_GRPC_PORT}
echo ""
echo "--- Tai Tunnel Registration ---"
sleep 5
echo "tai-docker tunnel logs:"
docker logs tai-docker 2>&1 | grep -iE "tunnel|register|connected" | tail -5 || true
echo "tai-k8s tunnel logs:"
docker logs tai-k8s 2>&1 | grep -iE "tunnel|register|connected" | tail -5 || true
# Check if Tai instances appear registered via Yao
WELL_KNOWN=$(curl -sf http://127.0.0.1:5099/.well-known/yao 2>/dev/null || echo "{}")
echo "Yao .well-known/yao:"
echo "$WELL_KNOWN" | jq . 2>/dev/null || echo "$WELL_KNOWN"
echo ""
echo "--- K8s (k3d) ---"
check "kubectl get nodes" kubectl --kubeconfig=$RUNNER_TEMP/kubeconfig-tai.yml get nodes
echo ""
echo "--- MongoDB ---"
check "MongoDB ping" mongosh --quiet --host 127.0.0.1 --port 27017 \
-u root -p 123456 --authenticationDatabase admin \
--eval "db.runCommand({ping:1})"
echo ""
echo "--- Redis ---"
check "Redis ping" docker exec redis redis-cli ping
echo ""
echo "=========================================="
if [ $FAILED -gt 0 ]; then
echo "::error::$FAILED verification check(s) FAILED"
echo ""
echo "=== Diagnostic Info ==="
echo "--- Docker containers ---"
docker ps -a
echo ""
echo "--- tai-docker full logs ---"
docker logs tai-docker 2>&1 | tail -50
echo ""
echo "--- tai-k8s full logs ---"
docker logs tai-k8s 2>&1 | tail -50
echo ""
echo "--- Yao process ---"
ps aux | grep yao || true
exit 1
else
echo "All verification checks PASSED"
fi