yao/.github/workflows/pr-test.yml
Max fcfe609344 Refactor CI workflows for Tai service and update health checks
- Rename and enhance the Docker instance startup steps for Tai in CI workflows, improving clarity and readiness checks for both HTTP and gRPC services.
- Update health check logic to ensure accurate reporting of service readiness, including specific error messages for failures.
- Modify environment variable configurations to streamline the setup for K8s and Docker instances, ensuring consistent port usage across tests.

These changes improve the reliability and clarity of the CI processes for the Tai service, enhancing overall testing and deployment workflows.
2026-03-05 21:58:04 +08:00

2129 lines
64 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

name: PR Unit Test
# read-write repo token
# access to secrets
on:
workflow_run:
workflows: ["Receive PR"]
types:
- completed
env:
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@"
OSS_TEST_ID: ${{ secrets.OSS_TEST_ID}}
OSS_TEST_SECRET: ${{ secrets.OSS_TEST_SECRET}}
ROOT_PLUGIN: ${{ github.WORKSPACE }}/../../../data/gou-unit/plugins
MYSQL_TEST_HOST: "127.0.0.1"
MYSQL_TEST_PORT: "3308"
MYSQL_TEST_USER: test
MYSQL_TEST_PASS: "123456"
SQLITE_DB: "./app/db/yao.db"
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"
OPENAI_TEST_KEY: ${{ secrets.OPENAI_TEST_KEY }}
TEST_MOAPI_SECRET: ${{ secrets.OPENAI_TEST_KEY }}
OPENAI_API_KEY: ${{ secrets.OPENAI_TEST_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
TEST_MOAPI_MIRROR: https://api.openai.com
# DeepSeek API Configuration
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
DEEPSEEK_API_PROXY: ${{ secrets.DEEPSEEK_API_PROXY }}
DEEPSEEK_MODELS_R1: ${{ secrets.DEEPSEEK_MODELS_R1 }}
DEEPSEEK_MODELS_V3: ${{ secrets.DEEPSEEK_MODELS_V3 }}
DEEPSEEK_MODELS_V3_1: ${{ secrets.DEEPSEEK_MODELS_V3_1 }}
# Search API Configuration
TAVILY_API_KEY: ${{ secrets.TAVILY_API_KEY }}
SERPAPI_API_KEY: ${{ secrets.SERPAPI_API_KEY }}
SERPER_API_KEY: ${{ secrets.SERPER_API_KEY }}
# Claude API Configuration
CLAUDE_API_KEY: ${{ secrets.CLAUDE_API_KEY }}
CLAUDE_PROXY: ${{ secrets.CLAUDE_PROXY }}
CLAUDE_API_HOST: ${{ secrets.CLAUDE_API_HOST }}
CLAUDE_SONNET_4: ${{ secrets.CLAUDE_SONNET_4 }}
CLAUDE_SONNET_4_THINKING: ${{ secrets.CLAUDE_SONNET_4_THINKING }}
# Moonshot / Kimi API Configuration
MOONSHOT_API_KEY: ${{ secrets.MOONSHOT_API_KEY }}
MOONSHOT_PROXY: "https://api.moonshot.cn"
KIMI_CODE_API_KEY: ${{ secrets.KIMI_CODE_API_KEY }}
KIMI_CODE_PROXY: "https://api.kimi.com/coding"
TAB_NAME: "::PET ADMIN"
PAGE_SIZE: "20"
PAGE_LINK: "https://yaoapps.com"
PAGE_ICON: "icon-trash"
DEMO_APP: ${{ github.WORKSPACE }}/../app
# Application Setting
## Path
YAO_EXTENSION_ROOT: ${{ github.WORKSPACE }}/../extension
YAO_TEST_APPLICATION: ${{ github.WORKSPACE }}/../app
YAO_SUI_TEST_APPLICATION: ${{ github.WORKSPACE }}/../yao-startup-webapp
## Runtime
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
# Neo4j
NEO4J_TEST_URL: "neo4j://localhost:7687"
NEO4J_TEST_USER: "neo4j"
NEO4J_TEST_PASS: "Yao2026Neo4j"
# Qdrant
QDRANT_TEST_HOST: "127.0.0.1"
QDRANT_TEST_PORT: "6334"
# S3
S3_API: ${{ secrets.S3_API }}
S3_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }}
S3_SECRET_KEY: ${{ secrets.S3_SECRET_KEY }}
S3_BUCKET: ${{ secrets.S3_BUCKET }}
S3_PUBLIC_URL: ${{ secrets.S3_PUBLIC_URL }}
# === Openapi Signin Configs ===
SIGNIN_CLIENT_ID: "kiCeR88kDwHBDuNHvN51cZgmpp3tmF6Z"
## Google
GOOGLE_CLIENT_ID: ${{ secrets.GOOGLE_CLIENT_ID }}
GOOGLE_CLIENT_SECRET: ${{ secrets.GOOGLE_CLIENT_SECRET }}
## Microsoft
MICROSOFT_CLIENT_ID: ${{ secrets.MICROSOFT_CLIENT_ID }}
MICROSOFT_CLIENT_SECRET: ${{ secrets.MICROSOFT_CLIENT_SECRET }}
## Apple
APPLE_SERVICE_ID: ${{ secrets.APPLE_SERVICE_ID }}
APPLE_PRIVATE_KEY_PATH: "apple/signin_client_secret_key.p8"
APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
## Github
GITHUBUSER_CLIENT_ID: ${{ secrets.GITHUBUSER_CLIENT_ID }}
GITHUBUSER_CLIENT_SECRET: ${{ secrets.GITHUBUSER_CLIENT_SECRET }}
## Cloudflare Turnstile
CLOUDFLARE_TURNSTILE_SITEKEY: ${{ secrets.CLOUDFLARE_TURNSTILE_SITEKEY }}
CLOUDFLARE_TURNSTILE_SECRET: ${{ secrets.CLOUDFLARE_TURNSTILE_SECRET }}
# === Messaging Services ===
## Mailgun
MAILGUN_DOMAIN: ${{ secrets.MAILGUN_DOMAIN }}
MAILGUN_API_KEY: ${{ secrets.MAILGUN_API_KEY }}
MAILGUN_FROM: "Yaobots Tests <unit-test@mailgun.yaobots.com>"
## SMTP Server Mailgun
SMTP_HOST: "smtp.mailgun.org"
SMTP_PORT: "465"
SMTP_USERNAME: ${{ secrets.SMTP_USERNAME }}
SMTP_PASSWORD: ${{ secrets.SMTP_PASSWORD }}
SMTP_FROM: "Yaobots SMTP Tests <unit-test@mailgun.yaobots.com>"
## SMTP Server Gmail
RELIABLE_SMTP_HOST: "smtp.gmail.com"
RELIABLE_SMTP_PORT: "465"
RELIABLE_SMTP_USERNAME: ${{ secrets.RELIABLE_SMTP_USERNAME }}
RELIABLE_SMTP_PASSWORD: ${{ secrets.RELIABLE_SMTP_PASSWORD }}
RELIABLE_SMTP_FROM: "Yaobots Gmail Tests <shadow.iqka@gmail.com>"
## IMAP Server (Gmail)
RELIABLE_IMAP_HOST: "imap.gmail.com"
RELIABLE_IMAP_PORT: "993"
RELIABLE_IMAP_USERNAME: ${{ secrets.RELIABLE_SMTP_USERNAME }}
RELIABLE_IMAP_PASSWORD: ${{ secrets.RELIABLE_SMTP_PASSWORD }}
RELIABLE_IMAP_MAILBOX: "INBOX"
## Twilio
TWILIO_ACCOUNT_SID: ${{ secrets.TWILIO_ACCOUNT_SID }}
TWILIO_AUTH_TOKEN: ${{ secrets.TWILIO_AUTH_TOKEN }}
TWILIO_API_SID: ${{ secrets.TWILIO_API_SID }}
TWILIO_API_KEY: ${{ secrets.TWILIO_API_KEY }}
TWILIO_SENDGRID_API_SID: ${{ secrets.TWILIO_SENDGRID_API_SID }}
TWILIO_SENDGRID_API_KEY: ${{ secrets.TWILIO_SENDGRID_API_KEY }}
TWILIO_FROM_PHONE: "+17035701412"
TWILIO_FROM_EMAIL: "unit-test@sendgrid.yaobots.com"
TWILIO_TEST_PHONE: ${{ secrets.TWILIO_TEST_PHONE }}
jobs:
# =============================================================================
# KB Tests (kb) - Run once with SQLite (requires Qdrant, Neo4j, FastEmbed)
# =============================================================================
KBTest:
runs-on: ubuntu-latest
services:
qdrant:
image: qdrant/qdrant:latest
ports:
- 6333:6333
- 6334:6334
fastembed:
image: yaoapp/fastembed:latest-amd64
env:
FASTEMBED_PASSWORD: Yao@2026
ports:
- 6001:8000
neo4j:
image: neo4j:latest
ports:
- "7687:7687"
env:
NEO4J_AUTH: neo4j/Yao2026Neo4j
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"]
if: >
${{ github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion == 'success' }}
steps:
- name: "Download artifact"
uses: actions/github-script@v7
with:
script: |
var artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{github.event.workflow_run.id }},
});
var matchArtifact = artifacts.data.artifacts.filter((artifact) => {
return artifact.name == "pr"
})[0];
var download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifact.id,
archive_format: 'zip',
});
var fs = require('fs');
fs.writeFileSync('${{github.workspace}}/pr.zip', Buffer.from(download.data));
- name: "Read NR & SHA"
run: |
unzip pr.zip
cat NR
cat SHA
echo HEAD=$(cat SHA) >> $GITHUB_ENV
echo NR=$(cat NR) >> $GITHUB_ENV
- name: "Comment on PR"
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { NR } = process.env
var issue_number = NR;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue_number,
body: '🤖 KB Tests (kb) running with SQLite...'
});
- name: Checkout Kun
uses: actions/checkout@v4
with:
repository: yaoapp/kun
path: kun
- name: Checkout Xun
uses: actions/checkout@v4
with:
repository: yaoapp/xun
path: xun
- name: Checkout Gou
uses: actions/checkout@v4
with:
repository: yaoapp/gou
path: gou
- name: Checkout V8Go
uses: actions/checkout@v4
with:
repository: yaoapp/v8go
path: v8go
- name: Unzip libv8
run: |
files=$(find ./v8go -name "libv8*.zip")
for file in $files; do
dir=$(dirname "$file")
echo "Extracting $file to directory $dir"
unzip -o -d $dir $file
rm -rf $dir/__MACOSX
done
- name: Checkout Demo App
uses: actions/checkout@v4
with:
repository: yaoapp/yao-dev-app
path: app
- name: Checkout Extension
uses: actions/checkout@v4
with:
repository: yaoapp/yao-extensions-dev
path: extension
- name: Move Dependencies
run: |
mv kun ../
mv xun ../
mv gou ../
mv v8go ../
mv app ../
mv extension ../
- name: Checkout pull request HEAD commit
uses: actions/checkout@v4
with:
ref: ${{ env.HEAD }}
- name: Setup Apple Private Key
run: |
mkdir -p ../app/openapi/certs/apple
echo "${{ secrets.APPLE_PRIVATE_KEY_USER }}" > ../app/openapi/certs/apple/signin_client_secret_key.p8
- name: Setup Go ${{ matrix.go }}
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go }}
- name: Start Redis
run: docker run --name redis --publish 6379:6379 --detach redis:6
- name: Setup Go Tools
run: make tools
- name: Setup ENV (SQLite)
run: |
mkdir -p ${{ github.WORKSPACE }}/../app/db
echo "YAO_DB_DRIVER=sqlite3" >> $GITHUB_ENV
echo "YAO_DB_PRIMARY=${{ github.WORKSPACE }}/../app/db/yao.db" >> $GITHUB_ENV
- name: Run KB Tests (kb)
run: make unit-test-kb
- name: Codecov Report
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
- name: "Comment on PR - KB Tests Done"
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { NR } = process.env
var issue_number = NR;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue_number,
body: '✅ KB Tests (kb) passed!'
});
# =============================================================================
# Agent Tests (agent, aigc) - Run once with SQLite
# =============================================================================
AgentTest:
runs-on: ubuntu-latest
services:
qdrant:
image: qdrant/qdrant:latest
ports:
- 6333:6333
- 6334:6334
fastembed:
image: yaoapp/fastembed:latest-amd64
env:
FASTEMBED_PASSWORD: Yao@2026
ports:
- 6001:8000
neo4j:
image: neo4j:latest
ports:
- "7687:7687"
env:
NEO4J_AUTH: neo4j/Yao2026Neo4j
mcp-everything:
image: yaoapp/mcp-everything:latest
ports:
- "3021:3021"
- "3022:3022"
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"]
if: >
${{ github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion == 'success' }}
steps:
- name: "Download artifact"
uses: actions/github-script@v7
with:
script: |
var artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{github.event.workflow_run.id }},
});
var matchArtifact = artifacts.data.artifacts.filter((artifact) => {
return artifact.name == "pr"
})[0];
var download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifact.id,
archive_format: 'zip',
});
var fs = require('fs');
fs.writeFileSync('${{github.workspace}}/pr.zip', Buffer.from(download.data));
- name: "Read NR & SHA"
run: |
unzip pr.zip
cat NR
cat SHA
echo HEAD=$(cat SHA) >> $GITHUB_ENV
echo NR=$(cat NR) >> $GITHUB_ENV
- name: "Comment on PR"
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { NR } = process.env
var issue_number = NR;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue_number,
body: '🤖 Agent Tests (agent, aigc) running with SQLite...'
});
- name: Checkout Kun
uses: actions/checkout@v4
with:
repository: yaoapp/kun
path: kun
- name: Checkout Xun
uses: actions/checkout@v4
with:
repository: yaoapp/xun
path: xun
- name: Checkout Gou
uses: actions/checkout@v4
with:
repository: yaoapp/gou
path: gou
- name: Checkout V8Go
uses: actions/checkout@v4
with:
repository: yaoapp/v8go
path: v8go
- name: Unzip libv8
run: |
files=$(find ./v8go -name "libv8*.zip")
for file in $files; do
dir=$(dirname "$file")
echo "Extracting $file to directory $dir"
unzip -o -d $dir $file
rm -rf $dir/__MACOSX
done
- name: Checkout Demo App
uses: actions/checkout@v4
with:
repository: yaoapp/yao-dev-app
path: app
- name: Checkout Extension
uses: actions/checkout@v4
with:
repository: yaoapp/yao-extensions-dev
path: extension
- name: Move Dependencies
run: |
mv kun ../
mv xun ../
mv gou ../
mv v8go ../
mv app ../
mv extension ../
- name: Checkout pull request HEAD commit
uses: actions/checkout@v4
with:
ref: ${{ env.HEAD }}
- name: Setup Apple Private Key
run: |
mkdir -p ../app/openapi/certs/apple
echo "${{ secrets.APPLE_PRIVATE_KEY_USER }}" > ../app/openapi/certs/apple/signin_client_secret_key.p8
- name: Setup Go ${{ matrix.go }}
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go }}
- name: Start Redis
run: docker run --name redis --publish 6379:6379 --detach redis:6
- name: Setup Go Tools
run: make tools
- name: Install pdftoppm, mutool, imagemagick
run: |
sudo apt update
sudo apt install -y poppler-utils mupdf-tools imagemagick
- name: Test pdftoppm, mutool, imagemagick
run: |
pdftoppm -v
mutool -v
convert -version
- name: Setup ENV (SQLite)
run: |
mkdir -p ${{ github.WORKSPACE }}/../app/db
echo "YAO_DB_DRIVER=sqlite3" >> $GITHUB_ENV
echo "YAO_DB_PRIMARY=${{ github.WORKSPACE }}/../app/db/yao.db" >> $GITHUB_ENV
- name: Pull Sandbox Test Images
run: |
docker pull alpine:latest
docker pull yaoapp/sandbox-base:latest || true
docker pull yaoapp/sandbox-claude:latest || true
- name: Run Agent Tests (agent, aigc)
env:
YAO_SANDBOX_WORKSPACE: ${{ runner.temp }}/sandbox/workspace
YAO_SANDBOX_IPC: ${{ runner.temp }}/sandbox/ipc
run: |
export YAO_SANDBOX_CONTAINER_USER="$(id -u):$(id -g)"
make unit-test-agent
- name: Codecov Report
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
- name: "Comment on PR - Agent Tests Done"
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { NR } = process.env
var issue_number = NR;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue_number,
body: '✅ Agent Tests (agent, aigc) passed!'
});
# =============================================================================
# Robot Tests (all agent/robot/... packages) - Unit + E2E with real LLM calls
# =============================================================================
RobotTest:
runs-on: ubuntu-latest
services:
mcp-everything:
image: yaoapp/mcp-everything:latest
ports:
- "3021:3021"
- "3022:3022"
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"]
if: >
${{ github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion == 'success' }}
steps:
- name: "Download artifact"
uses: actions/github-script@v7
with:
script: |
var artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{github.event.workflow_run.id }},
});
var matchArtifact = artifacts.data.artifacts.filter((artifact) => {
return artifact.name == "pr"
})[0];
var download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifact.id,
archive_format: 'zip',
});
var fs = require('fs');
fs.writeFileSync('${{github.workspace}}/pr.zip', Buffer.from(download.data));
- name: "Read NR & SHA"
run: |
unzip pr.zip
cat NR
cat SHA
echo HEAD=$(cat SHA) >> $GITHUB_ENV
echo NR=$(cat NR) >> $GITHUB_ENV
- name: "Comment on PR"
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { NR } = process.env
var issue_number = NR;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue_number,
body: '🤖 Robot Tests (Unit + E2E) running with SQLite...'
});
- name: Checkout Kun
uses: actions/checkout@v4
with:
repository: yaoapp/kun
path: kun
- name: Checkout Xun
uses: actions/checkout@v4
with:
repository: yaoapp/xun
path: xun
- name: Checkout Gou
uses: actions/checkout@v4
with:
repository: yaoapp/gou
path: gou
- name: Checkout V8Go
uses: actions/checkout@v4
with:
repository: yaoapp/v8go
path: v8go
- name: Unzip libv8
run: |
files=$(find ./v8go -name "libv8*.zip")
for file in $files; do
dir=$(dirname "$file")
echo "Extracting $file to directory $dir"
unzip -o -d $dir $file
rm -rf $dir/__MACOSX
done
- name: Checkout Demo App
uses: actions/checkout@v4
with:
repository: yaoapp/yao-dev-app
path: app
- name: Checkout Extension
uses: actions/checkout@v4
with:
repository: yaoapp/yao-extensions-dev
path: extension
- name: Move Dependencies
run: |
mv kun ../
mv xun ../
mv gou ../
mv v8go ../
mv app ../
mv extension ../
- name: Checkout pull request HEAD commit
uses: actions/checkout@v4
with:
ref: ${{ env.HEAD }}
- name: Setup Go ${{ matrix.go }}
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go }}
- name: Start Redis
run: docker run --name redis --publish 6379:6379 --detach redis:6
- name: Setup Go Tools
run: make tools
- name: Setup ENV (SQLite)
run: |
mkdir -p ${{ github.WORKSPACE }}/../app/db
echo "YAO_DB_DRIVER=sqlite3" >> $GITHUB_ENV
echo "YAO_DB_PRIMARY=${{ github.WORKSPACE }}/../app/db/yao.db" >> $GITHUB_ENV
- name: Run Robot Tests (Unit + E2E)
run: make unit-test-robot
- name: Codecov Report
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
- name: "Comment on PR - Robot Tests Done"
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { NR } = process.env
var issue_number = NR;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue_number,
body: '✅ Robot Tests (Unit + E2E) passed!'
});
# =============================================================================
# Sandbox Tests (requires Docker) - Run with Docker-in-Docker
# =============================================================================
SandboxTest:
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"]
if: >
${{ github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion == 'success' }}
steps:
- name: "Download artifact"
uses: actions/github-script@v7
with:
script: |
var artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{github.event.workflow_run.id }},
});
var matchArtifact = artifacts.data.artifacts.filter((artifact) => {
return artifact.name == "pr"
})[0];
var download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifact.id,
archive_format: 'zip',
});
var fs = require('fs');
fs.writeFileSync('${{github.workspace}}/pr.zip', Buffer.from(download.data));
- name: "Read NR & SHA"
run: |
unzip pr.zip
cat NR
cat SHA
echo HEAD=$(cat SHA) >> $GITHUB_ENV
echo NR=$(cat NR) >> $GITHUB_ENV
- name: "Comment on PR"
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { NR } = process.env
var issue_number = NR;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue_number,
body: '🤖 Sandbox Tests running with Docker...'
});
- name: Checkout Kun
uses: actions/checkout@v4
with:
repository: yaoapp/kun
path: kun
- name: Checkout Xun
uses: actions/checkout@v4
with:
repository: yaoapp/xun
path: xun
- name: Checkout Gou
uses: actions/checkout@v4
with:
repository: yaoapp/gou
path: gou
- name: Checkout V8Go
uses: actions/checkout@v4
with:
repository: yaoapp/v8go
path: v8go
- name: Unzip libv8
run: |
files=$(find ./v8go -name "libv8*.zip")
for file in $files; do
dir=$(dirname "$file")
echo "Extracting $file to directory $dir"
unzip -o -d $dir $file
rm -rf $dir/__MACOSX
done
- name: Checkout Demo App
uses: actions/checkout@v4
with:
repository: yaoapp/yao-dev-app
path: app
- name: Checkout Extension
uses: actions/checkout@v4
with:
repository: yaoapp/yao-extensions-dev
path: extension
- name: Move Dependencies
run: |
mv kun ../
mv xun ../
mv gou ../
mv v8go ../
mv app ../
mv extension ../
- name: Checkout pull request HEAD commit
uses: actions/checkout@v4
with:
ref: ${{ env.HEAD }}
- name: Setup Go ${{ matrix.go }}
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go }}
- name: Start Redis
run: docker run --name redis --publish 6379:6379 --detach redis:6
- name: Setup Go Tools
run: make tools
- name: Setup ENV (SQLite)
run: |
mkdir -p ${{ github.WORKSPACE }}/../app/db
echo "YAO_DB_DRIVER=sqlite3" >> $GITHUB_ENV
echo "YAO_DB_PRIMARY=${{ github.WORKSPACE }}/../app/db/yao.db" >> $GITHUB_ENV
- name: Pull Sandbox Test Images
run: |
docker pull alpine:latest
docker pull yaoapp/sandbox-base:latest || true
docker pull yaoapp/sandbox-claude:latest || true
- name: Run Sandbox Tests
env:
YAO_SANDBOX_WORKSPACE: ${{ runner.temp }}/sandbox/workspace
YAO_SANDBOX_IPC: ${{ runner.temp }}/sandbox/ipc
run: |
# Use runner's UID:GID to avoid permission issues
export YAO_SANDBOX_CONTAINER_USER="$(id -u):$(id -g)"
make unit-test-sandbox
- name: Codecov Report
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
- name: "Comment on PR - Sandbox Tests Done"
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { NR } = process.env
var issue_number = NR;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue_number,
body: '✅ Sandbox Tests passed!'
});
# =============================================================================
# Sandbox V2 Tests (tai + sandbox/v2 + workspace, Docker + K8s via k3d)
# =============================================================================
SandboxV2Test:
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"]
if: >
${{ github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion == 'success' }}
steps:
- name: "Download artifact"
uses: actions/github-script@v7
with:
script: |
var artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{github.event.workflow_run.id }},
});
var matchArtifact = artifacts.data.artifacts.filter((artifact) => {
return artifact.name == "pr"
})[0];
var download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifact.id,
archive_format: 'zip',
});
var fs = require('fs');
fs.writeFileSync('${{github.workspace}}/pr.zip', Buffer.from(download.data));
- name: "Read NR & SHA"
run: |
unzip pr.zip
cat NR
cat SHA
echo HEAD=$(cat SHA) >> $GITHUB_ENV
echo NR=$(cat NR) >> $GITHUB_ENV
- name: "Comment on PR"
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { NR } = process.env
var issue_number = NR;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue_number,
body: '🤖 Sandbox V2 Tests running (tai + sandbox-v2 + workspace)...'
});
- name: Checkout Kun
uses: actions/checkout@v4
with:
repository: yaoapp/kun
path: kun
- name: Checkout Xun
uses: actions/checkout@v4
with:
repository: yaoapp/xun
path: xun
- name: Checkout Gou
uses: actions/checkout@v4
with:
repository: yaoapp/gou
path: gou
- name: Checkout V8Go
uses: actions/checkout@v4
with:
repository: yaoapp/v8go
path: v8go
- name: Unzip libv8
run: |
files=$(find ./v8go -name "libv8*.zip")
for file in $files; do
dir=$(dirname "$file")
echo "Extracting $file to directory $dir"
unzip -o -d $dir $file
rm -rf $dir/__MACOSX
done
- name: Checkout Demo App
uses: actions/checkout@v4
with:
repository: yaoapp/yao-dev-app
path: app
- name: Checkout Extension
uses: actions/checkout@v4
with:
repository: yaoapp/yao-extensions-dev
path: extension
- name: Move Dependencies
run: |
mv kun ../
mv xun ../
mv gou ../
mv v8go ../
mv app ../
mv extension ../
- name: Checkout pull request HEAD commit
uses: actions/checkout@v4
with:
ref: ${{ env.HEAD }}
- name: Setup Apple Private Key
run: |
mkdir -p ../app/openapi/certs/apple
echo "${{ secrets.APPLE_PRIVATE_KEY_USER }}" > ../app/openapi/certs/apple/signin_client_secret_key.p8
- name: Setup Go ${{ matrix.go }}
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go }}
- name: Start Redis
run: docker run --name redis --publish 6379:6379 --detach redis:6
- name: Setup Go Tools
run: make tools
- name: Setup ENV (SQLite)
run: |
mkdir -p ${{ github.WORKSPACE }}/../app/db
echo "YAO_DB_DRIVER=sqlite3" >> $GITHUB_ENV
echo "YAO_DB_PRIMARY=${{ github.WORKSPACE }}/../app/db/yao.db" >> $GITHUB_ENV
- name: Pull Test Images
run: |
docker pull yaoapp/sandbox-v2-test:latest || true
docker pull yaoapp/tai:latest
docker pull alpine:latest
- name: Install k3d
run: curl -s https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash
- name: Create k3d cluster
run: |
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: Start Tai Docker instance
run: |
docker run -d --name tai-docker \
-v /var/run/docker.sock:/var/run/docker.sock \
-p 8080:8080 -p 9100:9100 -p 2375:2375 -p 6080:6080 \
yaoapp/tai:latest
for i in $(seq 1 30); do
if curl -sf http://127.0.0.1:8080/healthz > /dev/null 2>&1; then
echo "Tai Docker HTTP ready"; break
fi
echo "Waiting for Tai Docker HTTP... ($i)"; sleep 1
done
curl -sf http://127.0.0.1:8080/healthz > /dev/null 2>&1 || {
echo "::error::Tai Docker HTTP failed"; docker logs tai-docker 2>&1; exit 1
}
for i in $(seq 1 15); do
if nc -z 127.0.0.1 9100 2>/dev/null; then
echo "Tai Docker gRPC ready"; break
fi
echo "Waiting for Tai Docker gRPC... ($i)"; sleep 1
done
nc -z 127.0.0.1 9100 2>/dev/null || {
echo "::error::Tai Docker gRPC failed"; docker logs tai-docker 2>&1; exit 1
}
- name: Start Tai K8s instance
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}"
docker run -d --name tai-k8s \
--network k3d-tai-test \
-p 8081:8080 -p 9101:9100 -p 6443:6443 -p 6081:6080 \
-e TAI_K8S_UPSTREAM="tcp://${K3D_IP}:6443" \
yaoapp/tai:latest
for i in $(seq 1 30); do
if curl -sf http://127.0.0.1:8081/healthz > /dev/null 2>&1; then
echo "Tai K8s HTTP ready"; break
fi
echo "Waiting for Tai K8s HTTP... ($i)"; sleep 1
done
curl -sf http://127.0.0.1:8081/healthz > /dev/null 2>&1 || {
echo "::error::Tai K8s HTTP failed"; docker logs tai-k8s 2>&1; exit 1
}
for i in $(seq 1 15); do
if nc -z 127.0.0.1 9101 2>/dev/null; then
echo "Tai K8s gRPC ready"; break
fi
echo "Waiting for Tai K8s gRPC... ($i)"; sleep 1
done
nc -z 127.0.0.1 9101 2>/dev/null || {
echo "::error::Tai K8s gRPC failed"; docker logs tai-k8s 2>&1; exit 1
}
- name: Generate kubeconfig for Tai K8s proxy
run: |
k3d kubeconfig get tai-test > /tmp/kubeconfig-k3d.yml
sed 's|server: .*|server: https://127.0.0.1:6443|' /tmp/kubeconfig-k3d.yml \
> ${{ runner.temp }}/kubeconfig-tai.yml
echo "Generated kubeconfig:"
grep server: ${{ runner.temp }}/kubeconfig-tai.yml
- name: Run Sandbox V2 Tests (tai + sandbox-v2 + workspace)
env:
TAI_TEST_HOST: "127.0.0.1"
TAI_TEST_DOCKER: "tcp://127.0.0.1:2375"
TAI_TEST_GRPC_PORT: "9100"
TAI_TEST_K8S_HOST: "127.0.0.1"
TAI_TEST_K8S_PORT: "6443"
TAI_TEST_K8S_GRPC_PORT: "9101"
TAI_TEST_KUBECONFIG: "${{ runner.temp }}/kubeconfig-tai.yml"
TAI_TEST_HOST_IP: "172.17.0.1"
SANDBOX_TEST_REMOTE_ADDR: "tai://127.0.0.1:9100"
SANDBOX_TEST_IMAGE: "yaoapp/sandbox-v2-test:latest"
run: make unit-test-sandbox-v2
- name: Codecov Report
if: always()
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: false
- name: "Comment on PR - Sandbox V2 Tests Done"
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { NR } = process.env
var issue_number = NR;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue_number,
body: '✅ Sandbox V2 Tests passed (tai + sandbox-v2 + workspace)!'
});
# =============================================================================
# Benchmark & Memory Leak Tests - Run with MySQL8.0 and SQLite3
# =============================================================================
PerfTest:
runs-on: ubuntu-latest
services:
mcp-everything:
image: yaoapp/mcp-everything:latest
ports:
- "3021:3021"
- "3022:3022"
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"]
db: [MySQL8.0, SQLite3]
if: >
${{ github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion == 'success' }}
steps:
- name: "Download artifact"
uses: actions/github-script@v7
with:
script: |
var artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{github.event.workflow_run.id }},
});
var matchArtifact = artifacts.data.artifacts.filter((artifact) => {
return artifact.name == "pr"
})[0];
var download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifact.id,
archive_format: 'zip',
});
var fs = require('fs');
fs.writeFileSync('${{github.workspace}}/pr.zip', Buffer.from(download.data));
- name: "Read NR & SHA"
run: |
unzip pr.zip
cat NR
cat SHA
echo HEAD=$(cat SHA) >> $GITHUB_ENV
echo NR=$(cat NR) >> $GITHUB_ENV
- name: Checkout Kun
uses: actions/checkout@v4
with:
repository: yaoapp/kun
path: kun
- name: Checkout Xun
uses: actions/checkout@v4
with:
repository: yaoapp/xun
path: xun
- name: Checkout Gou
uses: actions/checkout@v4
with:
repository: yaoapp/gou
path: gou
- name: Checkout V8Go
uses: actions/checkout@v4
with:
repository: yaoapp/v8go
path: v8go
- name: Unzip libv8
run: |
files=$(find ./v8go -name "libv8*.zip")
for file in $files; do
dir=$(dirname "$file")
echo "Extracting $file to directory $dir"
unzip -o -d $dir $file
rm -rf $dir/__MACOSX
done
- name: Checkout Demo App
uses: actions/checkout@v4
with:
repository: yaoapp/yao-dev-app
path: app
- name: Checkout Extension
uses: actions/checkout@v4
with:
repository: yaoapp/yao-extensions-dev
path: extension
- name: Move Dependencies
run: |
mv kun ../
mv xun ../
mv gou ../
mv v8go ../
mv app ../
mv extension ../
- name: Checkout pull request HEAD commit
uses: actions/checkout@v4
with:
ref: ${{ env.HEAD }}
- name: Setup Go ${{ matrix.go }}
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go }}
- name: Start Redis
run: docker run --name redis --publish 6379:6379 --detach redis:6
- name: Install FFmpeg 7.x
run: |
wget https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-linux64-gpl.tar.xz
tar -xf ffmpeg-master-latest-linux64-gpl.tar.xz
sudo cp ffmpeg-master-latest-linux64-gpl/bin/ffmpeg /usr/local/bin/
sudo cp ffmpeg-master-latest-linux64-gpl/bin/ffprobe /usr/local/bin/
sudo chmod +x /usr/local/bin/ffmpeg /usr/local/bin/ffprobe
- name: Test FFmpeg
run: ffmpeg -version
- name: Setup Go Tools
run: make tools
- name: Setup ${{ matrix.db }}
uses: ./.github/actions/setup-db
with:
kind: "${{ matrix.db }}"
db: "xiang"
user: "xiang"
password: ${{ secrets.UNIT_PASS }}
- name: Setup ENV
env:
PASSWORD: ${{ secrets.UNIT_PASS }}
run: |
echo "YAO_DB_DRIVER=$DB_DRIVER" >> $GITHUB_ENV
if [ "$DB_DRIVER" = "mysql" ]; then
echo "YAO_DB_PRIMARY=$DB_USER:$PASSWORD@$DB_HOST" >> $GITHUB_ENV
else
echo "YAO_DB_PRIMARY=${{ github.WORKSPACE }}/../app/db/yao.db" >> $GITHUB_ENV
mkdir -p ${{ github.WORKSPACE }}/../app/db
fi
- name: Run Benchmark & Memory Leak Tests
run: |
make benchmark
make memory-leak
# =============================================================================
# Core Tests - Run with DB matrix (MySQL/SQLite/Redis/Mongo combinations)
# =============================================================================
CoreTest:
runs-on: ubuntu-latest
services:
qdrant:
image: qdrant/qdrant:latest
ports:
- 6333:6333 # HTTP API
- 6334:6334 # gRPC
fastembed:
image: yaoapp/fastembed:latest-amd64
env:
FASTEMBED_PASSWORD: Yao@2026
ports:
- 6001:8000
neo4j:
image: neo4j:latest
ports:
- "7687:7687"
env:
NEO4J_AUTH: neo4j/Yao2026Neo4j
mcp-everything:
image: yaoapp/mcp-everything:latest
ports:
- "3021:3021"
- "3022:3022"
strategy:
matrix:
go: ["1.25"]
db: [MySQL8.0, SQLite3]
redis: [4, 5, 6]
mongo: ["6.0"]
if: >
${{ github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion == 'success' }}
steps:
- name: "Download artifact"
uses: actions/github-script@v7
with:
script: |
var artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{github.event.workflow_run.id }},
});
var matchArtifact = artifacts.data.artifacts.filter((artifact) => {
return artifact.name == "pr"
})[0];
var download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifact.id,
archive_format: 'zip',
});
var fs = require('fs');
fs.writeFileSync('${{github.workspace}}/pr.zip', Buffer.from(download.data));
- name: "Read NR & SHA"
run: |
unzip pr.zip
cat NR
cat SHA
echo HEAD=$(cat SHA) >> $GITHUB_ENV
echo NR=$(cat NR) >> $GITHUB_ENV
- name: "Comment on PR"
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { NR } = process.env
var fs = require('fs');
var issue_number = NR;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue_number,
body: 'Thank you for the PR! The db: ${{ matrix.db }} redis: ${{ matrix.redis }} mongo: ${{ matrix.mongo }} test workflow is running, the results of the run will be commented later.'
});
- name: Checkout Kun
uses: actions/checkout@v4
with:
repository: yaoapp/kun
path: kun
- name: Checkout Xun
uses: actions/checkout@v4
with:
repository: yaoapp/xun
path: xun
- name: Checkout Gou
uses: actions/checkout@v4
with:
repository: yaoapp/gou
path: gou
- name: Checkout V8Go
uses: actions/checkout@v4
with:
repository: yaoapp/v8go
path: v8go
- name: Unzip libv8
run: |
files=$(find ./v8go -name "libv8*.zip")
for file in $files; do
dir=$(dirname "$file") # Get the directory where the ZIP file is located
echo "Extracting $file to directory $dir"
unzip -o -d $dir $file
rm -rf $dir/__MACOSX
done
- name: Checkout Demo App
uses: actions/checkout@v4
with:
repository: yaoapp/yao-dev-app
path: app
- name: Checkout Yao Startup Webapp
uses: actions/checkout@v4
with:
repository: yaoapp/yao-startup-webapp
submodules: true
token: ${{ secrets.YAO_TEST_TOKEN }}
path: yao-startup-webapp
- name: Checkout Extension
uses: actions/checkout@v4
with:
repository: yaoapp/yao-extensions-dev
path: extension
- name: Move Kun, Xun, Gou, V8Go
run: |
mv kun ../
mv xun ../
mv gou ../
mv v8go ../
mv app ../
mv extension ../
mv yao-startup-webapp ../
ls -l .
ls -l ../
- name: Checkout pull request HEAD commit
uses: actions/checkout@v4
with:
ref: ${{ env.HEAD }}
- name: Setup Apple Private Key
run: |
mkdir -p ../app/openapi/certs/apple
echo "${{ secrets.APPLE_PRIVATE_KEY_USER }}" > ../app/openapi/certs/apple/signin_client_secret_key.p8
- name: Start Redis
run: docker run --name redis --publish 6379:6379 --detach redis:${{ matrix.redis }}
- name: Setup Go ${{ matrix.go }}
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go }}
- name: Install FFmpeg 7.x
run: |
wget https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-linux64-gpl.tar.xz
tar -xf ffmpeg-master-latest-linux64-gpl.tar.xz
sudo cp ffmpeg-master-latest-linux64-gpl/bin/ffmpeg /usr/local/bin/
sudo cp ffmpeg-master-latest-linux64-gpl/bin/ffprobe /usr/local/bin/
sudo chmod +x /usr/local/bin/ffmpeg /usr/local/bin/ffprobe
- name: Test FFmpeg
run: ffmpeg -version
- name: Install pdftoppm, mutool, imagemagick
run: |
sudo apt update
sudo apt install -y poppler-utils mupdf-tools imagemagick
- name: Test pdftoppm, mutool, imagemagick
run: |
pdftoppm -v
mutool -v
convert -version
- name: Start MongoDB
run: |
docker run --name mongodb --publish 27017:27017 \
-e MONGO_INITDB_DATABASE=test \
-e MONGO_INITDB_ROOT_USERNAME=root \
-e MONGO_INITDB_ROOT_PASSWORD=123456 \
--detach mongo:${{ matrix.mongo }}
# Wait for MongoDB to be ready
for i in $(seq 1 20); do
if docker exec mongodb mongosh --quiet --port 27017 --username root --password 123456 --eval "db.serverStatus()" > /dev/null 2>&1; then
echo "MongoDB is ready"
break
fi
echo "Waiting for MongoDB... ($i)"
sleep 1
done
- name: Setup MySQL8.0 (connector)
uses: ./.github/actions/setup-db
with:
kind: "MySQL8.0"
db: "test"
user: "test"
password: "123456"
port: "3308"
- name: Setup ${{ matrix.db }}
uses: ./.github/actions/setup-db
with:
kind: "${{ matrix.db }}"
db: "xiang"
user: "xiang"
password: ${{ secrets.UNIT_PASS }}
- name: Setup Go Tools
run: |
make tools
- name: Setup ENV & Host
env:
PASSWORD: ${{ secrets.UNIT_PASS }}
run: |
sudo echo "127.0.0.1 local.iqka.com" | sudo tee -a /etc/hosts
echo "YAO_DB_DRIVER=$DB_DRIVER" >> $GITHUB_ENV
echo "GITHUB_WORKSPACE:\n" && ls -l $GITHUB_WORKSPACE
if [ "$DB_DRIVER" = "mysql" ]; then
echo "YAO_DB_PRIMARY=$DB_USER:$PASSWORD@$DB_HOST" >> $GITHUB_ENV
elif [ "$DB_DRIVER" = "postgres" ]; then
echo "YAO_DB_PRIMARY=postgres://$DB_USER:$PASSWORD@$DB_HOST" >> $GITHUB_ENV
else
echo "YAO_DB_PRIMARY=$YAO_ROOT/$DB_HOST" >> $GITHUB_ENV
fi
echo ".:\n" && ls -l .
echo "..:\n" && ls -l ..
ping -c 1 -t 1 local.iqka.com
- name: Test Prepare
run: |
make vet
make fmt-check
make misspell-check
- name: Run Core Tests (exclude AI)
run: make unit-test-core
- name: Codecov Report
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos
- name: "Comment on PR"
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { NR } = process.env
var fs = require('fs');
var issue_number = NR;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue_number,
body: '✨DONE✨ db: ${{ matrix.db }} redis: ${{ matrix.redis }} mongo: ${{ matrix.mongo }} passed.'
});
# =============================================================================
# Registry Client SDK Tests (requires Yao Registry Docker service)
# =============================================================================
RegistryTest:
runs-on: ubuntu-latest
services:
yao-registry:
image: yaoapp/registry:latest
ports:
- "8080:8080"
env:
REGISTRY_INIT_USER: yaoagents
REGISTRY_INIT_PASS: yaoagents
strategy:
matrix:
go: ["1.25"]
if: >
${{ github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion == 'success' }}
steps:
- name: "Download artifact"
uses: actions/github-script@v7
with:
script: |
var artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{github.event.workflow_run.id }},
});
var matchArtifact = artifacts.data.artifacts.filter((artifact) => {
return artifact.name == "pr"
})[0];
var download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifact.id,
archive_format: 'zip',
});
var fs = require('fs');
fs.writeFileSync('${{github.workspace}}/pr.zip', Buffer.from(download.data));
- name: "Read NR & SHA"
run: |
unzip pr.zip
cat NR
cat SHA
echo HEAD=$(cat SHA) >> $GITHUB_ENV
echo NR=$(cat NR) >> $GITHUB_ENV
- name: "Comment on PR"
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { NR } = process.env
var issue_number = NR;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue_number,
body: '🤖 Registry Client SDK Tests running...'
});
- name: Wait for Registry
run: |
for i in $(seq 1 15); do
if curl -sf http://localhost:8080/.well-known/yao-registry > /dev/null 2>&1; then
echo "Registry is ready"
break
fi
echo "Waiting for registry... ($i)"
sleep 1
done
- name: Checkout Kun
uses: actions/checkout@v4
with:
repository: yaoapp/kun
path: kun
- name: Checkout Xun
uses: actions/checkout@v4
with:
repository: yaoapp/xun
path: xun
- name: Checkout Gou
uses: actions/checkout@v4
with:
repository: yaoapp/gou
path: gou
- name: Checkout V8Go
uses: actions/checkout@v4
with:
repository: yaoapp/v8go
path: v8go
- name: Unzip libv8
run: |
files=$(find ./v8go -name "libv8*.zip")
for file in $files; do
dir=$(dirname "$file")
echo "Extracting $file to directory $dir"
unzip -o -d $dir $file
rm -rf $dir/__MACOSX
done
- name: Checkout Demo App
uses: actions/checkout@v4
with:
repository: yaoapp/yao-dev-app
path: app
- name: Checkout Extension
uses: actions/checkout@v4
with:
repository: yaoapp/yao-extensions-dev
path: extension
- name: Move Dependencies
run: |
mv kun ../
mv xun ../
mv gou ../
mv v8go ../
mv app ../
mv extension ../
- name: Checkout pull request HEAD commit
uses: actions/checkout@v4
with:
ref: ${{ env.HEAD }}
- name: Setup Go ${{ matrix.go }}
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go }}
- name: Run Registry Client Tests
env:
YAO_REGISTRY_URL: http://localhost:8080
YAO_TEST_APPLICATION: ${{ github.workspace }}/../app
run: make unit-test-registry
- name: Codecov Report
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
- name: "Comment on PR - Registry Tests Done"
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { NR } = process.env
var issue_number = NR;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue_number,
body: '✅ Registry Client SDK Tests passed!'
});
# =============================================================================
# Benchmark: Sandbox V2 + Workspace (parallel with SandboxV2Test, non-blocking)
# =============================================================================
BenchmarkSandboxV2:
runs-on: ubuntu-latest
strategy:
matrix:
go: ["1.25"]
if: >
${{ github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion == 'success' }}
steps:
- name: "Download artifact"
uses: actions/github-script@v7
with:
script: |
var artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{github.event.workflow_run.id }},
});
var matchArtifact = artifacts.data.artifacts.filter((artifact) => {
return artifact.name == "pr"
})[0];
var download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifact.id,
archive_format: 'zip',
});
var fs = require('fs');
fs.writeFileSync('${{github.workspace}}/pr.zip', Buffer.from(download.data));
- name: "Read NR & SHA"
run: |
unzip pr.zip
cat NR
cat SHA
echo HEAD=$(cat SHA) >> $GITHUB_ENV
echo NR=$(cat NR) >> $GITHUB_ENV
- name: Checkout Kun
uses: actions/checkout@v4
with:
repository: yaoapp/kun
path: kun
- name: Checkout Xun
uses: actions/checkout@v4
with:
repository: yaoapp/xun
path: xun
- name: Checkout Gou
uses: actions/checkout@v4
with:
repository: yaoapp/gou
path: gou
- name: Checkout V8Go
uses: actions/checkout@v4
with:
repository: yaoapp/v8go
path: v8go
- name: Unzip libv8
run: |
files=$(find ./v8go -name "libv8*.zip")
for file in $files; do
dir=$(dirname "$file")
echo "Extracting $file to directory $dir"
unzip -o -d $dir $file
rm -rf $dir/__MACOSX
done
- name: Checkout Demo App
uses: actions/checkout@v4
with:
repository: yaoapp/yao-dev-app
path: app
- name: Checkout Extension
uses: actions/checkout@v4
with:
repository: yaoapp/yao-extensions-dev
path: extension
- name: Move Dependencies
run: |
mv kun ../
mv xun ../
mv gou ../
mv v8go ../
mv app ../
mv extension ../
- name: Checkout pull request HEAD commit
uses: actions/checkout@v4
with:
ref: ${{ env.HEAD }}
- name: Setup Apple Private Key
run: |
mkdir -p ../app/openapi/certs/apple
echo "${{ secrets.APPLE_PRIVATE_KEY_USER }}" > ../app/openapi/certs/apple/signin_client_secret_key.p8
- name: Setup Go ${{ matrix.go }}
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go }}
- name: Start Redis
run: docker run --name redis --publish 6379:6379 --detach redis:6
- name: Setup Go Tools
run: make tools
- name: Setup ENV (SQLite)
run: |
mkdir -p ${{ github.WORKSPACE }}/../app/db
echo "YAO_DB_DRIVER=sqlite3" >> $GITHUB_ENV
echo "YAO_DB_PRIMARY=${{ github.WORKSPACE }}/../app/db/yao.db" >> $GITHUB_ENV
- name: Pull Test Images
run: |
docker pull yaoapp/sandbox-v2-test:latest || true
docker pull yaoapp/tai:latest
docker pull alpine:latest
- name: Start Tai (Docker proxy for benchmarks)
run: |
docker run -d --name tai \
-v /var/run/docker.sock:/var/run/docker.sock \
-p 8080:8080 -p 9100:9100 -p 2375:2375 -p 6080:6080 \
yaoapp/tai:latest
for i in $(seq 1 30); do
if curl -sf http://127.0.0.1:8080/healthz > /dev/null 2>&1; then
echo "Tai HTTP is ready"
break
fi
echo "Waiting for Tai HTTP... ($i)"
sleep 1
done
for i in $(seq 1 15); do
if nc -z 127.0.0.1 9100 2>/dev/null; then
echo "Tai gRPC is ready"
break
fi
echo "Waiting for Tai gRPC... ($i)"
sleep 1
done
- name: Run Benchmarks
env:
TAI_TEST_HOST: "127.0.0.1"
TAI_TEST_DOCKER: "tcp://127.0.0.1:2375"
TAI_TEST_GRPC_PORT: "9100"
TAI_TEST_HOST_IP: "172.17.0.1"
SANDBOX_TEST_REMOTE_ADDR: "tai://127.0.0.1:9100"
SANDBOX_TEST_IMAGE: "yaoapp/sandbox-v2-test:latest"
run: make benchmark-sandbox-v2
# =============================================================================
# gRPC Tests - Run once with SQLite (transport layer, no DB matrix needed)
# =============================================================================
GRPCTest:
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"]
if: >
${{ github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion == 'success' }}
steps:
- name: "Download artifact"
uses: actions/github-script@v7
with:
script: |
var artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{github.event.workflow_run.id }},
});
var matchArtifact = artifacts.data.artifacts.filter((artifact) => {
return artifact.name == "pr"
})[0];
var download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifact.id,
archive_format: 'zip',
});
var fs = require('fs');
fs.writeFileSync('${{github.workspace}}/pr.zip', Buffer.from(download.data));
- name: "Read NR & SHA"
run: |
unzip pr.zip
cat NR
cat SHA
echo HEAD=$(cat SHA) >> $GITHUB_ENV
echo NR=$(cat NR) >> $GITHUB_ENV
- name: "Comment on PR"
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { NR } = process.env
var issue_number = NR;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue_number,
body: '🤖 gRPC Tests running with SQLite...'
});
- name: Checkout Kun
uses: actions/checkout@v4
with:
repository: yaoapp/kun
path: kun
- name: Checkout Xun
uses: actions/checkout@v4
with:
repository: yaoapp/xun
path: xun
- name: Checkout Gou
uses: actions/checkout@v4
with:
repository: yaoapp/gou
path: gou
- name: Checkout V8Go
uses: actions/checkout@v4
with:
repository: yaoapp/v8go
path: v8go
- name: Unzip libv8
run: |
files=$(find ./v8go -name "libv8*.zip")
for file in $files; do
dir=$(dirname "$file")
echo "Extracting $file to directory $dir"
unzip -o -d $dir $file
rm -rf $dir/__MACOSX
done
- name: Checkout Demo App
uses: actions/checkout@v4
with:
repository: yaoapp/yao-dev-app
path: app
- name: Checkout Extension
uses: actions/checkout@v4
with:
repository: yaoapp/yao-extensions-dev
path: extension
- name: Move Dependencies
run: |
mv kun ../
mv xun ../
mv gou ../
mv v8go ../
mv app ../
mv extension ../
- name: Checkout pull request HEAD commit
uses: actions/checkout@v4
with:
ref: ${{ env.HEAD }}
- name: Setup Apple Private Key
run: |
mkdir -p ../app/openapi/certs/apple
echo "${{ secrets.APPLE_PRIVATE_KEY_USER }}" > ../app/openapi/certs/apple/signin_client_secret_key.p8
- name: Setup Go ${{ matrix.go }}
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go }}
- name: Start Redis
run: docker run --name redis --publish 6379:6379 --detach redis:6
- name: Setup Go Tools
run: make tools
- name: Setup ENV (SQLite)
run: |
mkdir -p ${{ github.WORKSPACE }}/../app/db
echo "YAO_DB_DRIVER=sqlite3" >> $GITHUB_ENV
echo "YAO_DB_PRIMARY=${{ github.WORKSPACE }}/../app/db/yao.db" >> $GITHUB_ENV
- name: Run gRPC Tests
run: make unit-test-grpc
- name: Codecov Report
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
- name: "Comment on PR - gRPC Tests Done"
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { NR } = process.env
var issue_number = NR;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue_number,
body: '✅ gRPC Tests passed!'
});