Simplify single-backend HttpApi exerciser (#26906)

This commit is contained in:
Kit Langton
2026-05-11 13:22:31 -04:00
committed by GitHub
parent 6f2f759fbb
commit c7e084c32c
3 changed files with 19 additions and 29 deletions
@@ -2,7 +2,7 @@ import { ConfigProvider, Effect, Layer } from "effect"
import { HttpRouter } from "effect/unstable/http" import { HttpRouter } from "effect/unstable/http"
import { parse } from "./assertions" import { parse } from "./assertions"
import { runtime, type Runtime } from "./runtime" import { runtime, type Runtime } from "./runtime"
import type { ActiveScenario, Backend, BackendApp, CallResult, CaptureMode, SeededContext } from "./types" import type { ActiveScenario, BackendApp, CallResult, CaptureMode, SeededContext } from "./types"
type CallOptions = { type CallOptions = {
auth?: { auth?: {
@@ -11,27 +11,18 @@ type CallOptions = {
} }
} }
export function call( export function call(scenario: ActiveScenario, ctx: SeededContext<unknown>, options: CallOptions = {}) {
backend: Backend,
scenario: ActiveScenario,
ctx: SeededContext<unknown>,
options: CallOptions = {},
) {
return Effect.promise(async () => return Effect.promise(async () =>
capture(await app(await runtime(), backend, options).request(toRequest(scenario, ctx)), scenario.capture), capture(await app(await runtime(), options).request(toRequest(scenario, ctx)), scenario.capture),
) )
} }
export function callAuthProbe( export function callAuthProbe(scenario: ActiveScenario, credentials: "missing" | "valid" = "missing") {
backend: Backend,
scenario: ActiveScenario,
credentials: "missing" | "valid" = "missing",
) {
return Effect.promise(async () => { return Effect.promise(async () => {
const controller = new AbortController() const controller = new AbortController()
return Promise.race([ return Promise.race([
Promise.resolve( Promise.resolve(
app(await runtime(), backend, { auth: { password: "secret" } }).request( app(await runtime(), { auth: { password: "secret" } }).request(
toAuthProbeRequest(scenario, credentials, controller.signal), toAuthProbeRequest(scenario, credentials, controller.signal),
), ),
).then((response) => capture(response, scenario.capture)), ).then((response) => capture(response, scenario.capture)),
@@ -51,10 +42,10 @@ export function callAuthProbe(
const appCache: Partial<Record<string, BackendApp>> = {} const appCache: Partial<Record<string, BackendApp>> = {}
function app(modules: Runtime, backend: Backend, options: CallOptions) { function app(modules: Runtime, options: CallOptions) {
const username = options.auth?.username const username = options.auth?.username
const password = options.auth?.password const password = options.auth?.password
const cacheKey = `${backend}:${username ?? ""}:${password ?? ""}` const cacheKey = `${username ?? ""}:${password ?? ""}`
if (appCache[cacheKey]) return appCache[cacheKey] if (appCache[cacheKey]) return appCache[cacheKey]
const handler = HttpRouter.toWebHandler( const handler = HttpRouter.toWebHandler(
@@ -30,28 +30,28 @@ function runActive(options: Options, scenario: ActiveScenario) {
return withContext(options, scenario, "shared", (ctx) => return withContext(options, scenario, "shared", (ctx) =>
Effect.gen(function* () { Effect.gen(function* () {
yield* trace(options, scenario, "effect request start") yield* trace(options, scenario, "request start")
const effect = yield* call("effect", scenario, ctx) const result = yield* call(scenario, ctx)
yield* trace(options, scenario, `effect response ${effect.status}`) yield* trace(options, scenario, `response ${result.status}`)
yield* trace(options, scenario, "effect expect start") yield* trace(options, scenario, "expect start")
yield* scenario.expect(ctx, ctx.state, effect) yield* scenario.expect(ctx, ctx.state, result)
yield* trace(options, scenario, "effect expect done") yield* trace(options, scenario, "expect done")
}), }),
) )
} }
function runAuth(scenario: ActiveScenario) { function runAuth(scenario: ActiveScenario) {
return Effect.gen(function* () { return Effect.gen(function* () {
const effect = yield* callAuthProbe("effect", scenario, "missing") const result = yield* callAuthProbe(scenario, "missing")
if (scenario.auth === "protected") { if (scenario.auth === "protected") {
if (effect.status !== 401) throw new Error(`effect auth expected 401, got ${effect.status}`) if (result.status !== 401) throw new Error(`auth expected 401, got ${result.status}`)
const effectAuthed = yield* callAuthProbe("effect", scenario, "valid") const authed = yield* callAuthProbe(scenario, "valid")
if (effectAuthed.status === 401) throw new Error("effect auth rejected valid credentials") if (authed.status === 401) throw new Error("auth rejected valid credentials")
return return
} }
if (effect.status === 401) throw new Error("effect auth expected public access, got 401") if (result.status === 401) throw new Error("auth expected public access, got 401")
if (effect.timedOut) throw new Error("effect auth expected public access, probe timed out") if (result.timedOut) throw new Error("auth expected public access, probe timed out")
}) })
} }
@@ -11,7 +11,6 @@ export const Methods = ["GET", "POST", "PUT", "DELETE", "PATCH"] as const
export type Method = (typeof Methods)[number] export type Method = (typeof Methods)[number]
export type OpenApiMethod = (typeof OpenApiMethods)[number] export type OpenApiMethod = (typeof OpenApiMethods)[number]
export type Mode = "effect" | "coverage" | "auth" export type Mode = "effect" | "coverage" | "auth"
export type Backend = "effect"
export type Comparison = "none" | "status" | "json" export type Comparison = "none" | "status" | "json"
export type CaptureMode = "full" | "stream" export type CaptureMode = "full" | "stream"
export type AuthPolicy = "protected" | "public" | "public-bypass" | "ticket-bypass" export type AuthPolicy = "protected" | "public" | "public-bypass" | "ticket-bypass"