Files
Webklar-Kundenbereich/test/newsImages.test.js
T
2026-09-30 16:38:33 +00:00

87 lines
3.8 KiB
JavaScript

import test from 'node:test'
import assert from 'node:assert/strict'
import os from 'node:os'
import path from 'node:path'
import { mkdtempSync, existsSync } from 'node:fs'
import { readFile, writeFile } from 'node:fs/promises'
import sharp from 'sharp'
process.env.NEWS_UPLOAD_DIR = mkdtempSync(path.join(os.tmpdir(), 'news-images-'))
const { storeNewsImage, claimNewsImage, newsImagePath, purgeUnclaimedNewsImages, newsImageRateLimited, NEWS_IMAGE_MAX_BYTES } =
await import('../server/services/newsImages.js')
const solid = (width, height) => sharp({ create: { width, height, channels: 3, background: '#c33' } })
test('exif_gps_entfernt_und_gedreht', async () => {
const input = await solid(1200, 800)
.withMetadata({ orientation: 6 })
.withExif({ IFD3: { GPSLatitudeRef: 'N', GPSLatitude: '48/1 30/1 0/1' } })
.jpeg().toBuffer()
const inMeta = await sharp(input).metadata()
assert.ok(inMeta.exif, 'Fixture hat EXIF')
assert.equal(inMeta.orientation, 6)
const { imageId } = await storeNewsImage({ customerId: 'c1', projectId: 'p1', buffer: input })
for (const size of ['l', 's']) {
const meta = await sharp(newsImagePath('p1', imageId, size)).metadata()
assert.equal(meta.exif, undefined)
assert.ok(meta.width < meta.height, `${size}: gedreht`)
}
})
test('verkleinert_auf_1600_und_480', async () => {
const input = await solid(4000, 3000).png().toBuffer()
const { imageId, w, h } = await storeNewsImage({ customerId: 'c1', projectId: 'p1', buffer: input })
assert.deepEqual([w, h], [1600, 1200])
const l = await sharp(newsImagePath('p1', imageId, 'l')).metadata()
const s = await sharp(newsImagePath('p1', imageId, 's')).metadata()
assert.deepEqual([l.format, l.width, l.height], ['webp', 1600, 1200])
assert.deepEqual([s.format, s.width, s.height], ['webp', 480, 360])
})
test('zu_gross_413', async () => {
await assert.rejects(
storeNewsImage({ customerId: 'c1', projectId: 'p1', buffer: Buffer.alloc(NEWS_IMAGE_MAX_BYTES + 1) }),
{ status: 413 },
)
})
test('falscher_typ_415', async () => {
await assert.rejects(
storeNewsImage({ customerId: 'c1', projectId: 'p1', buffer: Buffer.from('%PDF-1.4\n1 0 obj\n<<>>\nendobj\ntrailer\n<<>>\n%%EOF\n') }),
{ status: 415 },
)
})
test('pfad_nur_saubere_ids', () => {
assert.equal(newsImagePath('p1', '../x', 'l'), null)
assert.equal(newsImagePath('../p', 'abc-1', 'l'), null)
assert.ok(newsImagePath('p1', 'abc-1', 's').endsWith(path.join('p1', 'abc-1-s.webp')))
})
test('unbenutzte_nach_24h_weg', async () => {
const input = await solid(100, 100).png().toBuffer()
const old = await storeNewsImage({ customerId: 'c1', projectId: 'p2', buffer: input })
const kept = await storeNewsImage({ customerId: 'c1', projectId: 'p2', buffer: input })
const fresh = await storeNewsImage({ customerId: 'c1', projectId: 'p2', buffer: input })
await claimNewsImage('p2', kept.imageId)
const backdate = async (id) => {
const f = path.join(process.env.NEWS_UPLOAD_DIR, 'p2', `${id}.json`)
const meta = JSON.parse(await readFile(f, 'utf8'))
meta.createdAt = new Date(Date.now() - 25 * 3600 * 1000).toISOString()
await writeFile(f, JSON.stringify(meta))
}
await backdate(old.imageId)
await backdate(kept.imageId)
assert.equal(await purgeUnclaimedNewsImages(), 1)
assert.equal(existsSync(newsImagePath('p2', old.imageId, 'l')), false)
assert.equal(existsSync(newsImagePath('p2', old.imageId, 's')), false)
assert.equal(existsSync(newsImagePath('p2', kept.imageId, 'l')), true)
assert.equal(existsSync(newsImagePath('p2', fresh.imageId, 'l')), true)
})
test('rate_limit_20_pro_stunde', () => {
for (let i = 0; i < 20; i++) assert.equal(newsImageRateLimited('rl'), false)
assert.equal(newsImageRateLimited('rl'), true)
assert.equal(newsImageRateLimited('other'), false)
})