test(e2e): C7 /v1/rerank + /v1/images/generations forward + model translation - #167

Merged
moonming merged 1 commit into
mainfrom
test/e2e-c7-rerank
May 9, 2026
Merged

test(e2e): C7 /v1/rerank + /v1/images/generations forward + model translation#167
moonming merged 1 commit into
mainfrom
test/e2e-c7-rerank

Conversation

@moonming

@moonmingmoonming commented May 9, 2026

Copy link
Copy Markdown
Member

Summary

Two more endpoints from #151's C7 row, both following the same "verbatim-forward with `model` rewrite" pattern per gateway docs:

  • `/v1/rerank` (docs §4.7): "Cohere-style rerank. Routed to `{base}/v1/rerank`. ... request body is forwarded verbatim after rewriting the `model` field."
  • `/v1/images/generations` (docs §4.9): "OpenAI Images API. Forwarded with the `model` field rewritten."

Prior to this PR the gateway had zero e2e coverage on either endpoint.

What's pinned

EndpointCaller bodyAsserts (caller-side)Asserts (upstream-side)
`/v1/rerank``{model, query, documents, top_n}``id`, 3-item `results` with `index` + `relevance_score` byte-for-byte, `meta` presentpath `/v1/rerank` exactly, `Bearer sk-mock`, `model` rewritten, query + documents + top_n verbatim
`/v1/images/generations``{model, prompt, n, size, response_format}``created` numeric, `data[0].url` + `data[0].revised_prompt` byte-for-bytepath `/v1/images/generations` exactly, `Bearer sk-mock`, `model` rewritten, prompt + n + size + response_format verbatim

Why these matter

  • Score / result corruption for rerank — a regression that mangled relevance_scores or reordered results would silently corrupt RAG ranking quality across every customer using rerank.
  • Image url / revised_prompt drop — those are the only signals callers have about what was generated. A regression that stripped them would leave callers with image-generation calls that "succeed" but provide nothing usable.

Source-blind discipline

Every assertion derives from external contracts:

No internal Rust paths or struct field names referenced.

Independent audit

Per CLAUDE.md §8, an independent audit agent reviewed commit 84bbd8e. Result: 0 HIGH, 0 MEDIUM blockers, 2 LOW informational notes (consistent with merged precedent), 1 MEDIUM-INFO gateway/product gap surfaced for separate tracking — filed as #168 (§4.7/§4.9 over-promise provider matrix; only OpenAI-compat upstreams actually have these routes). Per CLAUDE.md §8, gateway-product gaps are filed separately rather than blocking merge.

Test plan

  • `npm test` (full e2e suite) — 35/35 passing locally (was 33)
  • No mock-data-only paths: each case exercises the real `aisix` binary, real etcd config propagation, real fetch reverse-call against the actual route
  • CI green

Refs #151.

