storage-upload/test/media/routes.test.mjs

519 lines
16 KiB
JavaScript

import { Eltro as t, assert, stub } from 'eltro'
import { createContext } from '../helper.server.mjs'
import MediaRoutes from '../../api/media/routes.mjs'
import { HttpError } from '../../api/error.mjs'
t.describe('#filesCacheGet', function() {
t.test('should return all files in public folder', async function() {
const routes = new MediaRoutes()
await routes.init()
assert.ok(routes.filesCacheGet('development'))
assert.ok(Array.isArray(routes.filesCacheGet('development')))
assert.ok(routes.filesCacheGet('existing'))
assert.ok(Array.isArray(routes.filesCacheGet('existing')))
assert.ok(routes.filesCacheGet('nonexisting'))
assert.ok(Array.isArray(routes.filesCacheGet('nonexisting')))
assert.strictEqual(routes.filesCacheGet('development').length, 1)
assert.strictEqual(routes.filesCacheGet('existing').length, 2)
assert.strictEqual(routes.filesCacheGet('nonexisting').length, 0)
assert.strictEqual(routes.filesCacheGet('development')[0].name, '.gitkeep')
assert.strictEqual(routes.filesCacheGet('development')[0].size, 0)
assert.strictEqual(routes.filesCacheGet('existing')[0].name, '20220105_101610_test1.jpg')
assert.strictEqual(routes.filesCacheGet('existing')[0].size, 15079)
assert.strictEqual(routes.filesCacheGet('existing')[1].name, '20220105_101610_test2.png')
assert.strictEqual(routes.filesCacheGet('existing')[1].size, 31705)
})
t.test('should always sort result', async function() {
const routes = new MediaRoutes()
await routes.init()
let files = routes.filesCacheGet('existing')
assert.strictEqual(files[0].name, '20220105_101610_test1.jpg')
assert.strictEqual(files[0].size, 15079)
assert.strictEqual(files[1].name, '20220105_101610_test2.png')
assert.strictEqual(files[1].size, 31705)
routes.siteCache.get('existing').push({ name: '0000.png', size: 0 })
files = routes.filesCacheGet('existing')
assert.strictEqual(files[0].name, '0000.png')
assert.strictEqual(files[0].size, 0)
assert.strictEqual(files[1].name, '20220105_101610_test1.jpg')
assert.strictEqual(files[1].size, 15079)
assert.strictEqual(files[2].name, '20220105_101610_test2.png')
assert.strictEqual(files[2].size, 31705)
})
})
t.describe('#listFiles()', function() {
const stubVerify = stub()
const stubGetCache = stub()
const routes = new MediaRoutes({
security: { verifyToken: stubVerify },
})
routes.filesCacheGet = stubGetCache
function reset() {
stubVerify.reset()
stubGetCache.reset()
}
t.test('should call security correctly', async function() {
reset()
let ctx = createContext()
const assertError = new Error('temp')
stubVerify.rejects(assertError)
let err = await assert.isRejected(routes.listFiles(ctx))
assert.ok(stubVerify.called)
assert.strictEqual(err, assertError)
assert.strictEqual(stubVerify.firstCall[0], ctx)
})
t.test('should call filesCacheGet and return results', async function() {
reset()
let ctx = createContext()
const assertSiteName = 'benshapiro'
const assertResult = { a: 1 }
stubVerify.resolves(assertSiteName)
stubGetCache.returns(assertResult)
await routes.listFiles(ctx)
assert.ok(stubGetCache.called)
assert.strictEqual(stubGetCache.firstCall[0], assertSiteName)
assert.strictEqual(ctx.body, assertResult)
})
})
t.describe('#listPublicFiles()', function() {
const stubSitePublic = stub()
const stubGetCache = stub()
const routes = new MediaRoutes({
security: { throwIfNotPublic: stubSitePublic },
})
routes.filesCacheGet = stubGetCache
function reset() {
stubSitePublic.reset()
stubGetCache.reset()
}
t.test('should call security correctly', async function() {
reset()
let ctx = createContext()
const assertError = new Error('temp')
const assertSite = 'astalavista'
stubSitePublic.throws(assertError)
ctx.params.site = assertSite
let err = await assert.isRejected(routes.listPublicFiles(ctx))
assert.ok(stubSitePublic.called)
assert.strictEqual(err, assertError)
assert.strictEqual(stubSitePublic.firstCall[0], assertSite)
})
t.test('should call filesCacheGet and return results', async function() {
reset()
let ctx = createContext()
const assertSiteName = 'benshapiro'
const assertResult = { a: 1 }
ctx.params.site = assertSiteName
stubGetCache.returns(assertResult)
await routes.listPublicFiles(ctx)
assert.ok(stubGetCache.called)
assert.strictEqual(stubGetCache.firstCall[0], assertSiteName)
assert.strictEqual(ctx.body, assertResult)
})
})
t.describe('#filesCacheAdd', function() {
t.test('should auto-create array of site and add file', async function() {
const routes = new MediaRoutes()
const assertName = 'asdf.png'
const assertSize = 1234
await routes.init()
assert.ok(routes.filesCacheGet('nonexisting'))
assert.ok(Array.isArray(routes.filesCacheGet('nonexisting')))
assert.strictEqual(routes.filesCacheGet('nonexisting').length, 0)
routes.filesCacheAdd('nonexisting', assertName, assertSize)
assert.strictEqual(routes.filesCacheGet('nonexisting').length, 1)
assert.strictEqual(routes.filesCacheGet('nonexisting')[0].name, assertName)
assert.strictEqual(routes.filesCacheGet('nonexisting')[0].size, assertSize)
})
})
t.describe('#upload', function() {
const stubVerify = stub()
const stubUpload = stub()
const stubStat = stub()
const routes = new MediaRoutes({
security: { verifyToken: stubVerify },
formidable: { uploadFile: stubUpload },
fs: { stat: stubStat },
})
function reset() {
stubVerify.reset()
stubUpload.reset()
stubStat.reset()
}
t.test('should call security correctly', async function() {
reset()
let ctx = createContext()
const assertError = new Error('temp')
stubVerify.rejects(assertError)
let err = await assert.isRejected(routes.upload(ctx))
assert.ok(stubVerify.called)
assert.strictEqual(err, assertError)
assert.strictEqual(stubVerify.firstCall[0], ctx)
})
t.test('should call upload correctly', async function() {
reset()
let ctx = createContext()
const assertSiteName = 'benshapiro'
const assertError = new Error('hello')
stubVerify.resolves(assertSiteName)
stubUpload.rejects(assertError)
let err = await assert.isRejected(routes.upload(ctx))
assert.ok(stubUpload.called)
assert.strictEqual(err, assertError)
assert.strictEqual(stubUpload.firstCall[0], ctx)
assert.strictEqual(stubUpload.firstCall[1], assertSiteName)
})
t.test('should otherwise set context status to 204 and file in result', async function() {
reset()
let ctx = createContext()
const assertSize = 1241412
const assertFilename = 'asdfsafd'
const assertSite = 'mario'
stubVerify.resolves(assertSite)
stubUpload.resolves({ filename: assertFilename })
stubStat.resolves({ size: assertSize })
await routes.upload(ctx)
assert.strictEqual(ctx.body.filename, assertFilename)
assert.strictEqual(ctx.body.path, `/${assertSite}/${assertFilename}`)
assert.ok(stubStat.called)
assert.strictEqual(stubStat.firstCall[0], `./public/${assertSite}/${assertFilename}`)
let filesFromCache = routes.filesCacheGet(assertSite)
assert.strictEqual(filesFromCache.length, 1)
assert.strictEqual(filesFromCache[0].name, assertFilename)
assert.strictEqual(filesFromCache[0].size, assertSize)
})
})
t.describe('#resize', function() {
const stubVerifyToken = stub()
const stubVerifyBody = stub()
const stubUpload = stub()
const stubSharp = stub()
const stubSharpResize = stub()
const stubSharpRotate = stub()
const stubSharpToFile = stub()
const stubSharpJpeg = stub()
const stubSharpPng = stub()
const stubSharpToBuffer = stub()
const stubStat = stub()
const routes = new MediaRoutes({
security: {
verifyToken: stubVerifyToken,
verifyBody: stubVerifyBody,
},
fs: { stat: stubStat },
formidable: { uploadFile: stubUpload },
sharp: stubSharp,
})
function reset() {
stubVerifyToken.reset()
stubVerifyBody.reset()
stubUpload.reset()
let def = {
toFile: stubSharpToFile,
jpeg: stubSharpJpeg,
png: stubSharpPng,
resize: stubSharpResize,
rotate: stubSharpRotate,
toBuffer: stubSharpToBuffer,
}
stubStat.reset()
stubStat.resolves({ size: 0 })
stubSharp.reset()
stubSharp.returns(def)
stubSharpToFile.reset()
stubSharpToFile.resolves()
stubSharpJpeg.reset()
stubSharpJpeg.returns(def)
stubSharpResize.reset()
stubSharpResize.returns(def)
stubSharpRotate.reset()
stubSharpRotate.returns(def)
stubSharpPng.reset()
stubSharpPng.returns(def)
stubSharpToBuffer.reset()
stubSharpToBuffer.resolves()
routes.siteCache.clear()
}
t.test('should call security verifyToken correctly', async function() {
reset()
let ctx = createContext({ req: { body: { }}})
const assertError = new Error('temp')
stubVerifyToken.rejects(assertError)
let err = await assert.isRejected(routes.resize(ctx))
assert.ok(stubVerifyToken.called)
assert.strictEqual(err, assertError)
assert.strictEqual(stubVerifyToken.firstCall[0], ctx)
})
t.test('should call upload correctly', async function() {
reset()
let ctx = createContext({ req: { body: { }}})
const assertSiteName = 'benshapiro'
const assertError = new Error('hello')
stubVerifyToken.resolves(assertSiteName)
stubUpload.rejects(assertError)
let err = await assert.isRejected(routes.resize(ctx))
assert.strictEqual(err, assertError)
assert.ok(stubUpload.called)
assert.strictEqual(stubUpload.firstCall[0], ctx)
assert.strictEqual(stubUpload.firstCall[1], assertSiteName)
})
t.test('should call security verifyBody correctly', async function() {
reset()
let ctx = createContext({ req: { body: { }}})
const assertError = new Error('temp')
stubUpload.resolves({ filename: 'bla' })
stubVerifyBody.throws(assertError)
let err = await assert.isRejected(routes.resize(ctx))
assert.strictEqual(err, assertError)
assert.ok(stubVerifyBody.called)
assert.strictEqual(stubVerifyBody.firstCall[0], ctx)
})
t.test('should otherwise return original in result', async function() {
reset()
let ctx = createContext({ req: { body: { }}})
const assertFilename = 'asdfsafd.png'
const assertSite = 'mario'
stubVerifyToken.resolves(assertSite)
stubUpload.resolves({ filename: assertFilename })
await routes.resize(ctx)
assert.notOk(stubSharp.called)
assert.strictEqual(ctx.body.original.filename, assertFilename)
assert.strictEqual(ctx.body.original.path, `/${assertSite}/${assertFilename}`)
})
t.test('should call sharp correctly if items are specified', async function() {
reset()
const assertKey = 'asdf'
const assertJpeg = { a: 1 }
const assertFilename = 'asdfsafd'
const assertSite = 'mario'
stubVerifyToken.resolves(assertSite)
stubUpload.resolves({ filename: assertFilename + '.png' })
let ctx = createContext({ req: { body: {
[assertKey]: {
format: 'jpeg',
}
}}})
ctx.req.body[assertKey].jpeg = assertJpeg
await routes.resize(ctx)
assert.ok(stubSharp.called)
assert.match(stubSharp.firstCall[0], new RegExp(`\/${assertSite}\/${assertFilename}\.png`))
assert.ok(stubSharpRotate.called)
assert.ok(stubSharpJpeg.called)
assert.strictEqual(stubSharpJpeg.firstCall[0], assertJpeg)
assert.ok(stubSharpToFile.called)
assert.match(stubSharpToFile.firstCall[0], new RegExp(`\/${assertSite}\/${assertFilename}_${assertKey}\.jpg`))
assert.notOk(stubSharpPng.called)
assert.notOk(stubSharpResize.called)
assert.strictEqual(ctx.body.original.filename, assertFilename + '.png')
assert.strictEqual(ctx.body.original.path, `/${assertSite}/${assertFilename}.png`)
assert.strictEqual(ctx.body[assertKey].filename, `${assertFilename}_${assertKey}\.jpg`)
assert.strictEqual(ctx.body[assertKey].path, `/${assertSite}/${assertFilename}_${assertKey}.jpg`)
})
t.test('should call sharp correctly if items and resize are specified', async function() {
reset()
const assertKey = 'herpderp'
const assertPng = { a: 1 }
const assertResize = { a: 1 }
const assertFilename = 'asdfsafd'
const assertSite = 'mario'
stubVerifyToken.resolves(assertSite)
stubUpload.resolves({ filename: assertFilename + '.png' })
let called = 0
stubStat.returnWith(function() {
called += 10
return { size: called }
})
let ctx = createContext({ req: { body: {
[assertKey]: {
format: 'png',
}
}}})
ctx.req.body[assertKey].png = assertPng
ctx.req.body[assertKey].resize = assertResize
await routes.resize(ctx)
assert.ok(stubSharp.called)
assert.match(stubSharp.firstCall[0], new RegExp(`\/${assertSite}\/${assertFilename}\.png`))
assert.ok(stubSharpRotate.called)
assert.ok(stubSharpPng.called)
assert.strictEqual(stubSharpPng.firstCall[0], assertPng)
assert.ok(stubSharpToFile.called)
assert.match(stubSharpToFile.firstCall[0], new RegExp(`\/${assertSite}\/${assertFilename}_${assertKey}\.png`))
assert.notOk(stubSharpJpeg.called)
assert.ok(stubSharpResize.called)
assert.strictEqual(stubSharpResize.firstCall[0], assertResize)
assert.strictEqual(ctx.body.original.filename, assertFilename + '.png')
assert.strictEqual(ctx.body.original.path, `/${assertSite}/${assertFilename}.png`)
assert.strictEqual(ctx.body[assertKey].filename, `${assertFilename}_${assertKey}\.png`)
assert.strictEqual(ctx.body[assertKey].path, `/${assertSite}/${assertFilename}_${assertKey}.png`)
let filesFromCache = routes.filesCacheGet(assertSite)
assert.strictEqual(filesFromCache.length, 2)
assert.strictEqual(filesFromCache[0].name, `${assertFilename}_${assertKey}\.png`)
assert.strictEqual(filesFromCache[0].size, 20)
assert.strictEqual(filesFromCache[1].name, assertFilename + '.png')
assert.strictEqual(filesFromCache[1].size, 10)
})
t.test('should notify which item failed if one fails', async function() {
reset()
const assertValidKey1 = 'herp'
const assertValidKey2 = 'derp'
const assertErrorKey = 'throwmyerr'
const assertErrorMessage = 'some message here'
stubVerifyToken.resolves('asdf')
stubUpload.resolves({ filename: 'file.png' })
let called = 0
stubStat.returnWith(function() {
called += 10
return { size: called }
})
let ctx = createContext({ req: { body: {
[assertValidKey1]: {
format: 'png',
png: { a: 1 },
},
[assertValidKey2]: {
format: 'png',
png: { a: 1 },
},
[assertErrorKey]: {
format: 'png',
png: { a: 1 },
},
}}})
stubSharpToFile.returnWith(function(file) {
if (file.match(new RegExp(assertErrorKey))) {
throw new Error(assertErrorMessage)
}
})
let err = await assert.isRejected(routes.resize(ctx))
assert.ok(err instanceof HttpError)
assert.ok(err instanceof Error)
assert.strictEqual(err.status, 422)
assert.match(err.message, new RegExp(assertErrorKey))
assert.match(err.message, new RegExp(assertErrorMessage))
})
t.test('should call sharp correctly and return base64 format if out is base64', async function() {
reset()
const assertKey = 'outtest'
const assertFilename = 'asdfsafd.png'
const assertSite = 'mario'
const assertBase64Data = 'asdf1234'
stubVerifyToken.resolves(assertSite)
stubUpload.resolves({ filename: assertFilename })
let ctx = createContext({ req: { body: {
[assertKey]: {
format: 'png',
png: { a: 1 },
out: 'base64',
}
}}})
stubSharpToBuffer.resolves(Buffer.from(assertBase64Data))
await routes.resize(ctx)
assert.ok(stubSharp.called)
assert.notOk(stubSharpToFile.called)
assert.ok(stubSharpToBuffer.called)
assert.ok(ctx.body[assertKey].base64)
assert.ok(ctx.body[assertKey].base64.startsWith(`data:image/png;base64,`))
let base64 = ctx.body[assertKey].base64
let bufferBase64 = Buffer.from(base64.slice(base64.indexOf(',')), 'base64')
assert.strictEqual(bufferBase64.toString(), assertBase64Data)
let filesFromCache = routes.filesCacheGet(assertSite)
assert.strictEqual(filesFromCache.length, 1)
assert.strictEqual(filesFromCache[0].name, assertFilename)
})
})