044daab357
Схлопнутая дельта feat/git-sync-2 поверх актуального develop (3085ec1b). Почему squash, а не буквальный rebase: в ветке 113 коммитов, из которых develop уже впитал ~80 в курированном виде при унификации конвертера (#326/#293) — но не patch-identical, поэтому они не отваливаются сами; а коммит, УДАЛЯЮЩИЙ вендоренную копию конвертера, апстримный и в replay-набор не входит, так что наивный replay заново добавил бы вендоренные копии. Поэтому корректный итог — «develop + чистая net-дельта ветки», сведённая 3-way мержом (merge-base5336f06d). Net-дельта: серверный git-sync модуль (GitSyncModule/orchestrator/HTTP), движок git-sync (layout/reconcile/pull/push/stabilize + QA), два фикса round-trip/data-loss конвертера поверх УНИФИЦИРОВАННОГО @docmost/prosemirror-markdown (вендоренной копии больше нет — git-sync целиком на унифицированном конвертере, поведение унифицированного принято за эталон), e2e-скрипты, доки. Конфликты (4) слиты объединением: main.ts (метрики + GitHttpService), apps/server/package.json (pretest-суперсет; moduleNameMapper: git-sync→src и .js-strip оставлены, а bare-specifier @docmost/prosemirror-markdown→src УБРАН — серверный jest выровнен на develop-подход #345 со сборённым пакетом), .env.example (метрики + GIT_SYNC блоки), AGENTS.md (строки про пакеты; устаревшая заметка про «три hand-synced копии схемы» в git-sync поправлена — схема теперь только в @docmost/prosemirror-markdown). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
72 lines
2.5 KiB
TypeScript
72 lines
2.5 KiB
TypeScript
import { resolveRequestWorkspace } from './resolve-request-workspace';
|
|
|
|
// Unit tests for the shared self-hosted/cloud workspace resolver deduplicated out
|
|
// of DomainMiddleware + GitHttpService (architecture #11). They must behave
|
|
// identically, so this pins the single source of truth.
|
|
|
|
type AnyMock = jest.Mock;
|
|
|
|
function build(opts: {
|
|
selfHosted: boolean;
|
|
first?: { id: string } | null;
|
|
byHostname?: { id: string } | null;
|
|
}) {
|
|
const env = {
|
|
isSelfHosted: jest.fn(() => opts.selfHosted),
|
|
isCloud: jest.fn(() => !opts.selfHosted),
|
|
};
|
|
const repo = {
|
|
findFirst: jest.fn(async () => opts.first ?? null) as AnyMock,
|
|
findByHostname: jest.fn(async () => opts.byHostname ?? null) as AnyMock,
|
|
};
|
|
return { env, repo };
|
|
}
|
|
|
|
describe('resolveRequestWorkspace', () => {
|
|
it('self-hosted: returns the first/default workspace, ignoring the host', async () => {
|
|
const { env, repo } = build({ selfHosted: true, first: { id: 'ws-1' } });
|
|
const ws = await resolveRequestWorkspace(
|
|
env as any,
|
|
repo as any,
|
|
'anything.example.com',
|
|
);
|
|
expect(ws).toEqual({ id: 'ws-1' });
|
|
expect(repo.findFirst).toHaveBeenCalledTimes(1);
|
|
expect(repo.findByHostname).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('self-hosted: returns null when no workspace is configured', async () => {
|
|
const { env, repo } = build({ selfHosted: true, first: null });
|
|
expect(await resolveRequestWorkspace(env as any, repo as any, 'h')).toBeNull();
|
|
});
|
|
|
|
it('cloud: resolves by the host-header subdomain', async () => {
|
|
const { env, repo } = build({
|
|
selfHosted: false,
|
|
byHostname: { id: 'ws-acme' },
|
|
});
|
|
const ws = await resolveRequestWorkspace(
|
|
env as any,
|
|
repo as any,
|
|
'acme.example.com',
|
|
);
|
|
expect(ws).toEqual({ id: 'ws-acme' });
|
|
expect(repo.findByHostname).toHaveBeenCalledWith('acme');
|
|
expect(repo.findFirst).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('cloud: returns null for a blank/missing host (no throw)', async () => {
|
|
const { env, repo } = build({ selfHosted: false, byHostname: { id: 'x' } });
|
|
expect(await resolveRequestWorkspace(env as any, repo as any, undefined)).toBeNull();
|
|
expect(await resolveRequestWorkspace(env as any, repo as any, '')).toBeNull();
|
|
expect(repo.findByHostname).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('cloud: returns null when the subdomain matches no workspace', async () => {
|
|
const { env, repo } = build({ selfHosted: false, byHostname: null });
|
|
expect(
|
|
await resolveRequestWorkspace(env as any, repo as any, 'ghost.example.com'),
|
|
).toBeNull();
|
|
});
|
|
});
|