…nslation (#151)
Two more endpoints from #151's C7 row, both following the same
"verbatim-forward with model rewrite" pattern per docs:
- `/v1/rerank` (docs §4.7): "Cohere-style rerank. Routed to
`{base}/v1/rerank`. The Model's provider supplies the API key;
the request body is forwarded verbatim after rewriting the
`model` field."
- `/v1/images/generations` (docs §4.9): "OpenAI Images API.
Forwarded with the `model` field rewritten."
Prior to this PR the gateway had **zero** e2e coverage on either
endpoint. Both are real production surfaces:
- Rerank is the standard relevance-scoring step in modern RAG
pipelines. A regression that mangled scores or reordered
results would silently corrupt RAG ranking quality across
every customer using rerank.
- Image generation (DALL-E / GPT-Image) is increasingly common
in agent-style workflows. A regression that dropped the
image url or revised_prompt fields would leave callers with
no signal about what was generated.
Two cases pinned, one per endpoint:
Rerank: caller POSTs Cohere-shape `{model, query, documents,
top_n}` to /v1/rerank. Asserts:
- Caller-side response: `id`, results array (3 items), each
item's `index` + `relevance_score` byte-for-byte from
upstream, `meta` present
- Upstream-side: hit `/v1/rerank` (NOT chat-completions),
`Bearer sk-mock` auth, `model` rewritten to upstream
model_name, query + documents + top_n forwarded verbatim
Images: caller POSTs OpenAI-shape `{model, prompt, n, size,
response_format}` to /v1/images/generations. Asserts:
- Caller-side response: `created` numeric, `data[0].url` and
`data[0].revised_prompt` byte-for-byte from upstream
- Upstream-side: hit `/v1/images/generations` (NOT another
route), `Bearer sk-mock` auth, `model` rewritten, prompt + n
+ size + response_format forwarded verbatim
References:
- Gateway's own /v1/rerank contract: `docs/api-proxy.md` §4.7
- Gateway's own /v1/images/generations contract: §4.9
- Cohere Rerank API spec:
<https://docs.cohere.com/reference/rerank>
- OpenAI Images API spec:
<https://platform.openai.com/docs/api-reference/images/create>
Refs #151
CopilotAI review requested due to automatic review settings May 9, 2026 14:17
@coderabbitai

coderabbitaiBot commented May 9, 2026

Copy link
Copy Markdown
ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Free

Run ID: 72dbeb67-2ea1-4a1a-a709-20058a25bf8e

📥 Commits

Reviewing files that changed from the base of the PR and between 971d119 and 84bbd8e.

📒 Files selected for processing (2)
  • tests/e2e/src/cases/images-generations-e2e.test.ts
  • tests/e2e/src/cases/rerank-e2e.test.ts

📝 Walkthrough

Walkthrough

This pull request adds two independent end-to-end test suites for the AI gateway. The first tests the /v1/images/generations endpoint for OpenAI-shaped request forwarding and response passthrough. The second tests the /v1/rerank endpoint for Cohere-shaped request forwarding with readiness polling. Both tests verify that the gateway correctly rewrites the model field while forwarding other request fields unchanged, and that responses match the upstream payload exactly.

Changes

Images Generations E2E Test

Layer / File(s)Summary
Test Setup and Imports
tests/e2e/src/cases/images-generations-e2e.test.ts
Imports crypto utilities, Vitest test helpers, and gateway harness utilities for bootstrapping upstream mock and gateway application.
Caller Identity Configuration
tests/e2e/src/cases/images-generations-e2e.test.ts
Defines caller plaintext secret and SHA-256 hash constant for API key authentication.
Test Fixture Lifecycle
tests/e2e/src/cases/images-generations-e2e.test.ts
Test suite hooks initialize etcd dependency, start OpenAI-shaped upstream mock with fixed response, spawn gateway, and configure provider/model/API-key mappings.
End-to-End Assertion
tests/e2e/src/cases/images-generations-e2e.test.ts
Verifies HTTP 200 response matches upstream payload exactly, confirms upstream receives one POST with expected Authorization header, and validates that only model field is rewritten.

Rerank E2E Test

Layer / File(s)Summary
Test Setup and Imports
tests/e2e/src/cases/rerank-e2e.test.ts
Imports crypto utilities, Vitest test helpers, and gateway harness utilities for bootstrapping upstream mock and gateway application.
Caller Identity Configuration
tests/e2e/src/cases/rerank-e2e.test.ts
Defines caller plaintext secret and SHA-256 hash constant for API key authentication.
Test Fixture Lifecycle
tests/e2e/src/cases/rerank-e2e.test.ts
Test suite hooks initialize etcd dependency, start Cohere-shaped upstream rerank mock with fixed response, spawn gateway, and configure provider/model/API-key mappings.
End-to-End Assertion with Readiness Polling
tests/e2e/src/cases/rerank-e2e.test.ts
Polls rerank endpoint until ready, verifies HTTP 200 with exact payload match (id, results ordering, meta), confirms upstream receives one POST with expected Authorization header, and validates that only model field is rewritten while query, documents, and top_n are unchanged.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes


Note

🎁 Summarized by CodeRabbit Free

Your organization has reached its limit of developer seats under the Pro Plan. For new users, CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please add seats to your subscription by visiting https://app.coderabbit.ai/login.If you believe this is a mistake and have available seats, please assign one to the pull request author through the subscription management page using the link above.

Comment @coderabbitai help to get the list of available commands and usage tips.

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds end-to-end (source-blind) regression coverage for two previously uncovered proxy endpoints—/v1/rerank and /v1/images/generations—verifying the gateway’s “verbatim forward with model rewrite” contract and correct upstream dispatch.

Changes:

  • Introduce an e2e test for /v1/rerank that asserts upstream path, upstream auth injection, model translation, and response passthrough.
  • Introduce an e2e test for /v1/images/generations that asserts upstream path, upstream auth injection, model translation, and response passthrough (including url + revised_prompt).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

FileDescription
tests/e2e/src/cases/rerank-e2e.test.tsNew e2e coverage for /v1/rerank forward + model rewrite + strict upstream/response assertions.
tests/e2e/src/cases/images-generations-e2e.test.tsNew e2e coverage for /v1/images/generations forward + model rewrite + strict upstream/response assertions.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@moonming
moonming merged commit 66baab0 into mainMay 9, 2026
14 of 15 checks passed
@moonming
moonming deleted the test/e2e-c7-rerank branch May 9, 2026 14:31
moonming added a commit that referenced this pull request May 9, 2026
Closes#157 (test-infra concern, not a product bug).
Issue: the e2e suite's `guardrail-keyword-e2e.test.ts` has flaked
three times on CI in the past 24 hours (#157 first occurrence,
plus reruns required on PR #165 and #167). Failure mode is the
same: `waitConfigPropagation: condition not met within 5s`.
Root cause: vitest is configured with `maxForks: 4` (per
`vitest.config.ts`), so up to 4 test files run in parallel, each
spawning its own `aisix` binary against a SHARED etcd. Each
binary opens watches and writes resources via the admin API
concurrently with the others. Under that load, etcd watch
dispatch latency for the LAST resource in a multi-resource
batch (e.g. a Guardrail rule following Model + ApiKey +
ProviderKey writes) can exceed the 5s budget.
The 5s budget was sized when the suite had ~9 files. The suite
is now 20+ files (#161, #163, #165, #167 added embeddings,
responses, passthrough, rerank, images). The growth in
parallelism load wasn't matched by a budget bump.
Fix: raise the deadline to 10s. This:
- Eliminates the recurring rerun churn on feature PRs
- Preserves the "fail loudly on a genuinely stuck snapshot"
property — 10s is still a generous floor; a real bug where
propagation hangs indefinitely would still fail clearly
- Doesn't change the happy-path latency at all (the helper
polls every 50ms and returns as soon as the condition is
met — bumping the deadline only affects the sad path)
This is a test-infra-only change; no product behavior is affected.
The ≤500ms spec target for in-process propagation is unchanged;
this is purely the CI test harness's wait budget for slow runners
under concurrent load.
If 10s proves insufficient as the suite grows further, the next
escalation would be to reduce `maxForks` from 4 to 2 (slower wall
time, less etcd pressure) — tracked in #157 as a fallback.
moonming added a commit that referenced this pull request May 9, 2026
… (#169)
* test(harness): raise waitConfigPropagation budget 5s → 10s (#157)
Closes#157 (test-infra concern, not a product bug).
Issue: the e2e suite's `guardrail-keyword-e2e.test.ts` has flaked
three times on CI in the past 24 hours (#157 first occurrence,
plus reruns required on PR #165 and #167). Failure mode is the
same: `waitConfigPropagation: condition not met within 5s`.
Root cause: vitest is configured with `maxForks: 4` (per
`vitest.config.ts`), so up to 4 test files run in parallel, each
spawning its own `aisix` binary against a SHARED etcd. Each
binary opens watches and writes resources via the admin API
concurrently with the others. Under that load, etcd watch
dispatch latency for the LAST resource in a multi-resource
batch (e.g. a Guardrail rule following Model + ApiKey +
ProviderKey writes) can exceed the 5s budget.
The 5s budget was sized when the suite had ~9 files. The suite
is now 20+ files (#161, #163, #165, #167 added embeddings,
responses, passthrough, rerank, images). The growth in
parallelism load wasn't matched by a budget bump.
Fix: raise the deadline to 10s. This:
- Eliminates the recurring rerun churn on feature PRs
- Preserves the "fail loudly on a genuinely stuck snapshot"
property — 10s is still a generous floor; a real bug where
propagation hangs indefinitely would still fail clearly
- Doesn't change the happy-path latency at all (the helper
polls every 50ms and returns as soon as the condition is
met — bumping the deadline only affects the sad path)
This is a test-infra-only change; no product behavior is affected.
The ≤500ms spec target for in-process propagation is unchanged;
this is purely the CI test harness's wait budget for slow runners
under concurrent load.
If 10s proves insufficient as the suite grows further, the next
escalation would be to reduce `maxForks` from 4 to 2 (slower wall
time, less etcd pressure) — tracked in #157 as a fallback.
* test(harness): also reduce maxForks 4→2 (#157 fallback escalation)
After the timeout bump landed, #169's own CI run still flaked with
the same `condition not met within 10s` error — meaning etcd watch
dispatch latency genuinely exceeds 10s under maxForks=4 with the
current suite size (20+ files). The audit on #169 had flagged this
as the "product-side hypothesis still open" — confirmed.
Apply the documented fallback from #157: cut maxForks from 4 to 2.
This halves the concurrent-watcher count against the shared etcd
and brings dispatch latency back inside the budget.
Trade-off: wall time grows ~1.5-2× per CI run (locally measured
~14s @ maxForks=4 vs ~30s @ maxForks=2, so faster than expected
because the extra parallelism wasn't fully utilized anyway —
contention dominated). Net for CI is "predictable green" vs
"fast but constantly-rerunning".
The 10s `waitConfigPropagation` budget from the prior commit stays
in place as belt-and-suspenders — even with maxForks=2 the original
5s would still be tight on slow runners.
Combined this PR now does:
1. waitConfigPropagation deadline 5s → 10s (`harness/admin.ts`)
2. maxForks 4 → 2 (`vitest.config.ts`)
The product-side hypothesis ("etcd watch dispatch degrades
non-linearly with concurrent watchers") is now strongly supported
and worth a separate product-side investigation tracked in #157
follow-up.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@moonming
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

test(e2e): C7 /v1/rerank + /v1/images/generations forward + model translation - #167

Merged
moonming merged 1 commit into
mainfrom
test/e2e-c7-rerank
May 9, 2026
Merged

test(e2e): C7 /v1/rerank + /v1/images/generations forward + model translation#167
moonming merged 1 commit into
mainfrom
test/e2e-c7-rerank

Conversation

@moonming

@moonmingmoonming commented May 9, 2026

Copy link
Copy Markdown
Member

Summary

Two more endpoints from #151's C7 row, both following the same "verbatim-forward with `model` rewrite" pattern per gateway docs:

  • `/v1/rerank` (docs §4.7): "Cohere-style rerank. Routed to `{base}/v1/rerank`. ... request body is forwarded verbatim after rewriting the `model` field."
  • `/v1/images/generations` (docs §4.9): "OpenAI Images API. Forwarded with the `model` field rewritten."

Prior to this PR the gateway had zero e2e coverage on either endpoint.

What's pinned

EndpointCaller bodyAsserts (caller-side)Asserts (upstream-side)
`/v1/rerank``{model, query, documents, top_n}``id`, 3-item `results` with `index` + `relevance_score` byte-for-byte, `meta` presentpath `/v1/rerank` exactly, `Bearer sk-mock`, `model` rewritten, query + documents + top_n verbatim
`/v1/images/generations``{model, prompt, n, size, response_format}``created` numeric, `data[0].url` + `data[0].revised_prompt` byte-for-bytepath `/v1/images/generations` exactly, `Bearer sk-mock`, `model` rewritten, prompt + n + size + response_format verbatim

Why these matter

  • Score / result corruption for rerank — a regression that mangled relevance_scores or reordered results would silently corrupt RAG ranking quality across every customer using rerank.
  • Image url / revised_prompt drop — those are the only signals callers have about what was generated. A regression that stripped them would leave callers with image-generation calls that "succeed" but provide nothing usable.

Source-blind discipline

Every assertion derives from external contracts:

No internal Rust paths or struct field names referenced.

Independent audit

Per CLAUDE.md §8, an independent audit agent reviewed commit 84bbd8e. Result: 0 HIGH, 0 MEDIUM blockers, 2 LOW informational notes (consistent with merged precedent), 1 MEDIUM-INFO gateway/product gap surfaced for separate tracking — filed as #168 (§4.7/§4.9 over-promise provider matrix; only OpenAI-compat upstreams actually have these routes). Per CLAUDE.md §8, gateway-product gaps are filed separately rather than blocking merge.

Test plan

  • `npm test` (full e2e suite) — 35/35 passing locally (was 33)
  • No mock-data-only paths: each case exercises the real `aisix` binary, real etcd config propagation, real fetch reverse-call against the actual route
  • CI green

Refs #151.

…nslation (#151)
Two more endpoints from #151's C7 row, both following the same
"verbatim-forward with model rewrite" pattern per docs:
- `/v1/rerank` (docs §4.7): "Cohere-style rerank. Routed to
`{base}/v1/rerank`. The Model's provider supplies the API key;
the request body is forwarded verbatim after rewriting the
`model` field."
- `/v1/images/generations` (docs §4.9): "OpenAI Images API.
Forwarded with the `model` field rewritten."
Prior to this PR the gateway had **zero** e2e coverage on either
endpoint. Both are real production surfaces:
- Rerank is the standard relevance-scoring step in modern RAG
pipelines. A regression that mangled scores or reordered
results would silently corrupt RAG ranking quality across
every customer using rerank.
- Image generation (DALL-E / GPT-Image) is increasingly common
in agent-style workflows. A regression that dropped the
image url or revised_prompt fields would leave callers with
no signal about what was generated.
Two cases pinned, one per endpoint:
Rerank: caller POSTs Cohere-shape `{model, query, documents,
top_n}` to /v1/rerank. Asserts:
- Caller-side response: `id`, results array (3 items), each
item's `index` + `relevance_score` byte-for-byte from
upstream, `meta` present
- Upstream-side: hit `/v1/rerank` (NOT chat-completions),
`Bearer sk-mock` auth, `model` rewritten to upstream
model_name, query + documents + top_n forwarded verbatim
Images: caller POSTs OpenAI-shape `{model, prompt, n, size,
response_format}` to /v1/images/generations. Asserts:
- Caller-side response: `created` numeric, `data[0].url` and
`data[0].revised_prompt` byte-for-byte from upstream
- Upstream-side: hit `/v1/images/generations` (NOT another
route), `Bearer sk-mock` auth, `model` rewritten, prompt + n
+ size + response_format forwarded verbatim
References:
- Gateway's own /v1/rerank contract: `docs/api-proxy.md` §4.7
- Gateway's own /v1/images/generations contract: §4.9
- Cohere Rerank API spec:
<https://docs.cohere.com/reference/rerank>
- OpenAI Images API spec:
<https://platform.openai.com/docs/api-reference/images/create>
Refs #151
CopilotAI review requested due to automatic review settings May 9, 2026 14:17
@coderabbitai

coderabbitaiBot commented May 9, 2026

Copy link
Copy Markdown
ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Free

Run ID: 72dbeb67-2ea1-4a1a-a709-20058a25bf8e

📥 Commits

Reviewing files that changed from the base of the PR and between 971d119 and 84bbd8e.

📒 Files selected for processing (2)
  • tests/e2e/src/cases/images-generations-e2e.test.ts
  • tests/e2e/src/cases/rerank-e2e.test.ts

📝 Walkthrough

Walkthrough

This pull request adds two independent end-to-end test suites for the AI gateway. The first tests the /v1/images/generations endpoint for OpenAI-shaped request forwarding and response passthrough. The second tests the /v1/rerank endpoint for Cohere-shaped request forwarding with readiness polling. Both tests verify that the gateway correctly rewrites the model field while forwarding other request fields unchanged, and that responses match the upstream payload exactly.

Changes

Images Generations E2E Test

Layer / File(s)Summary
Test Setup and Imports
tests/e2e/src/cases/images-generations-e2e.test.ts
Imports crypto utilities, Vitest test helpers, and gateway harness utilities for bootstrapping upstream mock and gateway application.
Caller Identity Configuration
tests/e2e/src/cases/images-generations-e2e.test.ts
Defines caller plaintext secret and SHA-256 hash constant for API key authentication.
Test Fixture Lifecycle
tests/e2e/src/cases/images-generations-e2e.test.ts
Test suite hooks initialize etcd dependency, start OpenAI-shaped upstream mock with fixed response, spawn gateway, and configure provider/model/API-key mappings.
End-to-End Assertion
tests/e2e/src/cases/images-generations-e2e.test.ts
Verifies HTTP 200 response matches upstream payload exactly, confirms upstream receives one POST with expected Authorization header, and validates that only model field is rewritten.

Rerank E2E Test

Layer / File(s)Summary
Test Setup and Imports
tests/e2e/src/cases/rerank-e2e.test.ts
Imports crypto utilities, Vitest test helpers, and gateway harness utilities for bootstrapping upstream mock and gateway application.
Caller Identity Configuration
tests/e2e/src/cases/rerank-e2e.test.ts
Defines caller plaintext secret and SHA-256 hash constant for API key authentication.
Test Fixture Lifecycle
tests/e2e/src/cases/rerank-e2e.test.ts
Test suite hooks initialize etcd dependency, start Cohere-shaped upstream rerank mock with fixed response, spawn gateway, and configure provider/model/API-key mappings.
End-to-End Assertion with Readiness Polling
tests/e2e/src/cases/rerank-e2e.test.ts
Polls rerank endpoint until ready, verifies HTTP 200 with exact payload match (id, results ordering, meta), confirms upstream receives one POST with expected Authorization header, and validates that only model field is rewritten while query, documents, and top_n are unchanged.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes


Note

🎁 Summarized by CodeRabbit Free

Your organization has reached its limit of developer seats under the Pro Plan. For new users, CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please add seats to your subscription by visiting https://app.coderabbit.ai/login.If you believe this is a mistake and have available seats, please assign one to the pull request author through the subscription management page using the link above.

Comment @coderabbitai help to get the list of available commands and usage tips.

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds end-to-end (source-blind) regression coverage for two previously uncovered proxy endpoints—/v1/rerank and /v1/images/generations—verifying the gateway’s “verbatim forward with model rewrite” contract and correct upstream dispatch.

Changes:

  • Introduce an e2e test for /v1/rerank that asserts upstream path, upstream auth injection, model translation, and response passthrough.
  • Introduce an e2e test for /v1/images/generations that asserts upstream path, upstream auth injection, model translation, and response passthrough (including url + revised_prompt).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

FileDescription
tests/e2e/src/cases/rerank-e2e.test.tsNew e2e coverage for /v1/rerank forward + model rewrite + strict upstream/response assertions.
tests/e2e/src/cases/images-generations-e2e.test.tsNew e2e coverage for /v1/images/generations forward + model rewrite + strict upstream/response assertions.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@moonming
moonming merged commit 66baab0 into mainMay 9, 2026
14 of 15 checks passed
@moonming
moonming deleted the test/e2e-c7-rerank branch May 9, 2026 14:31
moonming added a commit that referenced this pull request May 9, 2026
Closes#157 (test-infra concern, not a product bug).
Issue: the e2e suite's `guardrail-keyword-e2e.test.ts` has flaked
three times on CI in the past 24 hours (#157 first occurrence,
plus reruns required on PR #165 and #167). Failure mode is the
same: `waitConfigPropagation: condition not met within 5s`.
Root cause: vitest is configured with `maxForks: 4` (per
`vitest.config.ts`), so up to 4 test files run in parallel, each
spawning its own `aisix` binary against a SHARED etcd. Each
binary opens watches and writes resources via the admin API
concurrently with the others. Under that load, etcd watch
dispatch latency for the LAST resource in a multi-resource
batch (e.g. a Guardrail rule following Model + ApiKey +
ProviderKey writes) can exceed the 5s budget.
The 5s budget was sized when the suite had ~9 files. The suite
is now 20+ files (#161, #163, #165, #167 added embeddings,
responses, passthrough, rerank, images). The growth in
parallelism load wasn't matched by a budget bump.
Fix: raise the deadline to 10s. This:
- Eliminates the recurring rerun churn on feature PRs
- Preserves the "fail loudly on a genuinely stuck snapshot"
property — 10s is still a generous floor; a real bug where
propagation hangs indefinitely would still fail clearly
- Doesn't change the happy-path latency at all (the helper
polls every 50ms and returns as soon as the condition is
met — bumping the deadline only affects the sad path)
This is a test-infra-only change; no product behavior is affected.
The ≤500ms spec target for in-process propagation is unchanged;
this is purely the CI test harness's wait budget for slow runners
under concurrent load.
If 10s proves insufficient as the suite grows further, the next
escalation would be to reduce `maxForks` from 4 to 2 (slower wall
time, less etcd pressure) — tracked in #157 as a fallback.
moonming added a commit that referenced this pull request May 9, 2026
… (#169)
* test(harness): raise waitConfigPropagation budget 5s → 10s (#157)
Closes#157 (test-infra concern, not a product bug).
Issue: the e2e suite's `guardrail-keyword-e2e.test.ts` has flaked
three times on CI in the past 24 hours (#157 first occurrence,
plus reruns required on PR #165 and #167). Failure mode is the
same: `waitConfigPropagation: condition not met within 5s`.
Root cause: vitest is configured with `maxForks: 4` (per
`vitest.config.ts`), so up to 4 test files run in parallel, each
spawning its own `aisix` binary against a SHARED etcd. Each
binary opens watches and writes resources via the admin API
concurrently with the others. Under that load, etcd watch
dispatch latency for the LAST resource in a multi-resource
batch (e.g. a Guardrail rule following Model + ApiKey +
ProviderKey writes) can exceed the 5s budget.
The 5s budget was sized when the suite had ~9 files. The suite
is now 20+ files (#161, #163, #165, #167 added embeddings,
responses, passthrough, rerank, images). The growth in
parallelism load wasn't matched by a budget bump.
Fix: raise the deadline to 10s. This:
- Eliminates the recurring rerun churn on feature PRs
- Preserves the "fail loudly on a genuinely stuck snapshot"
property — 10s is still a generous floor; a real bug where
propagation hangs indefinitely would still fail clearly
- Doesn't change the happy-path latency at all (the helper
polls every 50ms and returns as soon as the condition is
met — bumping the deadline only affects the sad path)
This is a test-infra-only change; no product behavior is affected.
The ≤500ms spec target for in-process propagation is unchanged;
this is purely the CI test harness's wait budget for slow runners
under concurrent load.
If 10s proves insufficient as the suite grows further, the next
escalation would be to reduce `maxForks` from 4 to 2 (slower wall
time, less etcd pressure) — tracked in #157 as a fallback.
* test(harness): also reduce maxForks 4→2 (#157 fallback escalation)
After the timeout bump landed, #169's own CI run still flaked with
the same `condition not met within 10s` error — meaning etcd watch
dispatch latency genuinely exceeds 10s under maxForks=4 with the
current suite size (20+ files). The audit on #169 had flagged this
as the "product-side hypothesis still open" — confirmed.
Apply the documented fallback from #157: cut maxForks from 4 to 2.
This halves the concurrent-watcher count against the shared etcd
and brings dispatch latency back inside the budget.
Trade-off: wall time grows ~1.5-2× per CI run (locally measured
~14s @ maxForks=4 vs ~30s @ maxForks=2, so faster than expected
because the extra parallelism wasn't fully utilized anyway —
contention dominated). Net for CI is "predictable green" vs
"fast but constantly-rerunning".
The 10s `waitConfigPropagation` budget from the prior commit stays
in place as belt-and-suspenders — even with maxForks=2 the original
5s would still be tight on slow runners.
Combined this PR now does:
1. waitConfigPropagation deadline 5s → 10s (`harness/admin.ts`)
2. maxForks 4 → 2 (`vitest.config.ts`)
The product-side hypothesis ("etcd watch dispatch degrades
non-linearly with concurrent watchers") is now strongly supported
and worth a separate product-side investigation tracked in #157
follow-up.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@moonming
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

test(e2e): C7 /v1/rerank + /v1/images/generations forward + model translation - #167

Merged
moonming merged 1 commit into
mainfrom
test/e2e-c7-rerank
May 9, 2026
Merged

test(e2e): C7 /v1/rerank + /v1/images/generations forward + model translation#167
moonming merged 1 commit into
mainfrom
test/e2e-c7-rerank

Conversation

@moonming

@moonmingmoonming commented May 9, 2026

Copy link
Copy Markdown
Member

Summary

Two more endpoints from #151's C7 row, both following the same "verbatim-forward with `model` rewrite" pattern per gateway docs:

  • `/v1/rerank` (docs §4.7): "Cohere-style rerank. Routed to `{base}/v1/rerank`. ... request body is forwarded verbatim after rewriting the `model` field."
  • `/v1/images/generations` (docs §4.9): "OpenAI Images API. Forwarded with the `model` field rewritten."

Prior to this PR the gateway had zero e2e coverage on either endpoint.

What's pinned

EndpointCaller bodyAsserts (caller-side)Asserts (upstream-side)
`/v1/rerank``{model, query, documents, top_n}``id`, 3-item `results` with `index` + `relevance_score` byte-for-byte, `meta` presentpath `/v1/rerank` exactly, `Bearer sk-mock`, `model` rewritten, query + documents + top_n verbatim
`/v1/images/generations``{model, prompt, n, size, response_format}``created` numeric, `data[0].url` + `data[0].revised_prompt` byte-for-bytepath `/v1/images/generations` exactly, `Bearer sk-mock`, `model` rewritten, prompt + n + size + response_format verbatim

Why these matter

  • Score / result corruption for rerank — a regression that mangled relevance_scores or reordered results would silently corrupt RAG ranking quality across every customer using rerank.
  • Image url / revised_prompt drop — those are the only signals callers have about what was generated. A regression that stripped them would leave callers with image-generation calls that "succeed" but provide nothing usable.

Source-blind discipline

Every assertion derives from external contracts:

No internal Rust paths or struct field names referenced.

Independent audit

Per CLAUDE.md §8, an independent audit agent reviewed commit 84bbd8e. Result: 0 HIGH, 0 MEDIUM blockers, 2 LOW informational notes (consistent with merged precedent), 1 MEDIUM-INFO gateway/product gap surfaced for separate tracking — filed as #168 (§4.7/§4.9 over-promise provider matrix; only OpenAI-compat upstreams actually have these routes). Per CLAUDE.md §8, gateway-product gaps are filed separately rather than blocking merge.

Test plan

  • `npm test` (full e2e suite) — 35/35 passing locally (was 33)
  • No mock-data-only paths: each case exercises the real `aisix` binary, real etcd config propagation, real fetch reverse-call against the actual route
  • CI green

Refs #151.

…nslation (#151)
Two more endpoints from #151's C7 row, both following the same
"verbatim-forward with model rewrite" pattern per docs:
- `/v1/rerank` (docs §4.7): "Cohere-style rerank. Routed to
`{base}/v1/rerank`. The Model's provider supplies the API key;
the request body is forwarded verbatim after rewriting the
`model` field."
- `/v1/images/generations` (docs §4.9): "OpenAI Images API.
Forwarded with the `model` field rewritten."
Prior to this PR the gateway had **zero** e2e coverage on either
endpoint. Both are real production surfaces:
- Rerank is the standard relevance-scoring step in modern RAG
pipelines. A regression that mangled scores or reordered
results would silently corrupt RAG ranking quality across
every customer using rerank.
- Image generation (DALL-E / GPT-Image) is increasingly common
in agent-style workflows. A regression that dropped the
image url or revised_prompt fields would leave callers with
no signal about what was generated.
Two cases pinned, one per endpoint:
Rerank: caller POSTs Cohere-shape `{model, query, documents,
top_n}` to /v1/rerank. Asserts:
- Caller-side response: `id`, results array (3 items), each
item's `index` + `relevance_score` byte-for-byte from
upstream, `meta` present
- Upstream-side: hit `/v1/rerank` (NOT chat-completions),
`Bearer sk-mock` auth, `model` rewritten to upstream
model_name, query + documents + top_n forwarded verbatim
Images: caller POSTs OpenAI-shape `{model, prompt, n, size,
response_format}` to /v1/images/generations. Asserts:
- Caller-side response: `created` numeric, `data[0].url` and
`data[0].revised_prompt` byte-for-byte from upstream
- Upstream-side: hit `/v1/images/generations` (NOT another
route), `Bearer sk-mock` auth, `model` rewritten, prompt + n
+ size + response_format forwarded verbatim
References:
- Gateway's own /v1/rerank contract: `docs/api-proxy.md` §4.7
- Gateway's own /v1/images/generations contract: §4.9
- Cohere Rerank API spec:
<https://docs.cohere.com/reference/rerank>
- OpenAI Images API spec:
<https://platform.openai.com/docs/api-reference/images/create>
Refs #151
CopilotAI review requested due to automatic review settings May 9, 2026 14:17
@coderabbitai

coderabbitaiBot commented May 9, 2026

Copy link
Copy Markdown
ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Free

Run ID: 72dbeb67-2ea1-4a1a-a709-20058a25bf8e

📥 Commits

Reviewing files that changed from the base of the PR and between 971d119 and 84bbd8e.

📒 Files selected for processing (2)
  • tests/e2e/src/cases/images-generations-e2e.test.ts
  • tests/e2e/src/cases/rerank-e2e.test.ts

📝 Walkthrough

Walkthrough

This pull request adds two independent end-to-end test suites for the AI gateway. The first tests the /v1/images/generations endpoint for OpenAI-shaped request forwarding and response passthrough. The second tests the /v1/rerank endpoint for Cohere-shaped request forwarding with readiness polling. Both tests verify that the gateway correctly rewrites the model field while forwarding other request fields unchanged, and that responses match the upstream payload exactly.

Changes

Images Generations E2E Test

Layer / File(s)Summary
Test Setup and Imports
tests/e2e/src/cases/images-generations-e2e.test.ts
Imports crypto utilities, Vitest test helpers, and gateway harness utilities for bootstrapping upstream mock and gateway application.
Caller Identity Configuration
tests/e2e/src/cases/images-generations-e2e.test.ts
Defines caller plaintext secret and SHA-256 hash constant for API key authentication.
Test Fixture Lifecycle
tests/e2e/src/cases/images-generations-e2e.test.ts
Test suite hooks initialize etcd dependency, start OpenAI-shaped upstream mock with fixed response, spawn gateway, and configure provider/model/API-key mappings.
End-to-End Assertion
tests/e2e/src/cases/images-generations-e2e.test.ts
Verifies HTTP 200 response matches upstream payload exactly, confirms upstream receives one POST with expected Authorization header, and validates that only model field is rewritten.

Rerank E2E Test

Layer / File(s)Summary
Test Setup and Imports
tests/e2e/src/cases/rerank-e2e.test.ts
Imports crypto utilities, Vitest test helpers, and gateway harness utilities for bootstrapping upstream mock and gateway application.
Caller Identity Configuration
tests/e2e/src/cases/rerank-e2e.test.ts
Defines caller plaintext secret and SHA-256 hash constant for API key authentication.
Test Fixture Lifecycle
tests/e2e/src/cases/rerank-e2e.test.ts
Test suite hooks initialize etcd dependency, start Cohere-shaped upstream rerank mock with fixed response, spawn gateway, and configure provider/model/API-key mappings.
End-to-End Assertion with Readiness Polling
tests/e2e/src/cases/rerank-e2e.test.ts
Polls rerank endpoint until ready, verifies HTTP 200 with exact payload match (id, results ordering, meta), confirms upstream receives one POST with expected Authorization header, and validates that only model field is rewritten while query, documents, and top_n are unchanged.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes


Note

🎁 Summarized by CodeRabbit Free

Your organization has reached its limit of developer seats under the Pro Plan. For new users, CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please add seats to your subscription by visiting https://app.coderabbit.ai/login.If you believe this is a mistake and have available seats, please assign one to the pull request author through the subscription management page using the link above.

Comment @coderabbitai help to get the list of available commands and usage tips.

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds end-to-end (source-blind) regression coverage for two previously uncovered proxy endpoints—/v1/rerank and /v1/images/generations—verifying the gateway’s “verbatim forward with model rewrite” contract and correct upstream dispatch.

Changes:

  • Introduce an e2e test for /v1/rerank that asserts upstream path, upstream auth injection, model translation, and response passthrough.
  • Introduce an e2e test for /v1/images/generations that asserts upstream path, upstream auth injection, model translation, and response passthrough (including url + revised_prompt).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

FileDescription
tests/e2e/src/cases/rerank-e2e.test.tsNew e2e coverage for /v1/rerank forward + model rewrite + strict upstream/response assertions.
tests/e2e/src/cases/images-generations-e2e.test.tsNew e2e coverage for /v1/images/generations forward + model rewrite + strict upstream/response assertions.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@moonming
moonming merged commit 66baab0 into mainMay 9, 2026
14 of 15 checks passed
@moonming
moonming deleted the test/e2e-c7-rerank branch May 9, 2026 14:31
moonming added a commit that referenced this pull request May 9, 2026
Closes#157 (test-infra concern, not a product bug).
Issue: the e2e suite's `guardrail-keyword-e2e.test.ts` has flaked
three times on CI in the past 24 hours (#157 first occurrence,
plus reruns required on PR #165 and #167). Failure mode is the
same: `waitConfigPropagation: condition not met within 5s`.
Root cause: vitest is configured with `maxForks: 4` (per
`vitest.config.ts`), so up to 4 test files run in parallel, each
spawning its own `aisix` binary against a SHARED etcd. Each
binary opens watches and writes resources via the admin API
concurrently with the others. Under that load, etcd watch
dispatch latency for the LAST resource in a multi-resource
batch (e.g. a Guardrail rule following Model + ApiKey +
ProviderKey writes) can exceed the 5s budget.
The 5s budget was sized when the suite had ~9 files. The suite
is now 20+ files (#161, #163, #165, #167 added embeddings,
responses, passthrough, rerank, images). The growth in
parallelism load wasn't matched by a budget bump.
Fix: raise the deadline to 10s. This:
- Eliminates the recurring rerun churn on feature PRs
- Preserves the "fail loudly on a genuinely stuck snapshot"
property — 10s is still a generous floor; a real bug where
propagation hangs indefinitely would still fail clearly
- Doesn't change the happy-path latency at all (the helper
polls every 50ms and returns as soon as the condition is
met — bumping the deadline only affects the sad path)
This is a test-infra-only change; no product behavior is affected.
The ≤500ms spec target for in-process propagation is unchanged;
this is purely the CI test harness's wait budget for slow runners
under concurrent load.
If 10s proves insufficient as the suite grows further, the next
escalation would be to reduce `maxForks` from 4 to 2 (slower wall
time, less etcd pressure) — tracked in #157 as a fallback.
moonming added a commit that referenced this pull request May 9, 2026
… (#169)
* test(harness): raise waitConfigPropagation budget 5s → 10s (#157)
Closes#157 (test-infra concern, not a product bug).
Issue: the e2e suite's `guardrail-keyword-e2e.test.ts` has flaked
three times on CI in the past 24 hours (#157 first occurrence,
plus reruns required on PR #165 and #167). Failure mode is the
same: `waitConfigPropagation: condition not met within 5s`.
Root cause: vitest is configured with `maxForks: 4` (per
`vitest.config.ts`), so up to 4 test files run in parallel, each
spawning its own `aisix` binary against a SHARED etcd. Each
binary opens watches and writes resources via the admin API
concurrently with the others. Under that load, etcd watch
dispatch latency for the LAST resource in a multi-resource
batch (e.g. a Guardrail rule following Model + ApiKey +
ProviderKey writes) can exceed the 5s budget.
The 5s budget was sized when the suite had ~9 files. The suite
is now 20+ files (#161, #163, #165, #167 added embeddings,
responses, passthrough, rerank, images). The growth in
parallelism load wasn't matched by a budget bump.
Fix: raise the deadline to 10s. This:
- Eliminates the recurring rerun churn on feature PRs
- Preserves the "fail loudly on a genuinely stuck snapshot"
property — 10s is still a generous floor; a real bug where
propagation hangs indefinitely would still fail clearly
- Doesn't change the happy-path latency at all (the helper
polls every 50ms and returns as soon as the condition is
met — bumping the deadline only affects the sad path)
This is a test-infra-only change; no product behavior is affected.
The ≤500ms spec target for in-process propagation is unchanged;
this is purely the CI test harness's wait budget for slow runners
under concurrent load.
If 10s proves insufficient as the suite grows further, the next
escalation would be to reduce `maxForks` from 4 to 2 (slower wall
time, less etcd pressure) — tracked in #157 as a fallback.
* test(harness): also reduce maxForks 4→2 (#157 fallback escalation)
After the timeout bump landed, #169's own CI run still flaked with
the same `condition not met within 10s` error — meaning etcd watch
dispatch latency genuinely exceeds 10s under maxForks=4 with the
current suite size (20+ files). The audit on #169 had flagged this
as the "product-side hypothesis still open" — confirmed.
Apply the documented fallback from #157: cut maxForks from 4 to 2.
This halves the concurrent-watcher count against the shared etcd
and brings dispatch latency back inside the budget.
Trade-off: wall time grows ~1.5-2× per CI run (locally measured
~14s @ maxForks=4 vs ~30s @ maxForks=2, so faster than expected
because the extra parallelism wasn't fully utilized anyway —
contention dominated). Net for CI is "predictable green" vs
"fast but constantly-rerunning".
The 10s `waitConfigPropagation` budget from the prior commit stays
in place as belt-and-suspenders — even with maxForks=2 the original
5s would still be tight on slow runners.
Combined this PR now does:
1. waitConfigPropagation deadline 5s → 10s (`harness/admin.ts`)
2. maxForks 4 → 2 (`vitest.config.ts`)
The product-side hypothesis ("etcd watch dispatch degrades
non-linearly with concurrent watchers") is now strongly supported
and worth a separate product-side investigation tracked in #157
follow-up.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@moonming
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

test(e2e): C7 /v1/rerank + /v1/images/generations forward + model translation - #167

Merged
moonming merged 1 commit into
mainfrom
test/e2e-c7-rerank
May 9, 2026
Merged

test(e2e): C7 /v1/rerank + /v1/images/generations forward + model translation#167
moonming merged 1 commit into
mainfrom
test/e2e-c7-rerank

Conversation

@moonming

@moonmingmoonming commented May 9, 2026

Copy link
Copy Markdown
Member

Summary

Two more endpoints from #151's C7 row, both following the same "verbatim-forward with `model` rewrite" pattern per gateway docs:

  • `/v1/rerank` (docs §4.7): "Cohere-style rerank. Routed to `{base}/v1/rerank`. ... request body is forwarded verbatim after rewriting the `model` field."
  • `/v1/images/generations` (docs §4.9): "OpenAI Images API. Forwarded with the `model` field rewritten."

Prior to this PR the gateway had zero e2e coverage on either endpoint.

What's pinned

EndpointCaller bodyAsserts (caller-side)Asserts (upstream-side)
`/v1/rerank``{model, query, documents, top_n}``id`, 3-item `results` with `index` + `relevance_score` byte-for-byte, `meta` presentpath `/v1/rerank` exactly, `Bearer sk-mock`, `model` rewritten, query + documents + top_n verbatim
`/v1/images/generations``{model, prompt, n, size, response_format}``created` numeric, `data[0].url` + `data[0].revised_prompt` byte-for-bytepath `/v1/images/generations` exactly, `Bearer sk-mock`, `model` rewritten, prompt + n + size + response_format verbatim

Why these matter

  • Score / result corruption for rerank — a regression that mangled relevance_scores or reordered results would silently corrupt RAG ranking quality across every customer using rerank.
  • Image url / revised_prompt drop — those are the only signals callers have about what was generated. A regression that stripped them would leave callers with image-generation calls that "succeed" but provide nothing usable.

Source-blind discipline

Every assertion derives from external contracts:

No internal Rust paths or struct field names referenced.

Independent audit

Per CLAUDE.md §8, an independent audit agent reviewed commit 84bbd8e. Result: 0 HIGH, 0 MEDIUM blockers, 2 LOW informational notes (consistent with merged precedent), 1 MEDIUM-INFO gateway/product gap surfaced for separate tracking — filed as #168 (§4.7/§4.9 over-promise provider matrix; only OpenAI-compat upstreams actually have these routes). Per CLAUDE.md §8, gateway-product gaps are filed separately rather than blocking merge.

Test plan

  • `npm test` (full e2e suite) — 35/35 passing locally (was 33)
  • No mock-data-only paths: each case exercises the real `aisix` binary, real etcd config propagation, real fetch reverse-call against the actual route
  • CI green

Refs #151.

…nslation (#151)
Two more endpoints from #151's C7 row, both following the same
"verbatim-forward with model rewrite" pattern per docs:
- `/v1/rerank` (docs §4.7): "Cohere-style rerank. Routed to
`{base}/v1/rerank`. The Model's provider supplies the API key;
the request body is forwarded verbatim after rewriting the
`model` field."
- `/v1/images/generations` (docs §4.9): "OpenAI Images API.
Forwarded with the `model` field rewritten."
Prior to this PR the gateway had **zero** e2e coverage on either
endpoint. Both are real production surfaces:
- Rerank is the standard relevance-scoring step in modern RAG
pipelines. A regression that mangled scores or reordered
results would silently corrupt RAG ranking quality across
every customer using rerank.
- Image generation (DALL-E / GPT-Image) is increasingly common
in agent-style workflows. A regression that dropped the
image url or revised_prompt fields would leave callers with
no signal about what was generated.
Two cases pinned, one per endpoint:
Rerank: caller POSTs Cohere-shape `{model, query, documents,
top_n}` to /v1/rerank. Asserts:
- Caller-side response: `id`, results array (3 items), each
item's `index` + `relevance_score` byte-for-byte from
upstream, `meta` present
- Upstream-side: hit `/v1/rerank` (NOT chat-completions),
`Bearer sk-mock` auth, `model` rewritten to upstream
model_name, query + documents + top_n forwarded verbatim
Images: caller POSTs OpenAI-shape `{model, prompt, n, size,
response_format}` to /v1/images/generations. Asserts:
- Caller-side response: `created` numeric, `data[0].url` and
`data[0].revised_prompt` byte-for-byte from upstream
- Upstream-side: hit `/v1/images/generations` (NOT another
route), `Bearer sk-mock` auth, `model` rewritten, prompt + n
+ size + response_format forwarded verbatim
References:
- Gateway's own /v1/rerank contract: `docs/api-proxy.md` §4.7
- Gateway's own /v1/images/generations contract: §4.9
- Cohere Rerank API spec:
<https://docs.cohere.com/reference/rerank>
- OpenAI Images API spec:
<https://platform.openai.com/docs/api-reference/images/create>
Refs #151
CopilotAI review requested due to automatic review settings May 9, 2026 14:17
@coderabbitai

coderabbitaiBot commented May 9, 2026

Copy link
Copy Markdown
ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Free

Run ID: 72dbeb67-2ea1-4a1a-a709-20058a25bf8e

📥 Commits

Reviewing files that changed from the base of the PR and between 971d119 and 84bbd8e.

📒 Files selected for processing (2)
  • tests/e2e/src/cases/images-generations-e2e.test.ts
  • tests/e2e/src/cases/rerank-e2e.test.ts

📝 Walkthrough

Walkthrough

This pull request adds two independent end-to-end test suites for the AI gateway. The first tests the /v1/images/generations endpoint for OpenAI-shaped request forwarding and response passthrough. The second tests the /v1/rerank endpoint for Cohere-shaped request forwarding with readiness polling. Both tests verify that the gateway correctly rewrites the model field while forwarding other request fields unchanged, and that responses match the upstream payload exactly.

Changes

Images Generations E2E Test

Layer / File(s)Summary
Test Setup and Imports
tests/e2e/src/cases/images-generations-e2e.test.ts
Imports crypto utilities, Vitest test helpers, and gateway harness utilities for bootstrapping upstream mock and gateway application.
Caller Identity Configuration
tests/e2e/src/cases/images-generations-e2e.test.ts
Defines caller plaintext secret and SHA-256 hash constant for API key authentication.
Test Fixture Lifecycle
tests/e2e/src/cases/images-generations-e2e.test.ts
Test suite hooks initialize etcd dependency, start OpenAI-shaped upstream mock with fixed response, spawn gateway, and configure provider/model/API-key mappings.
End-to-End Assertion
tests/e2e/src/cases/images-generations-e2e.test.ts
Verifies HTTP 200 response matches upstream payload exactly, confirms upstream receives one POST with expected Authorization header, and validates that only model field is rewritten.

Rerank E2E Test

Layer / File(s)Summary
Test Setup and Imports
tests/e2e/src/cases/rerank-e2e.test.ts
Imports crypto utilities, Vitest test helpers, and gateway harness utilities for bootstrapping upstream mock and gateway application.
Caller Identity Configuration
tests/e2e/src/cases/rerank-e2e.test.ts
Defines caller plaintext secret and SHA-256 hash constant for API key authentication.
Test Fixture Lifecycle
tests/e2e/src/cases/rerank-e2e.test.ts
Test suite hooks initialize etcd dependency, start Cohere-shaped upstream rerank mock with fixed response, spawn gateway, and configure provider/model/API-key mappings.
End-to-End Assertion with Readiness Polling
tests/e2e/src/cases/rerank-e2e.test.ts
Polls rerank endpoint until ready, verifies HTTP 200 with exact payload match (id, results ordering, meta), confirms upstream receives one POST with expected Authorization header, and validates that only model field is rewritten while query, documents, and top_n are unchanged.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes


Note

🎁 Summarized by CodeRabbit Free

Your organization has reached its limit of developer seats under the Pro Plan. For new users, CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please add seats to your subscription by visiting https://app.coderabbit.ai/login.If you believe this is a mistake and have available seats, please assign one to the pull request author through the subscription management page using the link above.

Comment @coderabbitai help to get the list of available commands and usage tips.

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds end-to-end (source-blind) regression coverage for two previously uncovered proxy endpoints—/v1/rerank and /v1/images/generations—verifying the gateway’s “verbatim forward with model rewrite” contract and correct upstream dispatch.

Changes:

  • Introduce an e2e test for /v1/rerank that asserts upstream path, upstream auth injection, model translation, and response passthrough.
  • Introduce an e2e test for /v1/images/generations that asserts upstream path, upstream auth injection, model translation, and response passthrough (including url + revised_prompt).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

FileDescription
tests/e2e/src/cases/rerank-e2e.test.tsNew e2e coverage for /v1/rerank forward + model rewrite + strict upstream/response assertions.
tests/e2e/src/cases/images-generations-e2e.test.tsNew e2e coverage for /v1/images/generations forward + model rewrite + strict upstream/response assertions.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@moonming
moonming merged commit 66baab0 into mainMay 9, 2026
14 of 15 checks passed
@moonming
moonming deleted the test/e2e-c7-rerank branch May 9, 2026 14:31
moonming added a commit that referenced this pull request May 9, 2026
Closes#157 (test-infra concern, not a product bug).
Issue: the e2e suite's `guardrail-keyword-e2e.test.ts` has flaked
three times on CI in the past 24 hours (#157 first occurrence,
plus reruns required on PR #165 and #167). Failure mode is the
same: `waitConfigPropagation: condition not met within 5s`.
Root cause: vitest is configured with `maxForks: 4` (per
`vitest.config.ts`), so up to 4 test files run in parallel, each
spawning its own `aisix` binary against a SHARED etcd. Each
binary opens watches and writes resources via the admin API
concurrently with the others. Under that load, etcd watch
dispatch latency for the LAST resource in a multi-resource
batch (e.g. a Guardrail rule following Model + ApiKey +
ProviderKey writes) can exceed the 5s budget.
The 5s budget was sized when the suite had ~9 files. The suite
is now 20+ files (#161, #163, #165, #167 added embeddings,
responses, passthrough, rerank, images). The growth in
parallelism load wasn't matched by a budget bump.
Fix: raise the deadline to 10s. This:
- Eliminates the recurring rerun churn on feature PRs
- Preserves the "fail loudly on a genuinely stuck snapshot"
property — 10s is still a generous floor; a real bug where
propagation hangs indefinitely would still fail clearly
- Doesn't change the happy-path latency at all (the helper
polls every 50ms and returns as soon as the condition is
met — bumping the deadline only affects the sad path)
This is a test-infra-only change; no product behavior is affected.
The ≤500ms spec target for in-process propagation is unchanged;
this is purely the CI test harness's wait budget for slow runners
under concurrent load.
If 10s proves insufficient as the suite grows further, the next
escalation would be to reduce `maxForks` from 4 to 2 (slower wall
time, less etcd pressure) — tracked in #157 as a fallback.
moonming added a commit that referenced this pull request May 9, 2026
… (#169)
* test(harness): raise waitConfigPropagation budget 5s → 10s (#157)
Closes#157 (test-infra concern, not a product bug).
Issue: the e2e suite's `guardrail-keyword-e2e.test.ts` has flaked
three times on CI in the past 24 hours (#157 first occurrence,
plus reruns required on PR #165 and #167). Failure mode is the
same: `waitConfigPropagation: condition not met within 5s`.
Root cause: vitest is configured with `maxForks: 4` (per
`vitest.config.ts`), so up to 4 test files run in parallel, each
spawning its own `aisix` binary against a SHARED etcd. Each
binary opens watches and writes resources via the admin API
concurrently with the others. Under that load, etcd watch
dispatch latency for the LAST resource in a multi-resource
batch (e.g. a Guardrail rule following Model + ApiKey +
ProviderKey writes) can exceed the 5s budget.
The 5s budget was sized when the suite had ~9 files. The suite
is now 20+ files (#161, #163, #165, #167 added embeddings,
responses, passthrough, rerank, images). The growth in
parallelism load wasn't matched by a budget bump.
Fix: raise the deadline to 10s. This:
- Eliminates the recurring rerun churn on feature PRs
- Preserves the "fail loudly on a genuinely stuck snapshot"
property — 10s is still a generous floor; a real bug where
propagation hangs indefinitely would still fail clearly
- Doesn't change the happy-path latency at all (the helper
polls every 50ms and returns as soon as the condition is
met — bumping the deadline only affects the sad path)
This is a test-infra-only change; no product behavior is affected.
The ≤500ms spec target for in-process propagation is unchanged;
this is purely the CI test harness's wait budget for slow runners
under concurrent load.
If 10s proves insufficient as the suite grows further, the next
escalation would be to reduce `maxForks` from 4 to 2 (slower wall
time, less etcd pressure) — tracked in #157 as a fallback.
* test(harness): also reduce maxForks 4→2 (#157 fallback escalation)
After the timeout bump landed, #169's own CI run still flaked with
the same `condition not met within 10s` error — meaning etcd watch
dispatch latency genuinely exceeds 10s under maxForks=4 with the
current suite size (20+ files). The audit on #169 had flagged this
as the "product-side hypothesis still open" — confirmed.
Apply the documented fallback from #157: cut maxForks from 4 to 2.
This halves the concurrent-watcher count against the shared etcd
and brings dispatch latency back inside the budget.
Trade-off: wall time grows ~1.5-2× per CI run (locally measured
~14s @ maxForks=4 vs ~30s @ maxForks=2, so faster than expected
because the extra parallelism wasn't fully utilized anyway —
contention dominated). Net for CI is "predictable green" vs
"fast but constantly-rerunning".
The 10s `waitConfigPropagation` budget from the prior commit stays
in place as belt-and-suspenders — even with maxForks=2 the original
5s would still be tight on slow runners.
Combined this PR now does:
1. waitConfigPropagation deadline 5s → 10s (`harness/admin.ts`)
2. maxForks 4 → 2 (`vitest.config.ts`)
The product-side hypothesis ("etcd watch dispatch degrades
non-linearly with concurrent watchers") is now strongly supported
and worth a separate product-side investigation tracked in #157
follow-up.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@moonming
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

test(e2e): C7 /v1/rerank + /v1/images/generations forward + model translation - #167

Merged
moonming merged 1 commit into
mainfrom
test/e2e-c7-rerank
May 9, 2026
Merged

test(e2e): C7 /v1/rerank + /v1/images/generations forward + model translation#167
moonming merged 1 commit into
mainfrom
test/e2e-c7-rerank

Conversation

@moonming

@moonmingmoonming commented May 9, 2026

Copy link
Copy Markdown
Member

Summary

Two more endpoints from #151's C7 row, both following the same "verbatim-forward with `model` rewrite" pattern per gateway docs:

  • `/v1/rerank` (docs §4.7): "Cohere-style rerank. Routed to `{base}/v1/rerank`. ... request body is forwarded verbatim after rewriting the `model` field."
  • `/v1/images/generations` (docs §4.9): "OpenAI Images API. Forwarded with the `model` field rewritten."

Prior to this PR the gateway had zero e2e coverage on either endpoint.

What's pinned

EndpointCaller bodyAsserts (caller-side)Asserts (upstream-side)
`/v1/rerank``{model, query, documents, top_n}``id`, 3-item `results` with `index` + `relevance_score` byte-for-byte, `meta` presentpath `/v1/rerank` exactly, `Bearer sk-mock`, `model` rewritten, query + documents + top_n verbatim
`/v1/images/generations``{model, prompt, n, size, response_format}``created` numeric, `data[0].url` + `data[0].revised_prompt` byte-for-bytepath `/v1/images/generations` exactly, `Bearer sk-mock`, `model` rewritten, prompt + n + size + response_format verbatim

Why these matter

  • Score / result corruption for rerank — a regression that mangled relevance_scores or reordered results would silently corrupt RAG ranking quality across every customer using rerank.
  • Image url / revised_prompt drop — those are the only signals callers have about what was generated. A regression that stripped them would leave callers with image-generation calls that "succeed" but provide nothing usable.

Source-blind discipline

Every assertion derives from external contracts:

No internal Rust paths or struct field names referenced.

Independent audit

Per CLAUDE.md §8, an independent audit agent reviewed commit 84bbd8e. Result: 0 HIGH, 0 MEDIUM blockers, 2 LOW informational notes (consistent with merged precedent), 1 MEDIUM-INFO gateway/product gap surfaced for separate tracking — filed as #168 (§4.7/§4.9 over-promise provider matrix; only OpenAI-compat upstreams actually have these routes). Per CLAUDE.md §8, gateway-product gaps are filed separately rather than blocking merge.

Test plan

  • `npm test` (full e2e suite) — 35/35 passing locally (was 33)
  • No mock-data-only paths: each case exercises the real `aisix` binary, real etcd config propagation, real fetch reverse-call against the actual route
  • CI green

Refs #151.

…nslation (#151)
Two more endpoints from #151's C7 row, both following the same
"verbatim-forward with model rewrite" pattern per docs:
- `/v1/rerank` (docs §4.7): "Cohere-style rerank. Routed to
`{base}/v1/rerank`. The Model's provider supplies the API key;
the request body is forwarded verbatim after rewriting the
`model` field."
- `/v1/images/generations` (docs §4.9): "OpenAI Images API.
Forwarded with the `model` field rewritten."
Prior to this PR the gateway had **zero** e2e coverage on either
endpoint. Both are real production surfaces:
- Rerank is the standard relevance-scoring step in modern RAG
pipelines. A regression that mangled scores or reordered
results would silently corrupt RAG ranking quality across
every customer using rerank.
- Image generation (DALL-E / GPT-Image) is increasingly common
in agent-style workflows. A regression that dropped the
image url or revised_prompt fields would leave callers with
no signal about what was generated.
Two cases pinned, one per endpoint:
Rerank: caller POSTs Cohere-shape `{model, query, documents,
top_n}` to /v1/rerank. Asserts:
- Caller-side response: `id`, results array (3 items), each
item's `index` + `relevance_score` byte-for-byte from
upstream, `meta` present
- Upstream-side: hit `/v1/rerank` (NOT chat-completions),
`Bearer sk-mock` auth, `model` rewritten to upstream
model_name, query + documents + top_n forwarded verbatim
Images: caller POSTs OpenAI-shape `{model, prompt, n, size,
response_format}` to /v1/images/generations. Asserts:
- Caller-side response: `created` numeric, `data[0].url` and
`data[0].revised_prompt` byte-for-byte from upstream
- Upstream-side: hit `/v1/images/generations` (NOT another
route), `Bearer sk-mock` auth, `model` rewritten, prompt + n
+ size + response_format forwarded verbatim
References:
- Gateway's own /v1/rerank contract: `docs/api-proxy.md` §4.7
- Gateway's own /v1/images/generations contract: §4.9
- Cohere Rerank API spec:
<https://docs.cohere.com/reference/rerank>
- OpenAI Images API spec:
<https://platform.openai.com/docs/api-reference/images/create>
Refs #151
CopilotAI review requested due to automatic review settings May 9, 2026 14:17
@coderabbitai

coderabbitaiBot commented May 9, 2026

Copy link
Copy Markdown
ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Free

Run ID: 72dbeb67-2ea1-4a1a-a709-20058a25bf8e

📥 Commits

Reviewing files that changed from the base of the PR and between 971d119 and 84bbd8e.

📒 Files selected for processing (2)
  • tests/e2e/src/cases/images-generations-e2e.test.ts
  • tests/e2e/src/cases/rerank-e2e.test.ts

📝 Walkthrough

Walkthrough

This pull request adds two independent end-to-end test suites for the AI gateway. The first tests the /v1/images/generations endpoint for OpenAI-shaped request forwarding and response passthrough. The second tests the /v1/rerank endpoint for Cohere-shaped request forwarding with readiness polling. Both tests verify that the gateway correctly rewrites the model field while forwarding other request fields unchanged, and that responses match the upstream payload exactly.

Changes

Images Generations E2E Test

Layer / File(s)Summary
Test Setup and Imports
tests/e2e/src/cases/images-generations-e2e.test.ts
Imports crypto utilities, Vitest test helpers, and gateway harness utilities for bootstrapping upstream mock and gateway application.
Caller Identity Configuration
tests/e2e/src/cases/images-generations-e2e.test.ts
Defines caller plaintext secret and SHA-256 hash constant for API key authentication.
Test Fixture Lifecycle
tests/e2e/src/cases/images-generations-e2e.test.ts
Test suite hooks initialize etcd dependency, start OpenAI-shaped upstream mock with fixed response, spawn gateway, and configure provider/model/API-key mappings.
End-to-End Assertion
tests/e2e/src/cases/images-generations-e2e.test.ts
Verifies HTTP 200 response matches upstream payload exactly, confirms upstream receives one POST with expected Authorization header, and validates that only model field is rewritten.

Rerank E2E Test

Layer / File(s)Summary
Test Setup and Imports
tests/e2e/src/cases/rerank-e2e.test.ts
Imports crypto utilities, Vitest test helpers, and gateway harness utilities for bootstrapping upstream mock and gateway application.
Caller Identity Configuration
tests/e2e/src/cases/rerank-e2e.test.ts
Defines caller plaintext secret and SHA-256 hash constant for API key authentication.
Test Fixture Lifecycle
tests/e2e/src/cases/rerank-e2e.test.ts
Test suite hooks initialize etcd dependency, start Cohere-shaped upstream rerank mock with fixed response, spawn gateway, and configure provider/model/API-key mappings.
End-to-End Assertion with Readiness Polling
tests/e2e/src/cases/rerank-e2e.test.ts
Polls rerank endpoint until ready, verifies HTTP 200 with exact payload match (id, results ordering, meta), confirms upstream receives one POST with expected Authorization header, and validates that only model field is rewritten while query, documents, and top_n are unchanged.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes


Note

🎁 Summarized by CodeRabbit Free

Your organization has reached its limit of developer seats under the Pro Plan. For new users, CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please add seats to your subscription by visiting https://app.coderabbit.ai/login.If you believe this is a mistake and have available seats, please assign one to the pull request author through the subscription management page using the link above.

Comment @coderabbitai help to get the list of available commands and usage tips.

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds end-to-end (source-blind) regression coverage for two previously uncovered proxy endpoints—/v1/rerank and /v1/images/generations—verifying the gateway’s “verbatim forward with model rewrite” contract and correct upstream dispatch.

Changes:

  • Introduce an e2e test for /v1/rerank that asserts upstream path, upstream auth injection, model translation, and response passthrough.
  • Introduce an e2e test for /v1/images/generations that asserts upstream path, upstream auth injection, model translation, and response passthrough (including url + revised_prompt).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

FileDescription
tests/e2e/src/cases/rerank-e2e.test.tsNew e2e coverage for /v1/rerank forward + model rewrite + strict upstream/response assertions.
tests/e2e/src/cases/images-generations-e2e.test.tsNew e2e coverage for /v1/images/generations forward + model rewrite + strict upstream/response assertions.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@moonming
moonming merged commit 66baab0 into mainMay 9, 2026
14 of 15 checks passed
@moonming
moonming deleted the test/e2e-c7-rerank branch May 9, 2026 14:31
moonming added a commit that referenced this pull request May 9, 2026
Closes#157 (test-infra concern, not a product bug).
Issue: the e2e suite's `guardrail-keyword-e2e.test.ts` has flaked
three times on CI in the past 24 hours (#157 first occurrence,
plus reruns required on PR #165 and #167). Failure mode is the
same: `waitConfigPropagation: condition not met within 5s`.
Root cause: vitest is configured with `maxForks: 4` (per
`vitest.config.ts`), so up to 4 test files run in parallel, each
spawning its own `aisix` binary against a SHARED etcd. Each
binary opens watches and writes resources via the admin API
concurrently with the others. Under that load, etcd watch
dispatch latency for the LAST resource in a multi-resource
batch (e.g. a Guardrail rule following Model + ApiKey +
ProviderKey writes) can exceed the 5s budget.
The 5s budget was sized when the suite had ~9 files. The suite
is now 20+ files (#161, #163, #165, #167 added embeddings,
responses, passthrough, rerank, images). The growth in
parallelism load wasn't matched by a budget bump.
Fix: raise the deadline to 10s. This:
- Eliminates the recurring rerun churn on feature PRs
- Preserves the "fail loudly on a genuinely stuck snapshot"
property — 10s is still a generous floor; a real bug where
propagation hangs indefinitely would still fail clearly
- Doesn't change the happy-path latency at all (the helper
polls every 50ms and returns as soon as the condition is
met — bumping the deadline only affects the sad path)
This is a test-infra-only change; no product behavior is affected.
The ≤500ms spec target for in-process propagation is unchanged;
this is purely the CI test harness's wait budget for slow runners
under concurrent load.
If 10s proves insufficient as the suite grows further, the next
escalation would be to reduce `maxForks` from 4 to 2 (slower wall
time, less etcd pressure) — tracked in #157 as a fallback.
moonming added a commit that referenced this pull request May 9, 2026
… (#169)
* test(harness): raise waitConfigPropagation budget 5s → 10s (#157)
Closes#157 (test-infra concern, not a product bug).
Issue: the e2e suite's `guardrail-keyword-e2e.test.ts` has flaked
three times on CI in the past 24 hours (#157 first occurrence,
plus reruns required on PR #165 and #167). Failure mode is the
same: `waitConfigPropagation: condition not met within 5s`.
Root cause: vitest is configured with `maxForks: 4` (per
`vitest.config.ts`), so up to 4 test files run in parallel, each
spawning its own `aisix` binary against a SHARED etcd. Each
binary opens watches and writes resources via the admin API
concurrently with the others. Under that load, etcd watch
dispatch latency for the LAST resource in a multi-resource
batch (e.g. a Guardrail rule following Model + ApiKey +
ProviderKey writes) can exceed the 5s budget.
The 5s budget was sized when the suite had ~9 files. The suite
is now 20+ files (#161, #163, #165, #167 added embeddings,
responses, passthrough, rerank, images). The growth in
parallelism load wasn't matched by a budget bump.
Fix: raise the deadline to 10s. This:
- Eliminates the recurring rerun churn on feature PRs
- Preserves the "fail loudly on a genuinely stuck snapshot"
property — 10s is still a generous floor; a real bug where
propagation hangs indefinitely would still fail clearly
- Doesn't change the happy-path latency at all (the helper
polls every 50ms and returns as soon as the condition is
met — bumping the deadline only affects the sad path)
This is a test-infra-only change; no product behavior is affected.
The ≤500ms spec target for in-process propagation is unchanged;
this is purely the CI test harness's wait budget for slow runners
under concurrent load.
If 10s proves insufficient as the suite grows further, the next
escalation would be to reduce `maxForks` from 4 to 2 (slower wall
time, less etcd pressure) — tracked in #157 as a fallback.
* test(harness): also reduce maxForks 4→2 (#157 fallback escalation)
After the timeout bump landed, #169's own CI run still flaked with
the same `condition not met within 10s` error — meaning etcd watch
dispatch latency genuinely exceeds 10s under maxForks=4 with the
current suite size (20+ files). The audit on #169 had flagged this
as the "product-side hypothesis still open" — confirmed.
Apply the documented fallback from #157: cut maxForks from 4 to 2.
This halves the concurrent-watcher count against the shared etcd
and brings dispatch latency back inside the budget.
Trade-off: wall time grows ~1.5-2× per CI run (locally measured
~14s @ maxForks=4 vs ~30s @ maxForks=2, so faster than expected
because the extra parallelism wasn't fully utilized anyway —
contention dominated). Net for CI is "predictable green" vs
"fast but constantly-rerunning".
The 10s `waitConfigPropagation` budget from the prior commit stays
in place as belt-and-suspenders — even with maxForks=2 the original
5s would still be tight on slow runners.
Combined this PR now does:
1. waitConfigPropagation deadline 5s → 10s (`harness/admin.ts`)
2. maxForks 4 → 2 (`vitest.config.ts`)
The product-side hypothesis ("etcd watch dispatch degrades
non-linearly with concurrent watchers") is now strongly supported
and worth a separate product-side investigation tracked in #157
follow-up.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@moonming
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

test(e2e): C7 /v1/rerank + /v1/images/generations forward + model translation - #167

Merged
moonming merged 1 commit into
mainfrom
test/e2e-c7-rerank
May 9, 2026
Merged

test(e2e): C7 /v1/rerank + /v1/images/generations forward + model translation#167
moonming merged 1 commit into
mainfrom
test/e2e-c7-rerank

Conversation

@moonming

@moonmingmoonming commented May 9, 2026

Copy link
Copy Markdown
Member

Summary

Two more endpoints from #151's C7 row, both following the same "verbatim-forward with `model` rewrite" pattern per gateway docs:

  • `/v1/rerank` (docs §4.7): "Cohere-style rerank. Routed to `{base}/v1/rerank`. ... request body is forwarded verbatim after rewriting the `model` field."
  • `/v1/images/generations` (docs §4.9): "OpenAI Images API. Forwarded with the `model` field rewritten."

Prior to this PR the gateway had zero e2e coverage on either endpoint.

What's pinned

EndpointCaller bodyAsserts (caller-side)Asserts (upstream-side)
`/v1/rerank``{model, query, documents, top_n}``id`, 3-item `results` with `index` + `relevance_score` byte-for-byte, `meta` presentpath `/v1/rerank` exactly, `Bearer sk-mock`, `model` rewritten, query + documents + top_n verbatim
`/v1/images/generations``{model, prompt, n, size, response_format}``created` numeric, `data[0].url` + `data[0].revised_prompt` byte-for-bytepath `/v1/images/generations` exactly, `Bearer sk-mock`, `model` rewritten, prompt + n + size + response_format verbatim

Why these matter

  • Score / result corruption for rerank — a regression that mangled relevance_scores or reordered results would silently corrupt RAG ranking quality across every customer using rerank.
  • Image url / revised_prompt drop — those are the only signals callers have about what was generated. A regression that stripped them would leave callers with image-generation calls that "succeed" but provide nothing usable.

Source-blind discipline

Every assertion derives from external contracts:

No internal Rust paths or struct field names referenced.

Independent audit

Per CLAUDE.md §8, an independent audit agent reviewed commit 84bbd8e. Result: 0 HIGH, 0 MEDIUM blockers, 2 LOW informational notes (consistent with merged precedent), 1 MEDIUM-INFO gateway/product gap surfaced for separate tracking — filed as #168 (§4.7/§4.9 over-promise provider matrix; only OpenAI-compat upstreams actually have these routes). Per CLAUDE.md §8, gateway-product gaps are filed separately rather than blocking merge.

Test plan

  • `npm test` (full e2e suite) — 35/35 passing locally (was 33)
  • No mock-data-only paths: each case exercises the real `aisix` binary, real etcd config propagation, real fetch reverse-call against the actual route
  • CI green

Refs #151.

…nslation (#151)
Two more endpoints from #151's C7 row, both following the same
"verbatim-forward with model rewrite" pattern per docs:
- `/v1/rerank` (docs §4.7): "Cohere-style rerank. Routed to
`{base}/v1/rerank`. The Model's provider supplies the API key;
the request body is forwarded verbatim after rewriting the
`model` field."
- `/v1/images/generations` (docs §4.9): "OpenAI Images API.
Forwarded with the `model` field rewritten."
Prior to this PR the gateway had **zero** e2e coverage on either
endpoint. Both are real production surfaces:
- Rerank is the standard relevance-scoring step in modern RAG
pipelines. A regression that mangled scores or reordered
results would silently corrupt RAG ranking quality across
every customer using rerank.
- Image generation (DALL-E / GPT-Image) is increasingly common
in agent-style workflows. A regression that dropped the
image url or revised_prompt fields would leave callers with
no signal about what was generated.
Two cases pinned, one per endpoint:
Rerank: caller POSTs Cohere-shape `{model, query, documents,
top_n}` to /v1/rerank. Asserts:
- Caller-side response: `id`, results array (3 items), each
item's `index` + `relevance_score` byte-for-byte from
upstream, `meta` present
- Upstream-side: hit `/v1/rerank` (NOT chat-completions),
`Bearer sk-mock` auth, `model` rewritten to upstream
model_name, query + documents + top_n forwarded verbatim
Images: caller POSTs OpenAI-shape `{model, prompt, n, size,
response_format}` to /v1/images/generations. Asserts:
- Caller-side response: `created` numeric, `data[0].url` and
`data[0].revised_prompt` byte-for-byte from upstream
- Upstream-side: hit `/v1/images/generations` (NOT another
route), `Bearer sk-mock` auth, `model` rewritten, prompt + n
+ size + response_format forwarded verbatim
References:
- Gateway's own /v1/rerank contract: `docs/api-proxy.md` §4.7
- Gateway's own /v1/images/generations contract: §4.9
- Cohere Rerank API spec:
<https://docs.cohere.com/reference/rerank>
- OpenAI Images API spec:
<https://platform.openai.com/docs/api-reference/images/create>
Refs #151
CopilotAI review requested due to automatic review settings May 9, 2026 14:17
@coderabbitai

coderabbitaiBot commented May 9, 2026

Copy link
Copy Markdown
ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Free

Run ID: 72dbeb67-2ea1-4a1a-a709-20058a25bf8e

📥 Commits

Reviewing files that changed from the base of the PR and between 971d119 and 84bbd8e.

📒 Files selected for processing (2)
  • tests/e2e/src/cases/images-generations-e2e.test.ts
  • tests/e2e/src/cases/rerank-e2e.test.ts

📝 Walkthrough

Walkthrough

This pull request adds two independent end-to-end test suites for the AI gateway. The first tests the /v1/images/generations endpoint for OpenAI-shaped request forwarding and response passthrough. The second tests the /v1/rerank endpoint for Cohere-shaped request forwarding with readiness polling. Both tests verify that the gateway correctly rewrites the model field while forwarding other request fields unchanged, and that responses match the upstream payload exactly.

Changes

Images Generations E2E Test

Layer / File(s)Summary
Test Setup and Imports
tests/e2e/src/cases/images-generations-e2e.test.ts
Imports crypto utilities, Vitest test helpers, and gateway harness utilities for bootstrapping upstream mock and gateway application.
Caller Identity Configuration
tests/e2e/src/cases/images-generations-e2e.test.ts
Defines caller plaintext secret and SHA-256 hash constant for API key authentication.
Test Fixture Lifecycle
tests/e2e/src/cases/images-generations-e2e.test.ts
Test suite hooks initialize etcd dependency, start OpenAI-shaped upstream mock with fixed response, spawn gateway, and configure provider/model/API-key mappings.
End-to-End Assertion
tests/e2e/src/cases/images-generations-e2e.test.ts
Verifies HTTP 200 response matches upstream payload exactly, confirms upstream receives one POST with expected Authorization header, and validates that only model field is rewritten.

Rerank E2E Test

Layer / File(s)Summary
Test Setup and Imports
tests/e2e/src/cases/rerank-e2e.test.ts
Imports crypto utilities, Vitest test helpers, and gateway harness utilities for bootstrapping upstream mock and gateway application.
Caller Identity Configuration
tests/e2e/src/cases/rerank-e2e.test.ts
Defines caller plaintext secret and SHA-256 hash constant for API key authentication.
Test Fixture Lifecycle
tests/e2e/src/cases/rerank-e2e.test.ts
Test suite hooks initialize etcd dependency, start Cohere-shaped upstream rerank mock with fixed response, spawn gateway, and configure provider/model/API-key mappings.
End-to-End Assertion with Readiness Polling
tests/e2e/src/cases/rerank-e2e.test.ts
Polls rerank endpoint until ready, verifies HTTP 200 with exact payload match (id, results ordering, meta), confirms upstream receives one POST with expected Authorization header, and validates that only model field is rewritten while query, documents, and top_n are unchanged.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes


Note

🎁 Summarized by CodeRabbit Free

Your organization has reached its limit of developer seats under the Pro Plan. For new users, CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please add seats to your subscription by visiting https://app.coderabbit.ai/login.If you believe this is a mistake and have available seats, please assign one to the pull request author through the subscription management page using the link above.

Comment @coderabbitai help to get the list of available commands and usage tips.

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds end-to-end (source-blind) regression coverage for two previously uncovered proxy endpoints—/v1/rerank and /v1/images/generations—verifying the gateway’s “verbatim forward with model rewrite” contract and correct upstream dispatch.

Changes:

  • Introduce an e2e test for /v1/rerank that asserts upstream path, upstream auth injection, model translation, and response passthrough.
  • Introduce an e2e test for /v1/images/generations that asserts upstream path, upstream auth injection, model translation, and response passthrough (including url + revised_prompt).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

FileDescription
tests/e2e/src/cases/rerank-e2e.test.tsNew e2e coverage for /v1/rerank forward + model rewrite + strict upstream/response assertions.
tests/e2e/src/cases/images-generations-e2e.test.tsNew e2e coverage for /v1/images/generations forward + model rewrite + strict upstream/response assertions.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@moonming
moonming merged commit 66baab0 into mainMay 9, 2026
14 of 15 checks passed
@moonming
moonming deleted the test/e2e-c7-rerank branch May 9, 2026 14:31
moonming added a commit that referenced this pull request May 9, 2026
Closes#157 (test-infra concern, not a product bug).
Issue: the e2e suite's `guardrail-keyword-e2e.test.ts` has flaked
three times on CI in the past 24 hours (#157 first occurrence,
plus reruns required on PR #165 and #167). Failure mode is the
same: `waitConfigPropagation: condition not met within 5s`.
Root cause: vitest is configured with `maxForks: 4` (per
`vitest.config.ts`), so up to 4 test files run in parallel, each
spawning its own `aisix` binary against a SHARED etcd. Each
binary opens watches and writes resources via the admin API
concurrently with the others. Under that load, etcd watch
dispatch latency for the LAST resource in a multi-resource
batch (e.g. a Guardrail rule following Model + ApiKey +
ProviderKey writes) can exceed the 5s budget.
The 5s budget was sized when the suite had ~9 files. The suite
is now 20+ files (#161, #163, #165, #167 added embeddings,
responses, passthrough, rerank, images). The growth in
parallelism load wasn't matched by a budget bump.
Fix: raise the deadline to 10s. This:
- Eliminates the recurring rerun churn on feature PRs
- Preserves the "fail loudly on a genuinely stuck snapshot"
property — 10s is still a generous floor; a real bug where
propagation hangs indefinitely would still fail clearly
- Doesn't change the happy-path latency at all (the helper
polls every 50ms and returns as soon as the condition is
met — bumping the deadline only affects the sad path)
This is a test-infra-only change; no product behavior is affected.
The ≤500ms spec target for in-process propagation is unchanged;
this is purely the CI test harness's wait budget for slow runners
under concurrent load.
If 10s proves insufficient as the suite grows further, the next
escalation would be to reduce `maxForks` from 4 to 2 (slower wall
time, less etcd pressure) — tracked in #157 as a fallback.
moonming added a commit that referenced this pull request May 9, 2026
… (#169)
* test(harness): raise waitConfigPropagation budget 5s → 10s (#157)
Closes#157 (test-infra concern, not a product bug).
Issue: the e2e suite's `guardrail-keyword-e2e.test.ts` has flaked
three times on CI in the past 24 hours (#157 first occurrence,
plus reruns required on PR #165 and #167). Failure mode is the
same: `waitConfigPropagation: condition not met within 5s`.
Root cause: vitest is configured with `maxForks: 4` (per
`vitest.config.ts`), so up to 4 test files run in parallel, each
spawning its own `aisix` binary against a SHARED etcd. Each
binary opens watches and writes resources via the admin API
concurrently with the others. Under that load, etcd watch
dispatch latency for the LAST resource in a multi-resource
batch (e.g. a Guardrail rule following Model + ApiKey +
ProviderKey writes) can exceed the 5s budget.
The 5s budget was sized when the suite had ~9 files. The suite
is now 20+ files (#161, #163, #165, #167 added embeddings,
responses, passthrough, rerank, images). The growth in
parallelism load wasn't matched by a budget bump.
Fix: raise the deadline to 10s. This:
- Eliminates the recurring rerun churn on feature PRs
- Preserves the "fail loudly on a genuinely stuck snapshot"
property — 10s is still a generous floor; a real bug where
propagation hangs indefinitely would still fail clearly
- Doesn't change the happy-path latency at all (the helper
polls every 50ms and returns as soon as the condition is
met — bumping the deadline only affects the sad path)
This is a test-infra-only change; no product behavior is affected.
The ≤500ms spec target for in-process propagation is unchanged;
this is purely the CI test harness's wait budget for slow runners
under concurrent load.
If 10s proves insufficient as the suite grows further, the next
escalation would be to reduce `maxForks` from 4 to 2 (slower wall
time, less etcd pressure) — tracked in #157 as a fallback.
* test(harness): also reduce maxForks 4→2 (#157 fallback escalation)
After the timeout bump landed, #169's own CI run still flaked with
the same `condition not met within 10s` error — meaning etcd watch
dispatch latency genuinely exceeds 10s under maxForks=4 with the
current suite size (20+ files). The audit on #169 had flagged this
as the "product-side hypothesis still open" — confirmed.
Apply the documented fallback from #157: cut maxForks from 4 to 2.
This halves the concurrent-watcher count against the shared etcd
and brings dispatch latency back inside the budget.
Trade-off: wall time grows ~1.5-2× per CI run (locally measured
~14s @ maxForks=4 vs ~30s @ maxForks=2, so faster than expected
because the extra parallelism wasn't fully utilized anyway —
contention dominated). Net for CI is "predictable green" vs
"fast but constantly-rerunning".
The 10s `waitConfigPropagation` budget from the prior commit stays
in place as belt-and-suspenders — even with maxForks=2 the original
5s would still be tight on slow runners.
Combined this PR now does:
1. waitConfigPropagation deadline 5s → 10s (`harness/admin.ts`)
2. maxForks 4 → 2 (`vitest.config.ts`)
The product-side hypothesis ("etcd watch dispatch degrades
non-linearly with concurrent watchers") is now strongly supported
and worth a separate product-side investigation tracked in #157
follow-up.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@moonming
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

test(e2e): C7 /v1/rerank + /v1/images/generations forward + model translation - #167

Merged
moonming merged 1 commit into
mainfrom
test/e2e-c7-rerank
May 9, 2026
Merged

test(e2e): C7 /v1/rerank + /v1/images/generations forward + model translation#167
moonming merged 1 commit into
mainfrom
test/e2e-c7-rerank

Conversation

@moonming

@moonmingmoonming commented May 9, 2026

Copy link
Copy Markdown
Member

Summary

Two more endpoints from #151's C7 row, both following the same "verbatim-forward with `model` rewrite" pattern per gateway docs:

  • `/v1/rerank` (docs §4.7): "Cohere-style rerank. Routed to `{base}/v1/rerank`. ... request body is forwarded verbatim after rewriting the `model` field."
  • `/v1/images/generations` (docs §4.9): "OpenAI Images API. Forwarded with the `model` field rewritten."

Prior to this PR the gateway had zero e2e coverage on either endpoint.

What's pinned

EndpointCaller bodyAsserts (caller-side)Asserts (upstream-side)
`/v1/rerank``{model, query, documents, top_n}``id`, 3-item `results` with `index` + `relevance_score` byte-for-byte, `meta` presentpath `/v1/rerank` exactly, `Bearer sk-mock`, `model` rewritten, query + documents + top_n verbatim
`/v1/images/generations``{model, prompt, n, size, response_format}``created` numeric, `data[0].url` + `data[0].revised_prompt` byte-for-bytepath `/v1/images/generations` exactly, `Bearer sk-mock`, `model` rewritten, prompt + n + size + response_format verbatim

Why these matter

  • Score / result corruption for rerank — a regression that mangled relevance_scores or reordered results would silently corrupt RAG ranking quality across every customer using rerank.
  • Image url / revised_prompt drop — those are the only signals callers have about what was generated. A regression that stripped them would leave callers with image-generation calls that "succeed" but provide nothing usable.

Source-blind discipline

Every assertion derives from external contracts:

No internal Rust paths or struct field names referenced.

Independent audit

Per CLAUDE.md §8, an independent audit agent reviewed commit 84bbd8e. Result: 0 HIGH, 0 MEDIUM blockers, 2 LOW informational notes (consistent with merged precedent), 1 MEDIUM-INFO gateway/product gap surfaced for separate tracking — filed as #168 (§4.7/§4.9 over-promise provider matrix; only OpenAI-compat upstreams actually have these routes). Per CLAUDE.md §8, gateway-product gaps are filed separately rather than blocking merge.

Test plan

  • `npm test` (full e2e suite) — 35/35 passing locally (was 33)
  • No mock-data-only paths: each case exercises the real `aisix` binary, real etcd config propagation, real fetch reverse-call against the actual route
  • CI green

Refs #151.

…nslation (#151)
Two more endpoints from #151's C7 row, both following the same
"verbatim-forward with model rewrite" pattern per docs:
- `/v1/rerank` (docs §4.7): "Cohere-style rerank. Routed to
`{base}/v1/rerank`. The Model's provider supplies the API key;
the request body is forwarded verbatim after rewriting the
`model` field."
- `/v1/images/generations` (docs §4.9): "OpenAI Images API.
Forwarded with the `model` field rewritten."
Prior to this PR the gateway had **zero** e2e coverage on either
endpoint. Both are real production surfaces:
- Rerank is the standard relevance-scoring step in modern RAG
pipelines. A regression that mangled scores or reordered
results would silently corrupt RAG ranking quality across
every customer using rerank.
- Image generation (DALL-E / GPT-Image) is increasingly common
in agent-style workflows. A regression that dropped the
image url or revised_prompt fields would leave callers with
no signal about what was generated.
Two cases pinned, one per endpoint:
Rerank: caller POSTs Cohere-shape `{model, query, documents,
top_n}` to /v1/rerank. Asserts:
- Caller-side response: `id`, results array (3 items), each
item's `index` + `relevance_score` byte-for-byte from
upstream, `meta` present
- Upstream-side: hit `/v1/rerank` (NOT chat-completions),
`Bearer sk-mock` auth, `model` rewritten to upstream
model_name, query + documents + top_n forwarded verbatim
Images: caller POSTs OpenAI-shape `{model, prompt, n, size,
response_format}` to /v1/images/generations. Asserts:
- Caller-side response: `created` numeric, `data[0].url` and
`data[0].revised_prompt` byte-for-byte from upstream
- Upstream-side: hit `/v1/images/generations` (NOT another
route), `Bearer sk-mock` auth, `model` rewritten, prompt + n
+ size + response_format forwarded verbatim
References:
- Gateway's own /v1/rerank contract: `docs/api-proxy.md` §4.7
- Gateway's own /v1/images/generations contract: §4.9
- Cohere Rerank API spec:
<https://docs.cohere.com/reference/rerank>
- OpenAI Images API spec:
<https://platform.openai.com/docs/api-reference/images/create>
Refs #151
CopilotAI review requested due to automatic review settings May 9, 2026 14:17
@coderabbitai

coderabbitaiBot commented May 9, 2026

Copy link
Copy Markdown
ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Free

Run ID: 72dbeb67-2ea1-4a1a-a709-20058a25bf8e

📥 Commits

Reviewing files that changed from the base of the PR and between 971d119 and 84bbd8e.

📒 Files selected for processing (2)
  • tests/e2e/src/cases/images-generations-e2e.test.ts
  • tests/e2e/src/cases/rerank-e2e.test.ts

📝 Walkthrough

Walkthrough

This pull request adds two independent end-to-end test suites for the AI gateway. The first tests the /v1/images/generations endpoint for OpenAI-shaped request forwarding and response passthrough. The second tests the /v1/rerank endpoint for Cohere-shaped request forwarding with readiness polling. Both tests verify that the gateway correctly rewrites the model field while forwarding other request fields unchanged, and that responses match the upstream payload exactly.

Changes

Images Generations E2E Test

Layer / File(s)Summary
Test Setup and Imports
tests/e2e/src/cases/images-generations-e2e.test.ts
Imports crypto utilities, Vitest test helpers, and gateway harness utilities for bootstrapping upstream mock and gateway application.
Caller Identity Configuration
tests/e2e/src/cases/images-generations-e2e.test.ts
Defines caller plaintext secret and SHA-256 hash constant for API key authentication.
Test Fixture Lifecycle
tests/e2e/src/cases/images-generations-e2e.test.ts
Test suite hooks initialize etcd dependency, start OpenAI-shaped upstream mock with fixed response, spawn gateway, and configure provider/model/API-key mappings.
End-to-End Assertion
tests/e2e/src/cases/images-generations-e2e.test.ts
Verifies HTTP 200 response matches upstream payload exactly, confirms upstream receives one POST with expected Authorization header, and validates that only model field is rewritten.

Rerank E2E Test

Layer / File(s)Summary
Test Setup and Imports
tests/e2e/src/cases/rerank-e2e.test.ts
Imports crypto utilities, Vitest test helpers, and gateway harness utilities for bootstrapping upstream mock and gateway application.
Caller Identity Configuration
tests/e2e/src/cases/rerank-e2e.test.ts
Defines caller plaintext secret and SHA-256 hash constant for API key authentication.
Test Fixture Lifecycle
tests/e2e/src/cases/rerank-e2e.test.ts
Test suite hooks initialize etcd dependency, start Cohere-shaped upstream rerank mock with fixed response, spawn gateway, and configure provider/model/API-key mappings.
End-to-End Assertion with Readiness Polling
tests/e2e/src/cases/rerank-e2e.test.ts
Polls rerank endpoint until ready, verifies HTTP 200 with exact payload match (id, results ordering, meta), confirms upstream receives one POST with expected Authorization header, and validates that only model field is rewritten while query, documents, and top_n are unchanged.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes


Note

🎁 Summarized by CodeRabbit Free

Your organization has reached its limit of developer seats under the Pro Plan. For new users, CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please add seats to your subscription by visiting https://app.coderabbit.ai/login.If you believe this is a mistake and have available seats, please assign one to the pull request author through the subscription management page using the link above.

Comment @coderabbitai help to get the list of available commands and usage tips.

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds end-to-end (source-blind) regression coverage for two previously uncovered proxy endpoints—/v1/rerank and /v1/images/generations—verifying the gateway’s “verbatim forward with model rewrite” contract and correct upstream dispatch.

Changes:

  • Introduce an e2e test for /v1/rerank that asserts upstream path, upstream auth injection, model translation, and response passthrough.
  • Introduce an e2e test for /v1/images/generations that asserts upstream path, upstream auth injection, model translation, and response passthrough (including url + revised_prompt).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

FileDescription
tests/e2e/src/cases/rerank-e2e.test.tsNew e2e coverage for /v1/rerank forward + model rewrite + strict upstream/response assertions.
tests/e2e/src/cases/images-generations-e2e.test.tsNew e2e coverage for /v1/images/generations forward + model rewrite + strict upstream/response assertions.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@moonming
moonming merged commit 66baab0 into mainMay 9, 2026
14 of 15 checks passed
@moonming
moonming deleted the test/e2e-c7-rerank branch May 9, 2026 14:31
moonming added a commit that referenced this pull request May 9, 2026
Closes#157 (test-infra concern, not a product bug).
Issue: the e2e suite's `guardrail-keyword-e2e.test.ts` has flaked
three times on CI in the past 24 hours (#157 first occurrence,
plus reruns required on PR #165 and #167). Failure mode is the
same: `waitConfigPropagation: condition not met within 5s`.
Root cause: vitest is configured with `maxForks: 4` (per
`vitest.config.ts`), so up to 4 test files run in parallel, each
spawning its own `aisix` binary against a SHARED etcd. Each
binary opens watches and writes resources via the admin API
concurrently with the others. Under that load, etcd watch
dispatch latency for the LAST resource in a multi-resource
batch (e.g. a Guardrail rule following Model + ApiKey +
ProviderKey writes) can exceed the 5s budget.
The 5s budget was sized when the suite had ~9 files. The suite
is now 20+ files (#161, #163, #165, #167 added embeddings,
responses, passthrough, rerank, images). The growth in
parallelism load wasn't matched by a budget bump.
Fix: raise the deadline to 10s. This:
- Eliminates the recurring rerun churn on feature PRs
- Preserves the "fail loudly on a genuinely stuck snapshot"
property — 10s is still a generous floor; a real bug where
propagation hangs indefinitely would still fail clearly
- Doesn't change the happy-path latency at all (the helper
polls every 50ms and returns as soon as the condition is
met — bumping the deadline only affects the sad path)
This is a test-infra-only change; no product behavior is affected.
The ≤500ms spec target for in-process propagation is unchanged;
this is purely the CI test harness's wait budget for slow runners
under concurrent load.
If 10s proves insufficient as the suite grows further, the next
escalation would be to reduce `maxForks` from 4 to 2 (slower wall
time, less etcd pressure) — tracked in #157 as a fallback.
moonming added a commit that referenced this pull request May 9, 2026
… (#169)
* test(harness): raise waitConfigPropagation budget 5s → 10s (#157)
Closes#157 (test-infra concern, not a product bug).
Issue: the e2e suite's `guardrail-keyword-e2e.test.ts` has flaked
three times on CI in the past 24 hours (#157 first occurrence,
plus reruns required on PR #165 and #167). Failure mode is the
same: `waitConfigPropagation: condition not met within 5s`.
Root cause: vitest is configured with `maxForks: 4` (per
`vitest.config.ts`), so up to 4 test files run in parallel, each
spawning its own `aisix` binary against a SHARED etcd. Each
binary opens watches and writes resources via the admin API
concurrently with the others. Under that load, etcd watch
dispatch latency for the LAST resource in a multi-resource
batch (e.g. a Guardrail rule following Model + ApiKey +
ProviderKey writes) can exceed the 5s budget.
The 5s budget was sized when the suite had ~9 files. The suite
is now 20+ files (#161, #163, #165, #167 added embeddings,
responses, passthrough, rerank, images). The growth in
parallelism load wasn't matched by a budget bump.
Fix: raise the deadline to 10s. This:
- Eliminates the recurring rerun churn on feature PRs
- Preserves the "fail loudly on a genuinely stuck snapshot"
property — 10s is still a generous floor; a real bug where
propagation hangs indefinitely would still fail clearly
- Doesn't change the happy-path latency at all (the helper
polls every 50ms and returns as soon as the condition is
met — bumping the deadline only affects the sad path)
This is a test-infra-only change; no product behavior is affected.
The ≤500ms spec target for in-process propagation is unchanged;
this is purely the CI test harness's wait budget for slow runners
under concurrent load.
If 10s proves insufficient as the suite grows further, the next
escalation would be to reduce `maxForks` from 4 to 2 (slower wall
time, less etcd pressure) — tracked in #157 as a fallback.
* test(harness): also reduce maxForks 4→2 (#157 fallback escalation)
After the timeout bump landed, #169's own CI run still flaked with
the same `condition not met within 10s` error — meaning etcd watch
dispatch latency genuinely exceeds 10s under maxForks=4 with the
current suite size (20+ files). The audit on #169 had flagged this
as the "product-side hypothesis still open" — confirmed.
Apply the documented fallback from #157: cut maxForks from 4 to 2.
This halves the concurrent-watcher count against the shared etcd
and brings dispatch latency back inside the budget.
Trade-off: wall time grows ~1.5-2× per CI run (locally measured
~14s @ maxForks=4 vs ~30s @ maxForks=2, so faster than expected
because the extra parallelism wasn't fully utilized anyway —
contention dominated). Net for CI is "predictable green" vs
"fast but constantly-rerunning".
The 10s `waitConfigPropagation` budget from the prior commit stays
in place as belt-and-suspenders — even with maxForks=2 the original
5s would still be tight on slow runners.
Combined this PR now does:
1. waitConfigPropagation deadline 5s → 10s (`harness/admin.ts`)
2. maxForks 4 → 2 (`vitest.config.ts`)
The product-side hypothesis ("etcd watch dispatch degrades
non-linearly with concurrent watchers") is now strongly supported
and worth a separate product-side investigation tracked in #157
follow-up.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@moonming
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

test(e2e): C7 /v1/rerank + /v1/images/generations forward + model translation - #167

Merged
moonming merged 1 commit into
mainfrom
test/e2e-c7-rerank
May 9, 2026
Merged

test(e2e): C7 /v1/rerank + /v1/images/generations forward + model translation#167
moonming merged 1 commit into
mainfrom
test/e2e-c7-rerank

Conversation

@moonming

@moonmingmoonming commented May 9, 2026

Copy link
Copy Markdown
Member

Summary

Two more endpoints from #151's C7 row, both following the same "verbatim-forward with `model` rewrite" pattern per gateway docs:

  • `/v1/rerank` (docs §4.7): "Cohere-style rerank. Routed to `{base}/v1/rerank`. ... request body is forwarded verbatim after rewriting the `model` field."
  • `/v1/images/generations` (docs §4.9): "OpenAI Images API. Forwarded with the `model` field rewritten."

Prior to this PR the gateway had zero e2e coverage on either endpoint.

What's pinned

EndpointCaller bodyAsserts (caller-side)Asserts (upstream-side)
`/v1/rerank``{model, query, documents, top_n}``id`, 3-item `results` with `index` + `relevance_score` byte-for-byte, `meta` presentpath `/v1/rerank` exactly, `Bearer sk-mock`, `model` rewritten, query + documents + top_n verbatim
`/v1/images/generations``{model, prompt, n, size, response_format}``created` numeric, `data[0].url` + `data[0].revised_prompt` byte-for-bytepath `/v1/images/generations` exactly, `Bearer sk-mock`, `model` rewritten, prompt + n + size + response_format verbatim

Why these matter

  • Score / result corruption for rerank — a regression that mangled relevance_scores or reordered results would silently corrupt RAG ranking quality across every customer using rerank.
  • Image url / revised_prompt drop — those are the only signals callers have about what was generated. A regression that stripped them would leave callers with image-generation calls that "succeed" but provide nothing usable.

Source-blind discipline

Every assertion derives from external contracts:

No internal Rust paths or struct field names referenced.

Independent audit

Per CLAUDE.md §8, an independent audit agent reviewed commit 84bbd8e. Result: 0 HIGH, 0 MEDIUM blockers, 2 LOW informational notes (consistent with merged precedent), 1 MEDIUM-INFO gateway/product gap surfaced for separate tracking — filed as #168 (§4.7/§4.9 over-promise provider matrix; only OpenAI-compat upstreams actually have these routes). Per CLAUDE.md §8, gateway-product gaps are filed separately rather than blocking merge.

Test plan

  • `npm test` (full e2e suite) — 35/35 passing locally (was 33)
  • No mock-data-only paths: each case exercises the real `aisix` binary, real etcd config propagation, real fetch reverse-call against the actual route
  • CI green

Refs #151.

…nslation (#151)
Two more endpoints from #151's C7 row, both following the same
"verbatim-forward with model rewrite" pattern per docs:
- `/v1/rerank` (docs §4.7): "Cohere-style rerank. Routed to
`{base}/v1/rerank`. The Model's provider supplies the API key;
the request body is forwarded verbatim after rewriting the
`model` field."
- `/v1/images/generations` (docs §4.9): "OpenAI Images API.
Forwarded with the `model` field rewritten."
Prior to this PR the gateway had **zero** e2e coverage on either
endpoint. Both are real production surfaces:
- Rerank is the standard relevance-scoring step in modern RAG
pipelines. A regression that mangled scores or reordered
results would silently corrupt RAG ranking quality across
every customer using rerank.
- Image generation (DALL-E / GPT-Image) is increasingly common
in agent-style workflows. A regression that dropped the
image url or revised_prompt fields would leave callers with
no signal about what was generated.
Two cases pinned, one per endpoint:
Rerank: caller POSTs Cohere-shape `{model, query, documents,
top_n}` to /v1/rerank. Asserts:
- Caller-side response: `id`, results array (3 items), each
item's `index` + `relevance_score` byte-for-byte from
upstream, `meta` present
- Upstream-side: hit `/v1/rerank` (NOT chat-completions),
`Bearer sk-mock` auth, `model` rewritten to upstream
model_name, query + documents + top_n forwarded verbatim
Images: caller POSTs OpenAI-shape `{model, prompt, n, size,
response_format}` to /v1/images/generations. Asserts:
- Caller-side response: `created` numeric, `data[0].url` and
`data[0].revised_prompt` byte-for-byte from upstream
- Upstream-side: hit `/v1/images/generations` (NOT another
route), `Bearer sk-mock` auth, `model` rewritten, prompt + n
+ size + response_format forwarded verbatim
References:
- Gateway's own /v1/rerank contract: `docs/api-proxy.md` §4.7
- Gateway's own /v1/images/generations contract: §4.9
- Cohere Rerank API spec:
<https://docs.cohere.com/reference/rerank>
- OpenAI Images API spec:
<https://platform.openai.com/docs/api-reference/images/create>
Refs #151
CopilotAI review requested due to automatic review settings May 9, 2026 14:17
@coderabbitai

coderabbitaiBot commented May 9, 2026

Copy link
Copy Markdown
ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Free

Run ID: 72dbeb67-2ea1-4a1a-a709-20058a25bf8e

📥 Commits

Reviewing files that changed from the base of the PR and between 971d119 and 84bbd8e.

📒 Files selected for processing (2)
  • tests/e2e/src/cases/images-generations-e2e.test.ts
  • tests/e2e/src/cases/rerank-e2e.test.ts

📝 Walkthrough

Walkthrough

This pull request adds two independent end-to-end test suites for the AI gateway. The first tests the /v1/images/generations endpoint for OpenAI-shaped request forwarding and response passthrough. The second tests the /v1/rerank endpoint for Cohere-shaped request forwarding with readiness polling. Both tests verify that the gateway correctly rewrites the model field while forwarding other request fields unchanged, and that responses match the upstream payload exactly.

Changes

Images Generations E2E Test

Layer / File(s)Summary
Test Setup and Imports
tests/e2e/src/cases/images-generations-e2e.test.ts
Imports crypto utilities, Vitest test helpers, and gateway harness utilities for bootstrapping upstream mock and gateway application.
Caller Identity Configuration
tests/e2e/src/cases/images-generations-e2e.test.ts
Defines caller plaintext secret and SHA-256 hash constant for API key authentication.
Test Fixture Lifecycle
tests/e2e/src/cases/images-generations-e2e.test.ts
Test suite hooks initialize etcd dependency, start OpenAI-shaped upstream mock with fixed response, spawn gateway, and configure provider/model/API-key mappings.
End-to-End Assertion
tests/e2e/src/cases/images-generations-e2e.test.ts
Verifies HTTP 200 response matches upstream payload exactly, confirms upstream receives one POST with expected Authorization header, and validates that only model field is rewritten.

Rerank E2E Test

Layer / File(s)Summary
Test Setup and Imports
tests/e2e/src/cases/rerank-e2e.test.ts
Imports crypto utilities, Vitest test helpers, and gateway harness utilities for bootstrapping upstream mock and gateway application.
Caller Identity Configuration
tests/e2e/src/cases/rerank-e2e.test.ts
Defines caller plaintext secret and SHA-256 hash constant for API key authentication.
Test Fixture Lifecycle
tests/e2e/src/cases/rerank-e2e.test.ts
Test suite hooks initialize etcd dependency, start Cohere-shaped upstream rerank mock with fixed response, spawn gateway, and configure provider/model/API-key mappings.
End-to-End Assertion with Readiness Polling
tests/e2e/src/cases/rerank-e2e.test.ts
Polls rerank endpoint until ready, verifies HTTP 200 with exact payload match (id, results ordering, meta), confirms upstream receives one POST with expected Authorization header, and validates that only model field is rewritten while query, documents, and top_n are unchanged.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes


Note

🎁 Summarized by CodeRabbit Free

Your organization has reached its limit of developer seats under the Pro Plan. For new users, CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please add seats to your subscription by visiting https://app.coderabbit.ai/login.If you believe this is a mistake and have available seats, please assign one to the pull request author through the subscription management page using the link above.

Comment @coderabbitai help to get the list of available commands and usage tips.

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds end-to-end (source-blind) regression coverage for two previously uncovered proxy endpoints—/v1/rerank and /v1/images/generations—verifying the gateway’s “verbatim forward with model rewrite” contract and correct upstream dispatch.

Changes:

  • Introduce an e2e test for /v1/rerank that asserts upstream path, upstream auth injection, model translation, and response passthrough.
  • Introduce an e2e test for /v1/images/generations that asserts upstream path, upstream auth injection, model translation, and response passthrough (including url + revised_prompt).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

FileDescription
tests/e2e/src/cases/rerank-e2e.test.tsNew e2e coverage for /v1/rerank forward + model rewrite + strict upstream/response assertions.
tests/e2e/src/cases/images-generations-e2e.test.tsNew e2e coverage for /v1/images/generations forward + model rewrite + strict upstream/response assertions.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@moonming
moonming merged commit 66baab0 into mainMay 9, 2026
14 of 15 checks passed
@moonming
moonming deleted the test/e2e-c7-rerank branch May 9, 2026 14:31
moonming added a commit that referenced this pull request May 9, 2026
Closes#157 (test-infra concern, not a product bug).
Issue: the e2e suite's `guardrail-keyword-e2e.test.ts` has flaked
three times on CI in the past 24 hours (#157 first occurrence,
plus reruns required on PR #165 and #167). Failure mode is the
same: `waitConfigPropagation: condition not met within 5s`.
Root cause: vitest is configured with `maxForks: 4` (per
`vitest.config.ts`), so up to 4 test files run in parallel, each
spawning its own `aisix` binary against a SHARED etcd. Each
binary opens watches and writes resources via the admin API
concurrently with the others. Under that load, etcd watch
dispatch latency for the LAST resource in a multi-resource
batch (e.g. a Guardrail rule following Model + ApiKey +
ProviderKey writes) can exceed the 5s budget.
The 5s budget was sized when the suite had ~9 files. The suite
is now 20+ files (#161, #163, #165, #167 added embeddings,
responses, passthrough, rerank, images). The growth in
parallelism load wasn't matched by a budget bump.
Fix: raise the deadline to 10s. This:
- Eliminates the recurring rerun churn on feature PRs
- Preserves the "fail loudly on a genuinely stuck snapshot"
property — 10s is still a generous floor; a real bug where
propagation hangs indefinitely would still fail clearly
- Doesn't change the happy-path latency at all (the helper
polls every 50ms and returns as soon as the condition is
met — bumping the deadline only affects the sad path)
This is a test-infra-only change; no product behavior is affected.
The ≤500ms spec target for in-process propagation is unchanged;
this is purely the CI test harness's wait budget for slow runners
under concurrent load.
If 10s proves insufficient as the suite grows further, the next
escalation would be to reduce `maxForks` from 4 to 2 (slower wall
time, less etcd pressure) — tracked in #157 as a fallback.
moonming added a commit that referenced this pull request May 9, 2026
… (#169)
* test(harness): raise waitConfigPropagation budget 5s → 10s (#157)
Closes#157 (test-infra concern, not a product bug).
Issue: the e2e suite's `guardrail-keyword-e2e.test.ts` has flaked
three times on CI in the past 24 hours (#157 first occurrence,
plus reruns required on PR #165 and #167). Failure mode is the
same: `waitConfigPropagation: condition not met within 5s`.
Root cause: vitest is configured with `maxForks: 4` (per
`vitest.config.ts`), so up to 4 test files run in parallel, each
spawning its own `aisix` binary against a SHARED etcd. Each
binary opens watches and writes resources via the admin API
concurrently with the others. Under that load, etcd watch
dispatch latency for the LAST resource in a multi-resource
batch (e.g. a Guardrail rule following Model + ApiKey +
ProviderKey writes) can exceed the 5s budget.
The 5s budget was sized when the suite had ~9 files. The suite
is now 20+ files (#161, #163, #165, #167 added embeddings,
responses, passthrough, rerank, images). The growth in
parallelism load wasn't matched by a budget bump.
Fix: raise the deadline to 10s. This:
- Eliminates the recurring rerun churn on feature PRs
- Preserves the "fail loudly on a genuinely stuck snapshot"
property — 10s is still a generous floor; a real bug where
propagation hangs indefinitely would still fail clearly
- Doesn't change the happy-path latency at all (the helper
polls every 50ms and returns as soon as the condition is
met — bumping the deadline only affects the sad path)
This is a test-infra-only change; no product behavior is affected.
The ≤500ms spec target for in-process propagation is unchanged;
this is purely the CI test harness's wait budget for slow runners
under concurrent load.
If 10s proves insufficient as the suite grows further, the next
escalation would be to reduce `maxForks` from 4 to 2 (slower wall
time, less etcd pressure) — tracked in #157 as a fallback.
* test(harness): also reduce maxForks 4→2 (#157 fallback escalation)
After the timeout bump landed, #169's own CI run still flaked with
the same `condition not met within 10s` error — meaning etcd watch
dispatch latency genuinely exceeds 10s under maxForks=4 with the
current suite size (20+ files). The audit on #169 had flagged this
as the "product-side hypothesis still open" — confirmed.
Apply the documented fallback from #157: cut maxForks from 4 to 2.
This halves the concurrent-watcher count against the shared etcd
and brings dispatch latency back inside the budget.
Trade-off: wall time grows ~1.5-2× per CI run (locally measured
~14s @ maxForks=4 vs ~30s @ maxForks=2, so faster than expected
because the extra parallelism wasn't fully utilized anyway —
contention dominated). Net for CI is "predictable green" vs
"fast but constantly-rerunning".
The 10s `waitConfigPropagation` budget from the prior commit stays
in place as belt-and-suspenders — even with maxForks=2 the original
5s would still be tight on slow runners.
Combined this PR now does:
1. waitConfigPropagation deadline 5s → 10s (`harness/admin.ts`)
2. maxForks 4 → 2 (`vitest.config.ts`)
The product-side hypothesis ("etcd watch dispatch degrades
non-linearly with concurrent watchers") is now strongly supported
and worth a separate product-side investigation tracked in #157
follow-up.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@moonming