Skip to content
File

Blob: test/util/test-helpers.ts

typescript80 lines
1/**
2 * Shared test utilities for Git operations.
3 */
4 
5import { exports as workerExports } from "cloudflare:workers";
6import { lookupPushAuth } from "./repoSeed";
7 
8type StringEnvKey = {
9 [K in keyof Env]: Env[K] extends string | undefined ? K : never;
10}[keyof Env];
11 
12/**
13 * Temporarily override selected env bindings for the duration of fn(), restoring afterwards.
14 */
15export async function withEnvOverrides<T, K extends StringEnvKey>(
16 env: Env,
17 overrides: Pick<Env, K>,
18 fn: () => Promise<T>
19): Promise<T> {
20 const keys = Object.keys(overrides) as K[];
21 const prev = new Map<K, Env[K]>();
22 for (const key of keys) {
23 prev.set(key, env[key]);
24 env[key] = overrides[key];
25 }
26 try {
27 return await fn();
28 } finally {
29 for (const key of keys) {
30 const value = prev.get(key);
31 if (value !== undefined) {
32 env[key] = value;
33 } else {
34 delete env[key];
35 }
36 }
37 }
38}
39 
40export * from "./do-retry";
41export * from "./git-pack";
42export * from "./packed-repo";
43 
44export function toRequestBody(bytes: Uint8Array): ArrayBuffer {
45 const body = new ArrayBuffer(bytes.byteLength);
46 new Uint8Array(body).set(bytes);
47 return body;
48}
49 
50/**
51 * Generate a per-test unique repo id suffix to avoid shared storage collisions
52 * when isolatedStorage is disabled.
53 */
54export function uniqueRepoId(prefix = "r"): string {
55 return `${prefix}-${Math.random().toString(36).slice(2, 10)}`;
56}
57 
58// POST to git-receive-pack with the seeded push PAT auto-attached. The owner
59// and repo are parsed from the URL and matched against the auth registered
60// by `setupRepoForTests`. Tests that want to assert auth failures should
61// build the request themselves rather than going through this helper.
62export async function postReceivePack(
63 url: string,
64 body: Uint8Array,
65 options?: { authHeader?: string; signal?: AbortSignal }
66): Promise<Response> {
67 const headers: Record<string, string> = {
68 "Content-Type": "application/x-git-receive-pack-request",
69 };
70 const match = /https?:\/\/[^/]+\/([^/]+)\/([^/]+)\/git-receive-pack/.exec(url);
71 const auth = options?.authHeader ?? (match ? lookupPushAuth(match[1]!, match[2]!) : undefined);
72 if (auth) headers.Authorization = auth;
73 return await workerExports.default.fetch(url, {
74 method: "POST",
75 headers,
76 body: toRequestBody(body),
77 signal: options?.signal,
78 });
79}