feat(260923-dhh): Proxmox-Modul Aufgabe 3 - PBS und PMG auswerten
- proxmox-normalize.ts: nachsichtige Leser (readNumber/readText/readBool/ readList) und normalizePve/normalizePbs/normalizePmg als reine Funktionen, nie ein Wurf bei unerwarteter Form - PVE ergaenzt um je Speicherort Belegung (storages) - PBS: Belegung je Datenspeicher plus letzte Sicherung/Pruefergebnis aus bis zu 10 Folgeabfragen je Durchlauf (Deckel in proxmox.service.ts) - PMG: Tageszahlen eingehend/ausgehend/Spam/Viren - Feldnamen je Produkt als benannte Konstante (Annahmen A3/A5 der Recherche), mehrere plausible Namen je Feld moeglich - proxmox.service.ts: produktabhaengige Abfragefolge, Ticket-Erneuerung jetzt je Durchlauf statt je Aufruf (PBS-Mehrfachabfragen loggen nicht mehrfach neu ein) - proxmox-nur-lesen.spec.ts: Riegel erkennt jetzt auch den Umschlag getWithRetry als zulaessige Aufrufform Tore: api 1293/1293 (>=1240), type-check 4/4. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -264,3 +264,86 @@ describe('ProxmoxService — Aufgabe 1 (PVE per Token, durchgehender Weg)', () =
|
||||
expect(forTenant).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('ProxmoxService — Aufgabe 3 (PBS und PMG)', () => {
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
it('fragt PBS ab: Belegung plus je Datenspeicher hoechstens 10 Folgeabfragen', async () => {
|
||||
const prisma = makeFakePrisma();
|
||||
const service = new ProxmoxService(prisma as any, crypto as any);
|
||||
const created = await service.createServer('tenant-a', {
|
||||
...TOKEN_DTO,
|
||||
name: 'pbs-1',
|
||||
productType: 'pbs',
|
||||
baseUrl: 'https://pbs.intern:8007',
|
||||
});
|
||||
|
||||
const usageBody = {
|
||||
data: Array.from({ length: 15 }, (_, i) => ({ store: `store-${i}`, total: 100, used: 10, avail: 90 })),
|
||||
};
|
||||
|
||||
let snapshotCalls = 0;
|
||||
const fetchSpy = vi.fn(async (url: string) => {
|
||||
if (url.includes('/status/datastore-usage')) {
|
||||
return new Response(JSON.stringify(usageBody), { status: 200 });
|
||||
}
|
||||
snapshotCalls++;
|
||||
return new Response(JSON.stringify({ data: [] }), { status: 200 });
|
||||
});
|
||||
vi.stubGlobal('fetch', fetchSpy);
|
||||
|
||||
const result = await service.pollServer('tenant-a', (created as any).id);
|
||||
|
||||
expect(result?.reachable).toBe(true);
|
||||
expect(snapshotCalls).toBe(10);
|
||||
expect((result?.metrics as { datastores: unknown[] }).datastores).toHaveLength(15);
|
||||
});
|
||||
|
||||
it('fragt PMG ab und normalisiert die Tageszahlen', async () => {
|
||||
const prisma = makeFakePrisma();
|
||||
const service = new ProxmoxService(prisma as any, crypto as any);
|
||||
const created = await service.createServer('tenant-a', {
|
||||
name: 'pmg-1',
|
||||
productType: 'pmg',
|
||||
baseUrl: 'https://pmg.intern:8006',
|
||||
authMethod: 'password',
|
||||
username: 'admin@pmg',
|
||||
password: 'geheim',
|
||||
});
|
||||
|
||||
const fetchSpy = vi.fn(async (url: string) => {
|
||||
if (url.endsWith('/access/ticket')) {
|
||||
return new Response(JSON.stringify({ data: { ticket: 'PMG:admin@pmg:xyz' } }), { status: 200 });
|
||||
}
|
||||
return new Response(
|
||||
JSON.stringify({ data: { count_in: 10, count_out: 5, spamcount_in: 1, spamcount_out: 0, viruscount_in: 0, viruscount_out: 0 } }),
|
||||
{ status: 200 },
|
||||
);
|
||||
});
|
||||
vi.stubGlobal('fetch', fetchSpy);
|
||||
|
||||
const result = await service.pollServer('tenant-a', (created as any).id);
|
||||
|
||||
expect(result?.reachable).toBe(true);
|
||||
expect(result?.metrics).toMatchObject({ productType: 'pmg', countIn: 10, countOut: 5, spamCount: 1 });
|
||||
});
|
||||
|
||||
it('401/403/404/500 bleiben fuer PBS/PMG dieselben Fehlerschluessel wie fuer PVE', async () => {
|
||||
const prisma = makeFakePrisma();
|
||||
const service = new ProxmoxService(prisma as any, crypto as any);
|
||||
const created = await service.createServer('tenant-a', {
|
||||
...TOKEN_DTO,
|
||||
name: 'pbs-403',
|
||||
productType: 'pbs',
|
||||
baseUrl: 'https://pbs.intern:8007',
|
||||
});
|
||||
|
||||
vi.stubGlobal('fetch', vi.fn(async () => new Response('forbidden', { status: 403 })));
|
||||
const result = await service.pollServer('tenant-a', (created as any).id);
|
||||
expect(result?.reachable).toBe(false);
|
||||
expect(result?.errorKind).toBe('rechte');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user