87 lines
3.8 KiB
JavaScript
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)
|
|
})
|