Files
paseo/packages/server/src/utils/checkout-git-batching.test.ts
T
Mohamed Boudra 33a52d0ae7 Speed up cold diffs and wrapped text measurement (#4676)
* perf(app): optimize wrapped measurements and checkpoint native layout experiment

Compute full grapheme geometry only for final wrap fragments. Preserve shaped-text search behavior while bounding additive wrap probes. Keep the Android background layout experiment isolated from the normal diff renderer; native renderer integration and iOS bindings remain unfinished.

* perf(server): reduce cold diff generation work

Keep active diff reads owned across invalidation and wait for the initial watcher inventory before cold generation. Batch patch and blob reads while preserving per-file size isolation, bounded output, and daemon responsiveness. Avoid constructing fallback tokens when full-file highlighting already covers both sides.

* test(server): exercise oversized highlighted diff rejection

The single-line fixture now bypasses highlighting under the long-line guard, so it no longer reaches the structured payload limit. Use short dense lines to keep testing oversized rejection and continued socket usability.

* fix(server): queue fresh diffs for forced reads

A forced request following a repository mutation must not reuse an older active build. Invalidate that result and coalesce waiting callers onto one subsequent build. Give the cache a named object input and completed-value type.

* test(server): share deferred diff loader setup

* test(server): name completed diff cache setup

* refactor(server): use aliases for new diff imports

* fix(server): keep shipped diff imports resolvable by Node

The TypeScript build preserves path aliases without a runtime resolver. Restore relative imports for shipped code and declarations, and correct the server import guideline that prompted the regression.
2026-09-11 08:07:01 +02:00

98 lines
3.6 KiB
TypeScript

import { execFileSync } from "node:child_process";
import { mkdirSync, mkdtempSync, rmSync, writeFileSync, realpathSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { beforeEach, afterEach, describe, expect, it } from "vitest";
import { startGitCommandMetrics, stopGitCommandMetrics } from "@server/utils/run-git-command.js";
import { getCheckoutDiff } from "./checkout-git.js";
function initRepoWithTrackedChanges(fileCount: number): { tempDir: string; repoDir: string } {
const tempDir = realpathSync(mkdtempSync(join(tmpdir(), "checkout-git-batch-test-")));
const repoDir = join(tempDir, "repo");
mkdirSync(repoDir, { recursive: true });
execFileSync("git", ["init", "-b", "main"], { cwd: repoDir });
execFileSync("git", ["config", "user.email", "test@test.com"], { cwd: repoDir });
execFileSync("git", ["config", "user.name", "Test"], { cwd: repoDir });
for (let i = 0; i < fileCount; i += 1) {
writeFileSync(join(repoDir, `file-${i}.txt`), `before-${i}\n`);
}
execFileSync("git", ["add", "."], { cwd: repoDir });
execFileSync("git", ["-c", "commit.gpgsign=false", "commit", "-m", "initial"], {
cwd: repoDir,
});
for (let i = 0; i < fileCount; i += 1) {
writeFileSync(join(repoDir, `file-${i}.txt`), `after-${i}\n`);
}
return { tempDir, repoDir };
}
describe("checkout git diff batching", () => {
let tempDir: string;
let repoDir: string;
beforeEach(() => {
const setup = initRepoWithTrackedChanges(20);
tempDir = setup.tempDir;
repoDir = setup.repoDir;
});
afterEach(() => {
rmSync(tempDir, { recursive: true, force: true });
});
it("collects ordinary tracked patches with one bounded Git command", async () => {
startGitCommandMetrics();
const result = await getCheckoutDiff(repoDir, {
mode: "uncommitted",
includeStructured: false,
});
expect(result.diff).toContain("file-0.txt");
expect(result.diff).toContain("file-19.txt");
const metrics = stopGitCommandMetrics();
expect(
metrics.commands.filter(({ args }) => args[0] === "diff" && args.includes("--")),
).toHaveLength(1);
});
it("batches committed file contents and preserves the highlighted diff", async () => {
execFileSync("git", ["checkout", "-b", "feature"], { cwd: repoDir });
execFileSync("git", ["add", "."], { cwd: repoDir });
execFileSync("git", ["-c", "commit.gpgsign=false", "commit", "-m", "change"], { cwd: repoDir });
startGitCommandMetrics();
const result = await getCheckoutDiff(repoDir, {
mode: "base",
baseRef: "main",
includeStructured: true,
});
const metrics = stopGitCommandMetrics();
expect(result.structured).toHaveLength(20);
expect(result.structured?.every((file) => file.additions === 1 && file.deletions === 1)).toBe(
true,
);
expect(metrics.commands.filter(({ args }) => args[0] === "show")).toHaveLength(0);
expect(metrics.commands.filter(({ args }) => args[0] === "cat-file")).toHaveLength(1);
});
it("keeps small neighbors when a patch exceeds the entire batch budget", async () => {
writeFileSync(join(repoDir, "file-0.txt"), "x".repeat(9 * 1024 * 1024) + "\n");
const result = await getCheckoutDiff(repoDir, {
mode: "uncommitted",
includeStructured: true,
});
expect(result.structured).toHaveLength(20);
expect(result.structured?.find((file) => file.path === "file-0.txt")).toMatchObject({
status: "too_large",
hunks: [],
});
expect(result.structured?.filter((file) => file.status === "ok")).toHaveLength(19);
expect(result.diff).toContain("+after-19");
expect(result.diff).not.toContain("x".repeat(1_000));
});
});