Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .codex/skills/code-review-testing/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: Author and run risk-based tests for AsterRouter changes across the

# AsterRouter Test Authoring

Read `docs/test/v1/README.md` before broad or cross-surface changes. Treat that plan as the source of truth for priorities, environments, and release gates.
Read `docs/test/v1/README.md` and `docs/test/v1/scenario-registry.json` before broad or cross-surface changes. Treat them as the source of truth for proof levels, priorities, environments, and delivery gates.

## Select the test layer

Expand All @@ -20,6 +20,7 @@ Use these project conventions:
- Use `httptest` for HTTP routes, authentication middleware, gateway forwarding, streaming, and upstream failures.
- Use memory repositories for fast domain tests; use PostgreSQL for SQL, transactions, constraints, migration compatibility, and restart persistence.
- Add frontend unit or component tests for deterministic state and rendering. Use browser tests for routing, authentication, forms, responsive behavior, and multi-step workflows.
- Give every Playwright test one unique `@e2e-*` scenario ID and register its owner, fixture, proof level, claim boundary, routes, and delivery gates. New user-visible routes must have both a surface contract and a vertical journey.
- Do not add production-only test hooks. Extract a real interface only when it improves production design.
- Mock official services, identity providers, mail, object storage, plugins, and model upstreams by default. Never send secrets or test traffic to production.

