fix(260923-ku6): Verbindungstest prueft Formularwerte statt gespeicherten Stand
Nachbesserung aus dem Browser-Rundgang zu 260923-dhh (Befund 1): "Verbindung testen" pruefte bislang immer den in der Datenbank gespeicherten Server, nicht das ungespeicherte Formular. Eine im Formular abgeschaltete Zertifikatspruefung oder ein neu eingetipptes Token-Geheimnis wurden dadurch beim Test ignoriert und erst nach "Speichern" wirksam — eine Falle fuer genau den Ablauf, den Nutzer instinktiv waehlen (eintippen, testen, dann erst speichern). Neues `TestProxmoxServerDto` plus Merge-Baustein `resolveEffectiveTestServer` in `ProxmoxService`: normale Felder folgen dem Formular (auch wenn absichtlich geleert), Geheimnisfelder folgen der bestehenden "leer -> gespeicherten Wert behalten"-Regel, weil `ServerForm` sie beim Laden nie aus der Datenbank vorbefuellt. Neue Route `POST servers/test` (ohne `:id`) deckt die Neuanlage ab, wo es noch keinen gespeicherten Server gibt. Der Testen-Knopf steht jetzt immer zur Verfuegung, nicht mehr nur nach dem ersten Speichern. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -402,6 +402,115 @@ describe('ProxmoxService — Aufgabe 4 (Verbindungstest, Zehn-Sekunden-Sperre)',
|
||||
expect(status.reachable).toBe(false);
|
||||
});
|
||||
|
||||
it('Nachbesserung Befund 1: testConnection prueft die im Formular abgeschaltete Zertifikatspruefung, nicht den gespeicherten Stand (Server wurde MIT tlsRejectUnauthorized:true angelegt)', async () => {
|
||||
const prisma = makeFakePrisma();
|
||||
const service = new ProxmoxService(prisma as any, crypto as any);
|
||||
// Gespeichert: Zertifikatspruefung AN (Vorgabe).
|
||||
const created = await service.createServer('tenant-a', TOKEN_DTO);
|
||||
|
||||
const dispatchers: unknown[] = [];
|
||||
vi.stubGlobal(
|
||||
'fetch',
|
||||
vi.fn(async (_url: string, options: RequestInit & { dispatcher?: unknown }) => {
|
||||
dispatchers.push(options.dispatcher);
|
||||
return new Response(JSON.stringify(pveResourcesBody()), { status: 200 });
|
||||
}),
|
||||
);
|
||||
|
||||
// Formular: Zertifikatspruefung wurde vom Nutzer AUSGESCHALTET, aber noch nicht gespeichert.
|
||||
await service.testConnection('tenant-a', (created as any).id, {
|
||||
tlsRejectUnauthorized: false,
|
||||
});
|
||||
|
||||
// Vor der Korrektur wurde ausschliesslich der gespeicherte Server (Zertifikatspruefung AN)
|
||||
// getestet — dieser Test waere ohne die Korrektur rot, weil dispatchers[0] dann `undefined` waere.
|
||||
expect(dispatchers[0]).toBeInstanceOf(Agent);
|
||||
// biome-ignore lint/suspicious/noExplicitAny: Test-Attrappe traegt `options` nicht im echten undici-Typ
|
||||
expect((dispatchers[0] as any).options).toEqual({ connect: { rejectUnauthorized: false } });
|
||||
});
|
||||
|
||||
it('Nachbesserung Befund 1: ein im Formular NEU eingetipptes Token-Geheimnis wird getestet, nicht das gespeicherte', async () => {
|
||||
const prisma = makeFakePrisma();
|
||||
const service = new ProxmoxService(prisma as any, crypto as any);
|
||||
const created = await service.createServer('tenant-a', TOKEN_DTO);
|
||||
|
||||
let capturedAuth: string | null = null;
|
||||
vi.stubGlobal(
|
||||
'fetch',
|
||||
vi.fn(async (_url: string, options: RequestInit) => {
|
||||
capturedAuth = (options.headers as Record<string, string>).Authorization;
|
||||
return new Response(JSON.stringify(pveResourcesBody()), { status: 200 });
|
||||
}),
|
||||
);
|
||||
|
||||
await service.testConnection('tenant-a', (created as any).id, {
|
||||
tokenSecret: 'ein-anderes-geheimnis',
|
||||
});
|
||||
|
||||
// Ohne die Korrektur wuerde hier weiterhin TOKEN_DTO.tokenSecret gesendet — roter Test.
|
||||
expect(capturedAuth).toBe(`PVEAPIToken=${TOKEN_DTO.tokenId}=ein-anderes-geheimnis`);
|
||||
});
|
||||
|
||||
it('Nachbesserung Befund 1: leer gelassenes Geheimnisfeld im Formular nutzt weiterhin das gespeicherte Token-Geheimnis', async () => {
|
||||
const prisma = makeFakePrisma();
|
||||
const service = new ProxmoxService(prisma as any, crypto as any);
|
||||
const created = await service.createServer('tenant-a', TOKEN_DTO);
|
||||
|
||||
let capturedAuth: string | null = null;
|
||||
vi.stubGlobal(
|
||||
'fetch',
|
||||
vi.fn(async (_url: string, options: RequestInit) => {
|
||||
capturedAuth = (options.headers as Record<string, string>).Authorization;
|
||||
return new Response(JSON.stringify(pveResourcesBody()), { status: 200 });
|
||||
}),
|
||||
);
|
||||
|
||||
// Formular sendet kein tokenSecret (Feld leer gelassen) — wie `ServerForm.buildPayload()`.
|
||||
await service.testConnection('tenant-a', (created as any).id, {});
|
||||
|
||||
expect(capturedAuth).toBe(`PVEAPIToken=${TOKEN_DTO.tokenId}=${TOKEN_DTO.tokenSecret}`);
|
||||
});
|
||||
|
||||
it('Nachbesserung Befund 1: testDraftConnection testet einen noch nicht gespeicherten Server ausschliesslich mit den Formularwerten', async () => {
|
||||
const prisma = makeFakePrisma();
|
||||
const service = new ProxmoxService(prisma as any, crypto as any);
|
||||
|
||||
let capturedUrl: string | null = null;
|
||||
vi.stubGlobal(
|
||||
'fetch',
|
||||
vi.fn(async (url: string) => {
|
||||
capturedUrl = url;
|
||||
return new Response(JSON.stringify(pveResourcesBody()), { status: 200 });
|
||||
}),
|
||||
);
|
||||
|
||||
const result = await service.testDraftConnection({
|
||||
productType: 'pve',
|
||||
baseUrl: 'https://neu.intern:8006',
|
||||
authMethod: 'token',
|
||||
tokenId: 'root@pam!neu',
|
||||
tokenSecret: 'frisches-geheimnis',
|
||||
});
|
||||
|
||||
expect(result.reachable).toBe(true);
|
||||
expect(capturedUrl).toBe('https://neu.intern:8006/api2/json/cluster/resources');
|
||||
});
|
||||
|
||||
it('Nachbesserung Befund 1: testDraftConnection ohne Geheimnis liefert den Fehlerschluessel "zugang", statt zu werfen', async () => {
|
||||
const prisma = makeFakePrisma();
|
||||
const service = new ProxmoxService(prisma as any, crypto as any);
|
||||
|
||||
const result = await service.testDraftConnection({
|
||||
productType: 'pve',
|
||||
baseUrl: 'https://neu.intern:8006',
|
||||
authMethod: 'token',
|
||||
tokenId: 'root@pam!neu',
|
||||
});
|
||||
|
||||
expect(result.reachable).toBe(false);
|
||||
expect(result.errorKind).toBe('zugang');
|
||||
});
|
||||
|
||||
it('POST servers/:id/poll verweigert einen zweiten Durchlauf innerhalb von zehn Sekunden und liefert den vorhandenen Stand', async () => {
|
||||
const prisma = makeFakePrisma();
|
||||
const service = new ProxmoxService(prisma as any, crypto as any);
|
||||
|
||||
Reference in New Issue
Block a user