Cobre rotas HTTP, proxy, worker assíncrono e barreiras do dev auth
Os 34 testes existentes batiam só na camada de serviço: as rotas, o proxy e o loop do worker não tinham cobertura alguma. A suíte vai de 34 para 102. - `tests/http/`: rotas reais com o caminho real de autenticação, sem subir servidor. Cobre 401 sem sessão, módulo desligado, papel sem permissão, 403 ao tentar gravar workspace de terceiro, e 429 com Retry-After. - `tests/http/proxy.test.ts`: o proxy não propaga query da requisição para o login, o que impediria um returnTo forjado. - `tests/integration/worker.test.ts`: jornada assíncrona pelo loop real. A web enfileira e devolve `queued`, o download falha antes do tick, o tick conclui e os três formatos saem. Também: job sobrevive à perda da fila do Redis, worker relê o contexto e não processa com a flag desligada, TTL expira temporários sem tocar o modelo, e desligamento gracioso. - `tests/unit/dev-auth-guard.test.ts`: matriz de ambientes das três barreiras do login local. Um token de dev válido é recusado quando o ambiente é staging. Espaço em volta de um valor de ADAPTER_ENV é tolerado de propósito, e isso está declarado no teste; valor desconhecido nunca vira development. - `tests/services/`: Postgres e Redis reais. Confere `app_user` sem BYPASSRLS, FORCE RLS em todas as tabelas, isolamento entre workspaces, auditoria não alterável pelo papel da aplicação, e lock entre conexões diferentes. Sem as variáveis de serviço os casos são IGNORADOS, nunca aprovados, e ficam fora de `npm test` para a suíte padrão passar em qualquer máquina. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
dea510c3b4
commit
ce11a50091
10 files changed
+1182
No files matched your search
@@ -0,0 +1,69 @@
|
||||
import { vi } from "vitest";
|
||||
import type { Db } from "@/infra/db/types";
|
||||
import { MemoryCoordinator } from "@/infra/redis/memory";
|
||||
import { MemoryStorage } from "@/infra/storage/memory";
|
||||
import { signDevSession } from "@/server/auth/dev-session";
|
||||
|
||||
export type FakeCookie = { name: string; value: string };
|
||||
|
||||
/**
|
||||
* Jar de cookies no formato que `next/headers` entrega. Permite exercitar as
|
||||
* rotas reais, com o caminho real de autenticação, sem subir um servidor.
|
||||
*/
|
||||
export class FakeJar {
|
||||
private readonly store = new Map<string, string>();
|
||||
|
||||
get(name: string): FakeCookie | undefined {
|
||||
const value = this.store.get(name);
|
||||
return value === undefined ? undefined : { name, value };
|
||||
}
|
||||
|
||||
getAll(): FakeCookie[] {
|
||||
return [...this.store.entries()].map(([name, value]) => ({ name, value }));
|
||||
}
|
||||
|
||||
set(name: string, value: string): void {
|
||||
this.store.set(name, value);
|
||||
}
|
||||
|
||||
delete(name: string): void {
|
||||
this.store.delete(name);
|
||||
}
|
||||
|
||||
has(name: string): boolean {
|
||||
return this.store.has(name);
|
||||
}
|
||||
}
|
||||
|
||||
export const jar = new FakeJar();
|
||||
|
||||
/** Sessão local assinada. Só existe porque os testes rodam em development. */
|
||||
export function signIn(userId: string, workspaceId: string): void {
|
||||
jar.set("adapter_dev_session", signDevSession(userId, workspaceId));
|
||||
}
|
||||
|
||||
export function signOut(): void {
|
||||
for (const cookie of jar.getAll()) jar.delete(cookie.name);
|
||||
}
|
||||
|
||||
/** Dependências do módulo em memória, para não escrever em disco nos testes. */
|
||||
export function makeRuntimeDeps(db: Db) {
|
||||
const storage = new MemoryStorage();
|
||||
const coordinator = new MemoryCoordinator();
|
||||
return {
|
||||
deps: { db, storage, coordinator, ttlSeconds: 3600 },
|
||||
storage,
|
||||
coordinator,
|
||||
};
|
||||
}
|
||||
|
||||
export function installNextHeadersMock(): void {
|
||||
vi.mock("next/headers", () => ({
|
||||
cookies: async () => jar,
|
||||
headers: async () => new Headers(),
|
||||
}));
|
||||
}
|
||||
|
||||
export async function readJson<T = unknown>(response: Response): Promise<T> {
|
||||
return (await response.json()) as T;
|
||||
}
|
||||
Reference in new issue
Block a user