Simplify single-backend HttpApi exerciser (#26906)
This commit is contained in:
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user