Merge pull request #748 from LLOneBot/dev #61
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Test | |
| on: | |
| pull_request: | |
| branches: [main] | |
| push: | |
| branches: [main] | |
| jobs: | |
| unit-test: | |
| name: Unit Tests | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 24 | |
| - name: Install dependencies | |
| run: | | |
| corepack enable | |
| yarn install --no-immutable | |
| cd src/webui/FE && npm install | |
| - name: Run unit tests | |
| run: npm run test:unit | |
| - name: Run WebUI tests | |
| run: npm run test:webui | |
| e2e-test: | |
| name: E2E Tests | |
| runs-on: [self-hosted, llbot-test] | |
| needs: [unit-test] | |
| if: github.event_name == 'pull_request' | |
| steps: | |
| - name: Cleanup root-owned files | |
| run: sudo rm -rf ${{ github.workspace }}/workspace1 ${{ github.workspace }}/workspace2 ${{ github.workspace }}/test/onebot11-api-test/node_modules | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 24 | |
| - name: Install dependencies | |
| run: | | |
| corepack enable | |
| yarn install --no-immutable | |
| cd src/webui/FE && npm install | |
| - name: Build | |
| run: | | |
| npm run build | |
| npm run build-webui | |
| - name: Build PR LLBot image | |
| run: docker build -f docker/Dockerfile.test -t llbot-pr-test . | |
| - name: Write configs | |
| run: | | |
| mkdir -p workspace1/data workspace2/data | |
| cat > workspace1/data/config_1577491075.json << 'CONF' | |
| { | |
| "ob11": { | |
| "enable": true, | |
| "connect": [ | |
| { "type": "http", "enable": true, "host": "", "port": 53000, "token": "123", "messageFormat": "array", "reportSelfMessage": false, "reportOfflineMessage": false, "debug": false } | |
| ] | |
| }, | |
| "satori": { "enable": false }, | |
| "milky": { "enable": false }, | |
| "webui": { "enable": false } | |
| } | |
| CONF | |
| cat > workspace2/data/config_412805684.json << 'CONF' | |
| { | |
| "ob11": { | |
| "enable": true, | |
| "connect": [ | |
| { "type": "http", "enable": true, "host": "", "port": 53001, "token": "123", "messageFormat": "array", "reportSelfMessage": false, "reportOfflineMessage": false, "debug": false } | |
| ] | |
| }, | |
| "satori": { "enable": false }, | |
| "milky": { "enable": false }, | |
| "webui": { "enable": false } | |
| } | |
| CONF | |
| - name: Restart PMHQ with workspace mount | |
| run: | | |
| docker stop pmhq1 pmhq2 | |
| docker rm -f pmhq1-test pmhq2-test 2>/dev/null || true | |
| docker run -d --name pmhq1-test \ | |
| --network llbot-test_test_network \ | |
| --privileged \ | |
| -e ENABLE_HEADLESS=false \ | |
| -e AUTO_LOGIN_QQ=1577491075 \ | |
| -v llbot-test_qq_volume1:/root/.config/QQ \ | |
| -v ${{ github.workspace }}:/app/workspace:rw \ | |
| -v ${{ github.workspace }}/workspace1/data:/app/llbot/data:rw \ | |
| linyuchen/pmhq:latest | |
| docker run -d --name pmhq2-test \ | |
| --network llbot-test_test_network \ | |
| --privileged \ | |
| -e ENABLE_HEADLESS=false \ | |
| -e AUTO_LOGIN_QQ=412805684 \ | |
| -v llbot-test_qq_volume2:/root/.config/QQ \ | |
| -v ${{ github.workspace }}:/app/workspace:rw \ | |
| -v ${{ github.workspace }}/workspace2/data:/app/llbot/data:rw \ | |
| linyuchen/pmhq:latest | |
| echo "Waiting for PMHQ to be ready..." | |
| for i in $(seq 1 30); do | |
| H1=$(docker exec pmhq1-test curl -sf http://localhost:13000/health 2>/dev/null || true) | |
| H2=$(docker exec pmhq2-test curl -sf http://localhost:13000/health 2>/dev/null || true) | |
| [ -n "$H1" ] && [ -n "$H2" ] && echo "Both PMHQ ready" && break | |
| echo "Waiting for PMHQ... ($i/30)" | |
| sleep 5 | |
| done | |
| - name: Start PR LLBot containers | |
| run: | | |
| docker rm -f llbot-pr1 llbot-pr2 2>/dev/null || true | |
| docker run -d --name llbot-pr1 \ | |
| --network llbot-test_test_network \ | |
| -e pmhq_host=pmhq1-test \ | |
| -e pmhq_port=13000 \ | |
| -e WEBUI_PORT=3091 \ | |
| -v llbot-test_qq_volume1:/root/.config/QQ \ | |
| -v ${{ github.workspace }}/workspace1/data:/app/llbot/data:rw \ | |
| -v ${{ github.workspace }}:/app/workspace:ro \ | |
| llbot-pr-test | |
| docker run -d --name llbot-pr2 \ | |
| --network llbot-test_test_network \ | |
| -e pmhq_host=pmhq2-test \ | |
| -e pmhq_port=13000 \ | |
| -e WEBUI_PORT=3092 \ | |
| -v llbot-test_qq_volume2:/root/.config/QQ \ | |
| -v ${{ github.workspace }}/workspace2/data:/app/llbot/data:rw \ | |
| -v ${{ github.workspace }}:/app/workspace:ro \ | |
| llbot-pr-test | |
| - name: Wait for LLBot ready | |
| run: | | |
| for i in $(seq 1 60); do | |
| R1=$(docker exec llbot-pr1 curl -sf http://127.0.0.1:53000/get_login_info -H "Authorization: Bearer 123" 2>/dev/null || true) | |
| R2=$(docker exec llbot-pr2 curl -sf http://127.0.0.1:53001/get_login_info -H "Authorization: Bearer 123" 2>/dev/null || true) | |
| [ -n "$R1" ] && [ -n "$R2" ] && echo "Both LLBot instances ready" && break | |
| echo "Waiting... ($i/60)" | |
| sleep 5 | |
| done | |
| - name: Write test config | |
| run: | | |
| cat > ${{ github.workspace }}/test/onebot11-api-test/config/test.config.json << 'CONF' | |
| { | |
| "accounts": { | |
| "primary": { | |
| "host": "http://llbot-pr1:53000", | |
| "apiKey": "123", | |
| "protocol": "http", | |
| "user_id": "1577491075" | |
| }, | |
| "secondary": { | |
| "host": "http://llbot-pr2:53001", | |
| "apiKey": "123", | |
| "protocol": "http", | |
| "user_id": "412805684" | |
| } | |
| }, | |
| "test_group_id": "1098066573", | |
| "timeout": 30000, | |
| "retryAttempts": 3 | |
| } | |
| CONF | |
| - name: Run e2e tests in Docker | |
| run: | | |
| docker run --rm --name e2e-runner \ | |
| --network llbot-test_test_network \ | |
| -v ${{ github.workspace }}:/app/workspace:rw \ | |
| -w /app/workspace/test/onebot11-api-test \ | |
| node:24-alpine3.23 sh -c "npm install && npm test" | |
| continue-on-error: true | |
| - name: Show test summary | |
| if: always() | |
| run: | | |
| if [ -f test/onebot11-api-test/test-report.html ]; then | |
| echo "Test report generated" | |
| else | |
| echo "No test report found" | |
| fi | |
| - name: Stop test containers and restore PMHQ | |
| if: always() | |
| run: | | |
| echo "=== LLBot1 logs ===" && docker logs llbot-pr1 2>&1 | tail -30 || true | |
| echo "=== LLBot2 logs ===" && docker logs llbot-pr2 2>&1 | tail -30 || true | |
| docker rm -f llbot-pr1 llbot-pr2 pmhq1-test pmhq2-test 2>/dev/null || true | |
| docker start pmhq1 pmhq2 2>/dev/null || true | |
| sudo rm -rf ${{ github.workspace }}/workspace1 ${{ github.workspace }}/workspace2 | |
| - name: Upload test report | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: e2e-test-report | |
| path: test/onebot11-api-test/test-report.html | |
| retention-days: 30 | |
| report: | |
| name: Test Report | |
| runs-on: ubuntu-latest | |
| needs: [unit-test, e2e-test] | |
| if: always() && github.event_name == 'pull_request' | |
| permissions: | |
| pull-requests: write | |
| steps: | |
| - name: Generate report comment | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const jobs = { | |
| 'unit-test': '${{ needs.unit-test.result }}', | |
| 'e2e-test': '${{ needs.e2e-test.result }}', | |
| }; | |
| const icons = { success: '✅', failure: '❌', skipped: '⏭️', cancelled: '🚫' }; | |
| const lines = Object.entries(jobs).map(([name, result]) => | |
| `| ${name} | ${icons[result] || '❓'} ${result} |` | |
| ); | |
| const allPassed = Object.values(jobs).every(r => r === 'success' || r === 'skipped'); | |
| const summary = allPassed ? '✅ All tests passed' : '❌ Some tests failed'; | |
| const body = [ | |
| `## Test Report`, | |
| ``, | |
| `| Job | Status |`, | |
| `|-----|--------|`, | |
| ...lines, | |
| ``, | |
| summary, | |
| ].join('\n'); | |
| // Find existing comment | |
| const { data: comments } = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| }); | |
| const botComment = comments.find(c => | |
| c.user.type === 'Bot' && c.body.includes('## Test Report') | |
| ); | |
| if (botComment) { | |
| await github.rest.issues.updateComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: botComment.id, | |
| body, | |
| }); | |
| } else { | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body, | |
| }); | |
| } |