Expand Down Expand Up @@ -55,9 +56,10 @@ cd frontend
npm run typecheck
npm run build
npm run check:enterprise-surface
npm run check:e2e-coverage
```

When the test scripts defined by the v1 plan are present, also run the relevant `test:unit` and `test:e2e` targets. Do not claim frontend regression coverage based on typecheck or build alone.
Run `test:e2e:pr`, `test:e2e:full`, or `test:e2e:release` according to the gate declared by the registry. Do not select release scenarios with hand-maintained grep lists, and do not claim frontend regression coverage based on typecheck or build alone.

## Report evidence

Expand Down
4 changes: 3 additions & 1 deletion .codex/skills/remote-tests/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: Validate AsterRouter outside its in-memory fast path using PostgreS

# AsterRouter Environment Tests

Read the environment matrix and release gates in `docs/test/v1/README.md` before testing. Start with an isolated local environment and move outward only when the narrower environment passes.
Read `docs/test/v1/README.md` and `docs/test/v1/scenario-registry.json` before testing. Start with an isolated local environment and move outward only when the narrower proof level passes.

## Choose the environment

Expand Down Expand Up @@ -44,6 +44,8 @@ For containers and release artifacts, verify:
- checksums, `--version`, archive contents, install, upgrade, rollback, and restart;
- backup creation, restore into an empty database, and restored critical-record counts.

Gate B scenarios are selected from `gates: ["release"]` in the registry. Never restore hand-maintained `@jNN` grep lists. Candidate evidence must include the selected stable scenario IDs, version, commit, database class, candidate path, and single-origin URL.

Use fake upstream model APIs and fake official services. Cover normal JSON, server-sent streaming, timeout, malformed payload, 429, 5xx, and connection interruption without contacting a live provider.

## Remote deployment discipline
Expand Down
5 changes: 4 additions & 1 deletion .codex/skills/test-ui/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: Exercise and verify AsterRouter's Vue user interfaces in a browser,

# AsterRouter UI Tests

Read the UI coverage and critical journeys in `docs/test/v1/README.md`. Use an available browser-control tool for exploratory checks and Playwright suites once the v1 harness exists.
Read `docs/test/v1/README.md` and `docs/test/v1/scenario-registry.json`. The registry is the machine source of truth for browser routes, stable scenario IDs, fixtures, proof levels, and delivery gates.

## Start safely

Expand All @@ -22,6 +22,7 @@ Read the UI coverage and critical journeys in `docs/test/v1/README.md`. Use an a
4. Verify the browser URL, visible result, API request, persisted state after reload, and relevant audit evidence.
5. Check that forbidden surfaces redirect or return an authorization-safe state without leaking data.
6. Inspect console errors, failed network requests, unhandled promises, and unexpected page reloads.
7. Assert the canonical URL after navigation so Vue catch-all redirects cannot make a stale route appear to pass.

Prioritize these journeys:

Expand All @@ -39,6 +40,8 @@ For changed controls, verify keyboard navigation, visible focus, accessible name

Use screenshots as evidence, not as the only assertion. Prefer stable semantic locators and behavior assertions over CSS selectors or pixel-perfect snapshots.

Do not use fixed sleeps. Use Playwright web-first assertions, response/event waits, or `expect.poll`. A new user-visible route requires a surface contract at all supported viewports and at least one registered vertical journey; run `npm run check:e2e-coverage` before broader browser tests.

## Report evidence

Record the URL, profile/role, viewport, locale/theme, actions, expected and actual result, console/network findings, and screenshot path. For failures, provide the shortest reproducible sequence and the request ID when available.
25 changes: 25 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,14 @@ jobs:
bash scripts/test-release-browser-journeys.sh "${{ steps.version.outputs.version }}"
grep -Fxq 'release_browser_journeys=passed' "${{ runner.temp }}/asterrouter-release-journeys/report.txt"

- name: Validate system update lifecycle
env:
ASTER_SYSTEM_UPDATE_E2E_DIR: ${{ runner.temp }}/asterrouter-system-update-lifecycle
ASTER_SYSTEM_UPDATE_E2E_OLD_VERSION: ${{ steps.version.outputs.version }}
run: |
bash scripts/test-system-update-lifecycle.sh
grep -Fxq 'system_update_lifecycle=passed' "${{ runner.temp }}/asterrouter-system-update-lifecycle/report.txt"

- name: Validate Linux install, upgrade, and rollback
env:
ASTER_INSTALLER_TEST_DIR: ${{ runner.temp }}/asterrouter-installer-test
Expand Down Expand Up @@ -146,9 +154,26 @@ jobs:
path: |
${{ runner.temp }}/asterrouter-release-journeys/report.txt
${{ runner.temp }}/asterrouter-release-journeys/fake-upstream.log
${{ runner.temp }}/asterrouter-release-journeys/fake-official.log
${{ runner.temp }}/asterrouter-release-journeys/fake-smtp.log
${{ runner.temp }}/asterrouter-release-journeys/fake-s3.log
${{ runner.temp }}/asterrouter-release-journeys/setup/report.txt
${{ runner.temp }}/asterrouter-release-journeys/setup/runtime.log
${{ runner.temp }}/asterrouter-release-journeys/setup/playwright
${{ runner.temp }}/asterrouter-release-journeys/enterprise/runtime.log
${{ runner.temp }}/asterrouter-release-journeys/enterprise/playwright
if-no-files-found: ignore
- name: Upload system update lifecycle evidence
if: always()
uses: actions/upload-artifact@v7
with:
name: asterrouter-system-update-lifecycle
path: |
${{ runner.temp }}/asterrouter-system-update-lifecycle/report.txt
${{ runner.temp }}/asterrouter-system-update-lifecycle/generations.log
${{ runner.temp }}/asterrouter-system-update-lifecycle/supervisor.log
${{ runner.temp }}/asterrouter-system-update-lifecycle/runtime.log
${{ runner.temp }}/asterrouter-system-update-lifecycle/postgres.log
${{ runner.temp }}/asterrouter-system-update-lifecycle/official.log
${{ runner.temp }}/asterrouter-system-update-lifecycle/playwright
if-no-files-found: ignore
8 changes: 6 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ jobs:
--health-retries 20
env:
ASTERROUTER_SERVER_STORAGE_DATABASE_URL: postgres://asterrouter:asterrouter@127.0.0.1:5432/asterrouter_e2e_test?sslmode=disable
ASTER_E2E_ALLOW_DESTRUCTIVE_RESTORE: '1'
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v6
Expand All @@ -216,9 +217,12 @@ jobs:
- name: Install Chromium
working-directory: frontend
run: npx playwright install --with-deps chromium
- name: Browser smoke tests
- name: Check E2E coverage contract
working-directory: frontend
run: npm run test:e2e:smoke
run: npm run check:e2e-coverage
- name: Pull request browser gate
working-directory: frontend
run: npm run test:e2e:pr
- name: Create isolated first-install database
env:
PGPASSWORD: asterrouter
Expand Down
48 changes: 44 additions & 4 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ jobs:
--health-retries 20
env:
ASTERROUTER_SERVER_STORAGE_DATABASE_URL: postgres://asterrouter:asterrouter@127.0.0.1:5432/asterrouter_nightly_e2e?sslmode=disable
ASTER_E2E_ALLOW_DESTRUCTIVE_RESTORE: '1'
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v6
Expand All @@ -96,13 +97,34 @@ jobs:
run: npx playwright install --with-deps chromium firefox webkit
- name: Frontend unit and component tests
working-directory: frontend
run: npx vitest run --reporter=default --reporter=junit --outputFile.junit=test-results/vitest-junit.xml
- name: Full browser suite
run: npx vitest run --reporter=default --reporter=junit --outputFile.junit=unit-test-results/vitest-junit.xml
- name: Check E2E coverage contract
working-directory: frontend
run: npm run check:e2e-coverage
- name: Create isolated nightly first-install database
env:
PGPASSWORD: asterrouter
run: >-
psql --host=127.0.0.1 --username=asterrouter --dbname=postgres
--command='CREATE DATABASE asterrouter_nightly_e2e_setup_test'
- name: Nightly first-install setup browser journey
env:
ASTER_SETUP_JOURNEY_DIR: ${{ runner.temp }}/asterrouter-nightly-setup-journey
ASTER_SETUP_JOURNEY_DATABASE_URL: postgres://asterrouter:asterrouter@127.0.0.1:5432/asterrouter_nightly_e2e_setup_test?sslmode=disable
run: bash scripts/test-setup-browser-journey.sh
- name: Nightly browser gate
working-directory: frontend
env:
ASTER_E2E_ALL_BROWSERS: '1'
ASTER_E2E_RETRIES: '0'
run: npm run test:e2e
ASTER_E2E_OIDC_ENABLED: '1'
run: npm run test:e2e:nightly
- name: System update lifecycle browser journey
env:
ASTER_SYSTEM_UPDATE_E2E_DIR: ${{ runner.temp }}/asterrouter-system-update-lifecycle
run: |
bash scripts/test-system-update-lifecycle.sh
grep -Fxq 'system_update_lifecycle=passed' "${{ runner.temp }}/asterrouter-system-update-lifecycle/report.txt"
- name: Upload browser evidence
if: always()
uses: actions/upload-artifact@v7
Expand All @@ -111,14 +133,32 @@ jobs:
path: |
frontend/playwright-report
frontend/test-results
${{ runner.temp }}/asterrouter-nightly-setup-journey
if-no-files-found: ignore

- name: Upload system update lifecycle evidence
if: always()
uses: actions/upload-artifact@v7
with:
name: nightly-system-update-lifecycle
path: |
${{ runner.temp }}/asterrouter-system-update-lifecycle/report.txt
${{ runner.temp }}/asterrouter-system-update-lifecycle/generations.log
${{ runner.temp }}/asterrouter-system-update-lifecycle/supervisor.log
${{ runner.temp }}/asterrouter-system-update-lifecycle/runtime.log
${{ runner.temp }}/asterrouter-system-update-lifecycle/postgres.log
${{ runner.temp }}/asterrouter-system-update-lifecycle/official.log
${{ runner.temp }}/asterrouter-system-update-lifecycle/playwright
if-no-files-found: ignore

- name: Upload frontend test results
if: always()
uses: actions/upload-artifact@v7
with:
name: nightly-frontend-test-results
path: frontend/test-results
path: |
frontend/test-results
frontend/unit-test-results
if-no-files-found: ignore

test-health:
Expand Down
26 changes: 26 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,14 @@ jobs:
bash scripts/test-release-browser-journeys.sh "${{ steps.meta.outputs.version }}"
grep -Fxq 'release_browser_journeys=passed' "${{ runner.temp }}/asterrouter-release-journeys/report.txt"

- name: Validate system update lifecycle
env:
ASTER_SYSTEM_UPDATE_E2E_DIR: ${{ runner.temp }}/asterrouter-system-update-lifecycle
ASTER_SYSTEM_UPDATE_E2E_OLD_VERSION: ${{ steps.meta.outputs.version }}
run: |
bash scripts/test-system-update-lifecycle.sh
grep -Fxq 'system_update_lifecycle=passed' "${{ runner.temp }}/asterrouter-system-update-lifecycle/report.txt"

- name: Validate Linux install, upgrade, and rollback
env:
ASTER_INSTALLER_TEST_DIR: ${{ runner.temp }}/asterrouter-installer-test
Expand Down Expand Up @@ -150,13 +158,31 @@ jobs:
path: |
${{ runner.temp }}/asterrouter-release-journeys/report.txt
${{ runner.temp }}/asterrouter-release-journeys/fake-upstream.log
${{ runner.temp }}/asterrouter-release-journeys/fake-official.log
${{ runner.temp }}/asterrouter-release-journeys/fake-smtp.log
${{ runner.temp }}/asterrouter-release-journeys/fake-s3.log
${{ runner.temp }}/asterrouter-release-journeys/setup/report.txt
${{ runner.temp }}/asterrouter-release-journeys/setup/runtime.log
${{ runner.temp }}/asterrouter-release-journeys/setup/playwright
${{ runner.temp }}/asterrouter-release-journeys/enterprise/runtime.log
${{ runner.temp }}/asterrouter-release-journeys/enterprise/playwright
if-no-files-found: ignore

- name: Upload system update lifecycle evidence
if: always()
uses: actions/upload-artifact@v7
with:
name: asterrouter-system-update-lifecycle
path: |
${{ runner.temp }}/asterrouter-system-update-lifecycle/report.txt
${{ runner.temp }}/asterrouter-system-update-lifecycle/generations.log
${{ runner.temp }}/asterrouter-system-update-lifecycle/supervisor.log
${{ runner.temp }}/asterrouter-system-update-lifecycle/runtime.log
${{ runner.temp }}/asterrouter-system-update-lifecycle/postgres.log
${{ runner.temp }}/asterrouter-system-update-lifecycle/official.log
${{ runner.temp }}/asterrouter-system-update-lifecycle/playwright
if-no-files-found: ignore

- name: Write release notes
run: |
set -euo pipefail
Expand Down
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
# Changelog

## [0.24.0] - 2026-08-13

### Added

- 建立企业功能、API 操作与浏览器旅程的 E2E 机器事实源,并将覆盖完整性合同纳入 PR、夜间和发布门禁。
- 补齐企业身份、应用与凭据、计价、邮件、网关协议、插件中心、数据导出、系统备份、更新与恢复的端到端旅程。
- 新增合成 OIDC、SMTP、S3 和官方服务测试替身,默认隔离外部依赖与生产数据。
- 新增路由策略算法矩阵,覆盖硬约束、价格护栏、预置排序、批次选择、粘性、熔断、容量和失败切换。

### Changed

- 路由策略执行链统一输出策略 ID、版本、预置和候选排除原因,调度与模拟器共用同一套候选规则。
- 发布工作流增加 PostgreSQL 16、真实 Linux 产物、单源浏览器旅程、系统更新与安装升级回滚验收。
- 官网首屏改为直观的企业路由决策可视化,并完善响应式布局。

### Fixed

- 修复策略模型准入未在实际网关计划阶段阻断,以及原生协议、价格和首字节前切换排除原因不可见的问题。
- 修复路由模拟器与真实调度策略结果不一致,并补齐拒绝原因和容量证据。
- 修复插件工作台兼容路由、模型路由更新请求泄漏服务端字段,以及 OIDC/SMTP 自定义 CA 在隔离测试环境中无法验证的问题。
- 修复告警筛选的过期请求覆盖、插件运行状态浏览器监听竞态,以及隔离 S3 列表响应未使用标准 URL 编码的问题。

## [0.23.1] - 2026-08-12

### Fixed
Expand Down
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,21 @@ cd frontend
npm run build
```

