test/worktree-branch-collisions.test.js
Rama main · réplica de lectura del repositorio original.
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { mkdtempSync } from 'fs';
import { tmpdir } from 'os';
import { join } from 'path';
const stub = vi.hoisted(() => ({ exec: vi.fn(), uuid: vi.fn() }));
vi.mock('child_process', async importOriginal => ({ ...await importOriginal(), execFile: stub.exec }));
vi.mock('crypto', async importOriginal => ({ ...await importOriginal(), randomUUID: stub.uuid }));
import { createWorktree } from '../server/git.js';
const repo = mkdtempSync(join(tmpdir(), 'a007-branch-collision-'));
const uuid = '12345678-1234-4234-8234-123456789abc';
let attempts, remoteError, remoteNames, collision;
beforeEach(() => {
attempts = []; remoteError = false; remoteNames = []; collision = false;
stub.uuid.mockReset().mockReturnValue(uuid);
stub.exec.mockImplementation((file, args, options, callback) => {
expect(options.timeout).toBeGreaterThan(0);
expect(options.env.GIT_TERMINAL_PROMPT).toBe('0');
if (args.includes('config')) return callback(null, 'owner\n', '');
if (args.includes('ls-remote')) {
if (remoteError) return callback(new Error('offline'), '', 'offline');
return callback(null, remoteNames.map(n => `abc\trefs/heads/owner/${n}`).join('\n'), '');
}
if (args.includes('worktree')) {
const branch = args[args.indexOf('-b') + 1];
attempts.push(branch);
if (collision) return callback(new Error('collision'), '', `fatal: a branch named '${branch}' already exists`);
}
callback(null, '', '');
});
});
describe('bounded board branch allocation', () => {
it('uses fresh entropy if remote discovery fails instead of reusing a possibly remote-only base', async () => {
remoteError = true;
const result = await createWorktree(repo, 'offline', 'job', { suffixOnCollision: true, startPoint: 'HEAD' });
expect(result.branchName).toBe(`owner/job-${uuid}`);
expect(attempts).toEqual([result.branchName]);
});
it('bounds atomic local collision retries even when every random name collides', async () => {
collision = true;
const result = await createWorktree(repo, 'collisions', 'job', { suffixOnCollision: true, startPoint: 'HEAD' });
expect(result.error).toMatch(/Could not find a free branch name/);
expect(attempts).toHaveLength(10);
expect(attempts[0]).toBe('owner/job');
expect(stub.uuid).toHaveBeenCalledTimes(9);
});
it('retries an atomic local base collision with a fresh name when discovery succeeds', async () => {
const exec = stub.exec.getMockImplementation();
stub.exec.mockImplementation((file, args, options, callback) => {
collision = args.includes('worktree') && attempts.length === 0;
exec(file, args, options, callback);
});
const result = await createWorktree(repo, 'local', 'job', { suffixOnCollision: true, startPoint: 'HEAD' });
expect(result.error).toBeUndefined();
expect(result.branchName).toBe(`owner/job-${uuid}`);
expect(attempts).toEqual(['owner/job', `owner/job-${uuid}`]);
expect(stub.uuid).toHaveBeenCalledTimes(1);
});
it('bounds remote-only collisions without attempting or deleting those branches', async () => {
remoteNames = ['job', `job-${uuid}`];
const result = await createWorktree(repo, 'remote', 'job', { suffixOnCollision: true, startPoint: 'HEAD' });
expect(result.error).toMatch(/Could not find a free branch name/);
expect(attempts).toEqual([]);
expect(stub.uuid).toHaveBeenCalledTimes(9);
expect(stub.exec.mock.calls.every(([, args]) => !args.includes('-D') && !args.includes('delete'))).toBe(true);
});
});