Analyse: Freischalten selbstheilend, Sperre, Retention-Abschaltung

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Sonnet 5.5 committed 2026-10-01 10:13:28 +00:00
1 parent f0eee196ed
commit 37203f00c4
6 files changed
+149 -33

No files matched your search

+69 -1
View File
@@ -7,7 +7,7 @@ import { schemaKeys } from './support/schema.js'
import { mailSink } from './support/mailSink.js'
// Das Setup-Skript laedt config.js: erst nach useTestEnv() importieren, daher die Attributnamen hier fest
const ANALYSE_KEYS = ['accentColor', 'avvVersion', 'avvAcceptedAt', 'avvAcceptedBy', 'activatedAt', 'offSince', 'privacyTicketId']
const ANALYSE_KEYS = ['accentColor', 'avvVersion', 'avvAcceptedAt', 'avvAcceptedBy', 'activatedAt', 'offSince', 'privacyTicketId', 'activatedMailAt']
const aw = await startAppwriteMock({
schema: {
portalFeatures: [...schemaKeys('portalFeatures'), ...ANALYSE_KEYS],
@@ -175,3 +175,71 @@ test('News-Jobs ignorieren Analyse-Dokumente', async () => {
const active = await doc('c1', 'p1')
assert.equal(await sf.findActiveBySiteKey(active.siteKey.slice(0, 16)), null, 'Analyse-siteKey ist kein News-Schlüssel')
})
test('selbstheilend: Ticket scheitert einmal, Wiederholung holt Ticket, Neubau und Mail genau einmal nach', async () => {
aw.seed('websiteProjects', { $id: 'p6', customerId: 'c1', projectName: 'Heilung', subdomain: 'heilung', isPublic: true, repoFullName: 'WEBklar/heilung' })
const original = an.analyseDeps.ticket
let failOnce = true
an.analyseDeps.ticket = async (...args) => {
if (failOnce) { failOnce = false; throw new Error('Ticketsystem down') }
return original(...args)
}
const before = analyseTickets().length
await assert.rejects(an.activateAnalyse({ customerId: 'c1', projectId: 'p6', consent: consent() }), /Ticketsystem down/)
assert.equal((await doc('c1', 'p6')).state, 'active')
assert.equal(rebuilds.length, 0)
assert.equal(mails.sent.length, 0)
const r = await an.activateAnalyse({ customerId: 'c1', projectId: 'p6', consent: consent() })
assert.equal(r.doc.state, 'active')
assert.ok(r.doc.privacyTicketId && r.doc.activatedMailAt)
assert.equal(analyseTickets().length, before + 1)
assert.deepEqual(rebuilds, ['p6'])
assert.equal(mails.sent.length, 1)
// dritter Aufruf: nichts mehr offen
await an.activateAnalyse({ customerId: 'c1', projectId: 'p6', consent: consent() })
assert.equal(analyseTickets().length, before + 1)
assert.deepEqual(rebuilds, ['p6'])
assert.equal(mails.sent.length, 1)
an.analyseDeps.ticket = original
})
test('putSite scheitert: Dokument bleibt unverändert', async () => {
aw.seed('websiteProjects', { $id: 'p7', customerId: 'c1', projectName: 'Down', subdomain: 'down', isPublic: true })
const ok = an.analyseDeps.client
an.analyseDeps.client = { putSite: async () => { throw Object.assign(new Error('Auswertung nicht erreichbar'), { status: 502 }) } }
await assert.rejects(an.activateAnalyse({ customerId: 'c1', projectId: 'p7', consent: consent() }), { status: 502 })
assert.equal(await doc('c1', 'p7') === null || (await doc('c1', 'p7')).state === 'off', true)
assert.equal(analyseTickets().filter((t) => t.details.includes('Down')).length, 0)
an.analyseDeps.client = ok
})
test('Neubau scheitert: Analyse bleibt aktiv, kein Fehler', async () => {
aw.seed('websiteProjects', { $id: 'p8', customerId: 'c1', projectName: 'Bau', subdomain: 'bau', isPublic: true, repoFullName: 'WEBklar/bau' })
const ok = an.analyseDeps.rebuild
an.analyseDeps.rebuild = async () => { throw new Error('Runner weg') }
const r = await an.activateAnalyse({ customerId: 'c1', projectId: 'p8', consent: consent() })
assert.equal(r.doc.state, 'active')
assert.equal(mails.sent.length, 1)
an.analyseDeps.rebuild = ok
})
test('parallel einschalten: ein Ticket, eine Mail', async () => {
aw.seed('websiteProjects', { $id: 'p9', customerId: 'c1', projectName: 'Parallel', subdomain: 'parallel', isPublic: true })
const before = analyseTickets().length
mails.sent.length = 0
await Promise.all([
an.activateAnalyse({ customerId: 'c1', projectId: 'p9', consent: consent() }),
an.activateAnalyse({ customerId: 'c1', projectId: 'p9', consent: consent() }),
])
assert.equal(analyseTickets().length, before + 1)
assert.equal(mails.sent.length, 1)
})
test('gesperrte Analyse: Kunde 403, Mitarbeiter darf', async () => {
aw.seed('websiteProjects', { $id: 'p10', customerId: 'c1', projectName: 'Gesperrt', subdomain: 'gesperrt', isPublic: true })
const g = await sf.ensureFeatureDoc('c1', 'p10', 'analyse')
await sf.disable(g.$id, {})
await assert.rejects(an.activateAnalyse({ customerId: 'c1', projectId: 'p10', consent: consent() }), { status: 403, message: 'Analyse wurde gesperrt – bitte melde dich bei uns' })
const r = await an.activateAnalyse({ customerId: 'c1', projectId: 'p10', consent: consent(), by: 'Kenso' })
assert.equal(r.doc.state, 'active')
})