Skip to content

fix(intelligence): replace unsafe number-grabbing fallback in _parse_… #745

fix(intelligence): replace unsafe number-grabbing fallback in _parse_…

fix(intelligence): replace unsafe number-grabbing fallback in _parse_… #745

Workflow file for this run

name: Regression Tests
on:
push:
branches: [main]
paths:
- 'src/**'
- 'tests/**'
- 'pyproject.toml'
- 'Makefile'
pull_request_target:
branches: [main]
paths:
- 'src/**'
- 'tests/**'
- 'pyproject.toml'
- 'Makefile'
workflow_dispatch:
inputs:
pr_number:
description: 'PR number to test (e.g., 123). Leave empty if using ref instead.'
required: false
type: string
ref:
description: 'Branch, tag, or commit SHA to test (e.g., feature-branch or abc123). Leave empty if using PR number.'
required: false
type: string
schedule:
- cron: '0 16 * * *'
jobs:
test1:
runs-on: ubuntu-latest
# Skip on forks: schedule/push only run in the upstream repo (secrets are unavailable in forks).
# External PRs (from forks) require manual trigger via workflow_dispatch.
if: |
(github.event_name == 'push' && github.repository == 'oceanbase/powermem') ||
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'schedule' && github.repository == 'oceanbase/powermem') ||
(github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name == github.repository)
strategy:
matrix:
python-version: ["3.11"]
fail-fast: false
steps:
- name: Get PR SHA (if PR number provided)
if: github.event_name == 'workflow_dispatch' && github.event.inputs.pr_number != ''
id: get_pr_sha
uses: actions/github-script@v9
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const prNumber = context.payload.inputs.pr_number;
const { data: pr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: parseInt(prNumber)
});
console.log(`PR #${prNumber} head SHA: ${pr.head.sha}`);
core.setOutput('sha', pr.head.sha);
- name: Checkout code
uses: actions/checkout@v6
# For pull_request_target, checkout the PR branch
# For workflow_dispatch, checkout the PR SHA (if PR number provided), or specified ref, or default branch
# For push, checkout the pushed branch
with:
ref: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || (github.event_name == 'workflow_dispatch' && (github.event.inputs.pr_number != '' && steps.get_pr_sha.outputs.sha || github.event.inputs.ref || github.ref)) || github.ref }}
fetch-depth: 0
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
- name: Upgrade pip
run: |
python -m pip install --upgrade pip
pip install --upgrade setuptools wheel
- name: Cache pip dependencies
uses: actions/cache@v5
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/pyproject.toml') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install dependencies
run: |
pip install -e ".[dev,test,server,seekdb]"
- name: Deploy SeekDB (OceanBase)
run: |
# Remove existing container if it exists
sudo docker rm -f seekdb 2>/dev/null || true
# Start SeekDB container
sudo docker run -d -p 10001:2881 -e MEMORY_LIMIT=6G -e LOG_DISK_SIZE=6G -e DATAFILE_SIZE=6G -e DATAFILE_NEXT=6G -e DATAFILE_MAXSIZE=100G --name seekdb oceanbase/seekdb
# Wait for database to be ready
echo "Waiting for SeekDB to be ready..."
timeout=60
elapsed=0
while [ $elapsed -lt $timeout ]; do
if sudo docker exec seekdb mysql -uroot -e "SELECT 1" > /dev/null 2>&1; then
echo "✓ SeekDB is ready!"
break
fi
echo "Waiting for SeekDB... ($elapsed/$timeout seconds)"
sleep 2
elapsed=$((elapsed + 2))
done
if [ $elapsed -ge $timeout ]; then
echo "⚠ Warning: SeekDB may not be fully ready, but continuing..."
fi
# Show container status
echo "SeekDB container status:"
sudo docker ps | grep seekdb || true
echo "Recent logs:"
sudo docker logs --tail 20 seekdb || true
mysql -uroot -h127.0.0.1 -P10001 -e "CREATE DATABASE IF NOT EXISTS powermem;" || echo "⚠ Warning: Failed to create database, but continuing..."
mysql -uroot -h127.0.0.1 -P10001 -e "SHOW DATABASES LIKE 'powermem';" || echo "⚠ Warning: Could not verify database, but continuing..."
- name: Set env
env:
QWEN_API_KEY: "${{ secrets.QWEN_API_KEY }}"
SILICONFLOW_CN_API_KEY: "${{ secrets.SILICONFLOW_CN_API_KEY }}"
SILICONFLOW_COM_API_KEY: "${{ secrets.SILICONFLOW_COM_API_KEY }}"
run: |
echo "QWEN_API_KEY length: ${#QWEN_API_KEY}"
echo "SILICONFLOW_CN_API_KEY length: ${#SILICONFLOW_CN_API_KEY}"
echo "SILICONFLOW_COM_API_KEY length: ${#SILICONFLOW_COM_API_KEY}"
cp .env.example .env
set_env_var() {
local key="$1"
local value="$2"
awk -v prefix="${key}=" 'index($0, prefix) != 1 { print }' .env > .env.tmp
mv .env.tmp .env
printf '%s=%s\n' "${key}" "${value}" >> .env
}
# Update existing environment variables
set_env_var OCEANBASE_HOST 127.0.0.1
set_env_var OCEANBASE_PORT 10001
set_env_var OCEANBASE_USER root
set_env_var OCEANBASE_PASSWORD ""
set_env_var OCEANBASE_DATABASE powermem
set_env_var OCEANBASE_COLLECTION memories_1536
set_env_var DATABASE_PROVIDER oceanbase
set_env_var LLM_PROVIDER siliconflow
set_env_var LLM_MODEL THUDM/GLM-4-9B-0414
set_env_var SILICONFLOW_LLM_BASE_URL https://api.siliconflow.cn/v1
set_env_var EMBEDDING_PROVIDER qwen
set_env_var EMBEDDING_MODEL text-embedding-v4
set_env_var EMBEDDING_DIMS 1536
set_env_var QWEN_EMBEDDING_BASE_URL https://dashscope.aliyuncs.com/api/v1
set_env_var GRAPH_STORE_PORT 10001
set_env_var GRAPH_STORE_PASSWORD ""
set_env_var OCEANBASE_EMBEDDING_MODEL_DIMS 1536
set_env_var LLM_API_KEY "${SILICONFLOW_CN_API_KEY}"
set_env_var EMBEDDING_API_KEY "${QWEN_API_KEY}"
set_env_var POWERMEM_SERVER_API_KEYS key1,key2,key3
set_env_var POWERMEM_SERVER_WORKERS 1
- name: Run regression tests
id: run_tests
env:
QWEN_API_KEY: "${{ secrets.QWEN_API_KEY }}"
SILICONFLOW_CN_API_KEY: "${{ secrets.SILICONFLOW_CN_API_KEY }}"
SILICONFLOW_COM_API_KEY: "${{ secrets.SILICONFLOW_COM_API_KEY }}"
run: |
mkdir -p report
pytest tests/regression/test_scenario*.py -vs --junitxml=report/test1.xml
- name: Upload JUnit report
if: always() && (steps.run_tests.outcome == 'success' || steps.run_tests.outcome == 'failure')
uses: actions/upload-artifact@v7
with:
name: junit-test1
path: report/
- name: Cleanup Docker
if: always()
run: |
echo "清理 Docker 容器..."
sudo docker rm -f seekdb 2>/dev/null || true
sudo docker ps
echo "✓ 清理完成"
test2:
runs-on: ubuntu-latest
# Skip on forks: schedule/push only run in the upstream repo (secrets are unavailable in forks).
# External PRs (from forks) require manual trigger via workflow_dispatch.
if: |
(github.event_name == 'push' && github.repository == 'oceanbase/powermem') ||
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'schedule' && github.repository == 'oceanbase/powermem') ||
(github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name == github.repository)
strategy:
matrix:
python-version: ["3.11"]
fail-fast: false
steps:
- name: Get PR SHA (if PR number provided)
if: github.event_name == 'workflow_dispatch' && github.event.inputs.pr_number != ''
id: get_pr_sha
uses: actions/github-script@v9
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const prNumber = context.payload.inputs.pr_number;
const { data: pr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: parseInt(prNumber)
});
console.log(`PR #${prNumber} head SHA: ${pr.head.sha}`);
core.setOutput('sha', pr.head.sha);
- name: Checkout code
uses: actions/checkout@v6
# For pull_request_target, checkout the PR branch
# For workflow_dispatch, checkout the PR SHA (if PR number provided), or specified ref, or default branch
# For push, checkout the pushed branch
with:
ref: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || (github.event_name == 'workflow_dispatch' && (github.event.inputs.pr_number != '' && steps.get_pr_sha.outputs.sha || github.event.inputs.ref || github.ref)) || github.ref }}
fetch-depth: 0
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
- name: Upgrade pip
run: |
python -m pip install --upgrade pip
pip install --upgrade setuptools wheel
- name: Cache pip dependencies
uses: actions/cache@v5
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/pyproject.toml') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install dependencies
run: |
pip install -e ".[dev,test,server,seekdb]"
- name: Deploy SeekDB (OceanBase)
run: |
# Remove existing container if it exists
sudo docker rm -f seekdb 2>/dev/null || true
# Start SeekDB container
sudo docker run -d -p 10001:2881 -e MEMORY_LIMIT=6G -e LOG_DISK_SIZE=6G -e DATAFILE_SIZE=6G -e DATAFILE_NEXT=6G -e DATAFILE_MAXSIZE=100G --name seekdb oceanbase/seekdb
# Wait for database to be ready
echo "Waiting for SeekDB to be ready..."
timeout=60
elapsed=0
while [ $elapsed -lt $timeout ]; do
if sudo docker exec seekdb mysql -uroot -e "SELECT 1" > /dev/null 2>&1; then
echo "✓ SeekDB is ready!"
break
fi
echo "Waiting for SeekDB... ($elapsed/$timeout seconds)"
sleep 2
elapsed=$((elapsed + 2))
done
if [ $elapsed -ge $timeout ]; then
echo "⚠ Warning: SeekDB may not be fully ready, but continuing..."
fi
# Show container status
echo "SeekDB container status:"
sudo docker ps | grep seekdb || true
echo "Recent logs:"
sudo docker logs --tail 20 seekdb || true
mysql -uroot -h127.0.0.1 -P10001 -e "CREATE DATABASE IF NOT EXISTS powermem;" || echo "⚠ Warning: Failed to create database, but continuing..."
mysql -uroot -h127.0.0.1 -P10001 -e "SHOW DATABASES LIKE 'powermem';" || echo "⚠ Warning: Could not verify database, but continuing..."
- name: Set env
env:
QWEN_API_KEY: "${{ secrets.QWEN_API_KEY }}"
SILICONFLOW_CN_API_KEY: "${{ secrets.SILICONFLOW_CN_API_KEY }}"
SILICONFLOW_COM_API_KEY: "${{ secrets.SILICONFLOW_COM_API_KEY }}"
run: |
echo "QWEN_API_KEY length: ${#QWEN_API_KEY}"
echo "SILICONFLOW_CN_API_KEY length: ${#SILICONFLOW_CN_API_KEY}"
echo "SILICONFLOW_COM_API_KEY length: ${#SILICONFLOW_COM_API_KEY}"
cp .env.example .env
set_env_var() {
local key="$1"
local value="$2"
awk -v prefix="${key}=" 'index($0, prefix) != 1 { print }' .env > .env.tmp
mv .env.tmp .env
printf '%s=%s\n' "${key}" "${value}" >> .env
}
# Update existing environment variables
set_env_var OCEANBASE_HOST 127.0.0.1
set_env_var OCEANBASE_PORT 10001
set_env_var OCEANBASE_USER root
set_env_var OCEANBASE_PASSWORD ""
set_env_var OCEANBASE_DATABASE powermem
set_env_var OCEANBASE_COLLECTION memories_1536
set_env_var DATABASE_PROVIDER oceanbase
set_env_var LLM_PROVIDER siliconflow
set_env_var LLM_MODEL THUDM/GLM-4-9B-0414
set_env_var SILICONFLOW_LLM_BASE_URL https://api.siliconflow.cn/v1
set_env_var EMBEDDING_PROVIDER qwen
set_env_var EMBEDDING_MODEL text-embedding-v4
set_env_var EMBEDDING_DIMS 1536
set_env_var QWEN_EMBEDDING_BASE_URL https://dashscope.aliyuncs.com/api/v1
set_env_var GRAPH_STORE_PORT 10001
set_env_var GRAPH_STORE_PASSWORD ""
set_env_var OCEANBASE_EMBEDDING_MODEL_DIMS 1536
set_env_var LLM_API_KEY "${SILICONFLOW_CN_API_KEY}"
set_env_var EMBEDDING_API_KEY "${QWEN_API_KEY}"
set_env_var POWERMEM_SERVER_API_KEYS key1,key2,key3
set_env_var POWERMEM_SERVER_WORKERS 1
- name: Run regression tests
id: run_tests
env:
QWEN_API_KEY: "${{ secrets.QWEN_API_KEY }}"
SILICONFLOW_CN_API_KEY: "${{ secrets.SILICONFLOW_CN_API_KEY }}"
SILICONFLOW_COM_API_KEY: "${{ secrets.SILICONFLOW_COM_API_KEY }}"
run: |
mkdir -p report
pytest tests/regression/ --ignore-glob='*test_scenario*.py' -vs --junitxml=report/test2.xml
- name: Upload JUnit report
if: always() && (steps.run_tests.outcome == 'success' || steps.run_tests.outcome == 'failure')
uses: actions/upload-artifact@v7
with:
name: junit-test2
path: report/
- name: Cleanup Docker
if: always()
run: |
echo "清理 Docker 容器..."
sudo docker rm -f seekdb 2>/dev/null || true
sudo docker ps
echo "✓ 清理完成"
report:
runs-on: ubuntu-latest
needs: [test1, test2]
if: always() && (needs.test1.result == 'success' || needs.test1.result == 'failure') && (needs.test2.result == 'success' || needs.test2.result == 'failure')
steps:
- name: Download JUnit artifacts
uses: actions/download-artifact@v8
with:
pattern: junit-*
- name: Collect JUnit reports
run: |
mkdir -p all-reports
# download-artifact may only fetch reports from successful test shards.
# Search existing junit-* directories instead of assuming every shard
# produced an artifact.
report_dirs=(junit-*)
if [ -d "${report_dirs[0]}" ]; then
find "${report_dirs[@]}" -maxdepth 3 -name '*.xml' -exec cp {} all-reports/ \;
else
echo "No JUnit artifact directories found."
fi
ls -la all-reports/
- name: Publish Test Report Summary
uses: mikepenz/action-junit-report@v6
if: always()
with:
report_paths: 'all-reports/*.xml'
require_tests: false
job_name: Regression Tests
check_name: Test Report