-
-
Notifications
You must be signed in to change notification settings - Fork 60
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
70faceb
commit 2cc2d90
Showing
2 changed files
with
162 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
import { has, get, info, remove, generateKey } from '../cache' | ||
import mock from 'mock-fs' | ||
|
||
describe('cache', () => { | ||
afterAll(() => { | ||
mock.restore() | ||
}) | ||
|
||
describe('has', () => { | ||
it('returns true if file is present', async () => { | ||
mock({ | ||
'/cache': { | ||
'test.png': 'foobar' | ||
} | ||
}) | ||
|
||
expect(await has('/cache', 'test.png')).toBeTruthy() | ||
}) | ||
|
||
it('returns false if the file is missing', async () => { | ||
mock({}) | ||
|
||
expect(await has('/cache', 'test.png')).toBeFalsy() | ||
}) | ||
}) | ||
|
||
describe('get', () => { | ||
it('returns the data', async () => { | ||
mock({ | ||
'/cache': { | ||
'test.png': Buffer.from('foobar') | ||
} | ||
}) | ||
|
||
const res = await get('/cache', 'test.png') | ||
expect(res).toHaveProperty('data', Buffer.from('foobar')) | ||
}) | ||
|
||
it('returns the metadata if metadata file is present', async () => { | ||
mock({ | ||
'/cache': { | ||
'test.png': Buffer.from('foobar'), | ||
'test.png.json': JSON.stringify({ foo: 'bar' }) | ||
} | ||
}) | ||
|
||
const res = await get('/cache', 'test.png') | ||
|
||
expect(res).toHaveProperty('data', Buffer.from('foobar')) | ||
expect(res).toHaveProperty('metadata', { foo: 'bar' }) | ||
}) | ||
|
||
it('returns an empty object if metadata file is missing', async () => { | ||
mock({ | ||
'/cache': { | ||
'test.png': Buffer.from('foobar') | ||
} | ||
}) | ||
|
||
const res = await get('/cache', 'test.png') | ||
|
||
expect(res).toHaveProperty('data', Buffer.from('foobar')) | ||
expect(res).toHaveProperty('metadata', {}) | ||
}) | ||
|
||
it('throws if no image is found', async (done) => { | ||
mock({}) | ||
|
||
try { | ||
await get('/cache', 'test.png') | ||
fail() | ||
} catch { | ||
done() | ||
} | ||
}) | ||
}) | ||
|
||
describe('info', () => { | ||
it('returns an object if metadata file is present', async () => { | ||
mock({ | ||
'/cache': { | ||
'test.png.json': JSON.stringify({ foo: 'bar' }) | ||
} | ||
}) | ||
|
||
const res = await info('/cache', 'test.png') | ||
|
||
expect(res).toHaveProperty('foo', 'bar') | ||
}) | ||
|
||
it('throws if not metadata file is found', async (done) => { | ||
mock({}) | ||
|
||
try { | ||
await info('/cache', 'test.png') | ||
fail() | ||
} catch { | ||
done() | ||
} | ||
}) | ||
}) | ||
|
||
describe('remove', () => { | ||
it('removes the image file', () => { }) | ||
it('removes the metadata file if present', () => { }) | ||
it('throws if no image is found', () => { }) | ||
}) | ||
|
||
describe('generateKey', () => { | ||
it('returns a string', () => { }) | ||
test('returned string has file ending', () => { }) | ||
test('returned file ending matches config', () => { }) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import { mkdir, readFile, writeFile, stat, unlink } from 'fs/promises' | ||
import { join, extname } from 'path' | ||
|
||
export async function has(cachePath: string, key: string): Promise<boolean> { | ||
try { | ||
const file = await stat(join(cachePath, key)) | ||
return file.isFile() | ||
} catch { | ||
return false | ||
} | ||
} | ||
|
||
export async function get(cachePath: string, key: string): Promise<{ data: Uint8Array, metadata: Record<string, any> }> { | ||
const [data, metadata] = await Promise.all([ | ||
readFile(join(cachePath, key)), | ||
has(cachePath, key + '.json').then(has => has ? info(cachePath, key) : {}) | ||
]) | ||
|
||
return { data, metadata } | ||
} | ||
|
||
export async function info(cachePath: string, key: string): Promise<Record<string, any>> { | ||
const rawMeta = await readFile(join(cachePath, key + '.json'), 'utf-8') | ||
return JSON.parse(rawMeta) | ||
} | ||
|
||
export async function put(cachePath: string, key: string, data: Uint8Array, metadata?: Record<string, any>): Promise<void> { | ||
await mkdir(cachePath, { recursive: true }) | ||
|
||
await Promise.all([ | ||
writeFile(join(cachePath, key), data), | ||
metadata ? writeFile(join(cachePath, key + '.json'), JSON.stringify(metadata)) : undefined | ||
]) | ||
} | ||
|
||
export async function remove(cachePath: string, key: string): Promise<void> { | ||
await Promise.all([ | ||
unlink(join(cachePath, key)), | ||
has(cachePath, key + '.json').then(has => has ? unlink(join(cachePath, key + '.json')) : undefined) | ||
]) | ||
} | ||
|
||
export function generateKey(url: URL, config: Record<string, any>) { | ||
const name = Buffer.from(JSON.stringify(config)).toString('base64') | ||
const ext = config.format ? `.${config.format}` : extname(url.pathname) | ||
|
||
return name + ext | ||
} |