## Testing

The machine-readable browser coverage source is [docs/test/v1/scenario-registry.json](./docs/test/v1/scenario-registry.json). The proof levels, fixtures, delivery gates, and evidence rules are documented in [docs/test/v1/README.md](./docs/test/v1/README.md).

```bash
# Static coverage contract and pull-request browser gate
cd frontend
npm run check:e2e-coverage
npm run test:e2e:pr

# Full local backend, frontend, and browser suite
cd ..
bash scripts/test.sh all
```

## License

AsterRouter is licensed under the [Apache License 2.0](./LICENSE).
15 changes: 15 additions & 0 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,21 @@ cd frontend
npm run build
```

## 测试

浏览器覆盖的机器事实源为 [docs/test/v1/scenario-registry.json](./docs/test/v1/scenario-registry.json)。证明层级、测试夹具、交付门禁和证据规则见 [docs/test/v1/README.md](./docs/test/v1/README.md)。

```bash
# 静态覆盖合同与 PR 浏览器门禁
cd frontend
npm run check:e2e-coverage
npm run test:e2e:pr

# 本地后端、前端与浏览器完整测试
cd ..
bash scripts/test.sh all
```

## 许可证

AsterRouter 使用 [Apache License 2.0](./LICENSE) 授权。
2 changes: 1 addition & 1 deletion backend/cmd/asterrouter/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.23.1
0.24.0
2 changes: 1 addition & 1 deletion backend/internal/appcmd/server/infrastructure_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func TestConfigureAIJobInfrastructureSupportsRedisAffinityWithMemoryQueue(t *tes
}
input := controlplane.GatewayAffinityInput{
ApplicationID: "application", PrincipalID: "principal", CredentialID: "credential", Model: "model",
Protocol: "openai_chat_completions", RouteGroup: "default", PolicyVersion: 1,
Protocol: "openai_chat_completions", RouteGroup: "default", RoutingPolicyVersion: 1,
}
if err = service.BindGatewayCandidateAffinity(t.Context(), input, controlplane.GatewayProvider{ID: "provider-a"}); err != nil {
t.Fatal(err)
Expand Down
Loading
Loading