fs-cache-fast/test/fscache.test.mjs

340 lines
12 KiB
JavaScript

import { Eltro as t, assert, spy } from 'eltro'
import path from 'path'
import crypto from 'crypto'
import os from 'os'
import fsSyncOriginal from 'fs'
import fsPromisesOriginal from 'fs/promises'
import Cache from '../index.mjs'
import { fakeFs, fakeFsPromises, fakeFsSync } from './helper.mjs'
let fsSync
let fsPromises
t.beforeEach(function() {
fsSync = fakeFsSync()
fsPromises = fakeFsPromises()
})
function createCache(opts) {
return new Cache(opts, fsSync, fsPromises)
}
t.describe('#constructor()', function() {
t.test('uses default fs', function() {
let cache = new Cache({})
assert.strictEqual(cache.fsSync, fsSyncOriginal)
assert.strictEqual(cache.fsPromises, fsPromisesOriginal)
})
t.test('should be able to override the fs', function() {
let cache = createCache({})
assert.strictEqual(cache.fsSync, fsSync)
assert.strictEqual(cache.fsPromises, fsPromises)
})
t.test('comes with default options', function() {
let cache = createCache({})
assert.ok(cache.id)
assert.strictEqual(cache.parse_json, true)
assert.strictEqual(cache.prefix, '')
assert.strictEqual(cache.hash_alg, 'md5')
assert.strictEqual(cache.cache_dir, path.join(os.tmpdir(), cache.id))
})
t.test('can overwrite options', function() {
const assertHash = 'sha256'
const assertDir = '/something/else'
const assertPrefix = 'blabla'
const assertParseJson = false
let cache = createCache({
prefix: assertPrefix,
hash_alg: assertHash,
cache_dir: assertDir,
parse_json: assertParseJson,
})
assert.ok(cache.id)
assert.strictEqual(cache.parse_json, assertParseJson)
assert.strictEqual(cache.prefix, assertPrefix + '-')
assert.strictEqual(cache.hash_alg, assertHash)
assert.strictEqual(cache.cache_dir, assertDir)
})
t.test('should create the directory by default', function() {
assert.notOk(fsSync.mkdirSync.called)
let cache = createCache({})
assert.ok(fsSync.mkdirSync.called)
assert.strictEqual(fsSync.mkdirSync.firstCall[0], cache.cache_dir)
assert.strictEqual(fsSync.mkdirSync.firstCall[1]?.recursive, true)
})
t.test('should check if hash_alg is valid', function() {
assert.throws(function() {
createCache({ hash_alg: 'dafdsagasdgwa4e' })
})
})
})
t.describe('FSCache', function() {
t.describe('#hash()', function() {
t.test('should use cache hasher to hash string', function() {
let cache = createCache({ hash_alg: 'sha256' })
assert.strictEqual(cache.hash('asdf'), crypto.hash('sha256', 'asdf'))
cache = createCache({ hash_alg: 'md5' })
assert.strictEqual(cache.hash('asdf'), crypto.hash('md5', 'asdf'))
})
})
t.describe('#_parseCacheData()', function() {
t.test('should default parse as json', function() {
let cache = createCache()
let output = cache._parseCacheData('{"hello":"world"}')
assert.strictEqual(typeof output, 'object')
assert.strictEqual(output.hello, 'world')
})
t.test('can be overwritten in options', function() {
let cache = createCache({ parse_json: false })
let output = cache._parseCacheData('{"hello":"world"}')
assert.strictEqual(typeof output, 'string')
assert.strictEqual(output, '{"hello":"world"}')
})
t.test('can be overwritten in parameter', function() {
let cache = createCache()
let output = cache._parseCacheData('{"hello":"world"}', { parse_json: false })
assert.strictEqual(typeof output, 'string')
assert.strictEqual(output, '{"hello":"world"}')
})
})
t.describe('#_parseSetData()', function() {
t.test('should default stringify to json', function() {
let cache = createCache()
let output = cache._parseSetData({ hello: 'world' })
assert.strictEqual(typeof output, 'string')
assert.strictEqual(output, '{"hello":"world"}')
})
t.test('can be overwritten in options', function() {
let cache = createCache({ parse_json: false })
let output = cache._parseSetData('Hello world')
assert.strictEqual(typeof output, 'string')
assert.strictEqual(output, 'Hello world')
})
t.test('can be overwritten in parameter', function() {
let cache = createCache()
let output = cache._parseSetData('Hello world', { parse_json: false })
assert.strictEqual(typeof output, 'string')
assert.strictEqual(output, 'Hello world')
})
})
t.describe('#get()', function() {
t.test('should call promise readFile and parse result', async function() {
const assertKey = 'asdf1234'
const assertContent = '{"hello":"world"}'
const assertResult = { hello: 'world' }
let cache = createCache()
fsPromises.readFile.resolves(assertContent)
cache._parseCacheData = spy().returns(assertResult)
let output = await cache.get(assertKey)
assert.strictEqual(output, assertResult)
assert.ok(fsPromises.readFile.called)
assert.strictEqual(fsPromises.readFile.firstCall[0], path.join(cache.cache_dir, cache.hash(assertKey)))
assert.strictEqual(fsPromises.readFile.firstCall[1]?.encoding, 'utf8')
assert.ok(cache._parseCacheData.called)
assert.ok(cache._parseCacheData.firstCall[0], assertContent)
})
t.test('should pass extra options to the parser', async function() {
const assertOptions = { a: 1 }
let cache = createCache()
cache._parseCacheData = spy()
await cache.get('asdf', null, assertOptions)
assert.ok(cache._parseCacheData.called)
assert.ok(cache._parseCacheData.firstCall[1], assertOptions)
})
t.test('should support fallback value if file does not exist', async function() {
const assertFallback = { a: 1 }
let cache = createCache()
fsPromises.readFile.rejects(new Error('asdf'))
cache._parseCacheData = spy()
let output = await cache.get('bla', assertFallback)
assert.strictEqual(output, assertFallback)
assert.notOk(cache._parseCacheData.called)
})
t.test('parser error should propogate', async function() {
const assertError = new Error('Hello')
let cache = createCache()
cache._parseCacheData = spy().throws(assertError)
let err = await assert.isRejected(cache.get('asdf'))
assert.strictEqual(err, assertError)
})
})
t.describe('#getSync()', function() {
t.test('should call sync readFile and parse result', function() {
const assertKey = 'asdf1234'
const assertContent = '{"hello":"world"}'
const assertResult = { hello: 'world' }
let cache = createCache()
fsSync.readFileSync.returns(assertContent)
cache._parseCacheData = spy().returns(assertResult)
let output = cache.getSync(assertKey)
assert.strictEqual(output, assertResult)
assert.ok(fsSync.readFileSync.called)
assert.strictEqual(fsSync.readFileSync.firstCall[0], path.join(cache.cache_dir, cache.hash(assertKey)))
assert.strictEqual(fsSync.readFileSync.firstCall[1]?.encoding, 'utf8')
assert.ok(cache._parseCacheData.called)
assert.ok(cache._parseCacheData.firstCall[0], assertContent)
})
t.test('should pass extra options to the parser', function() {
const assertOptions = { a: 1 }
let cache = createCache()
cache._parseCacheData = spy()
cache.getSync('asdf', null, assertOptions)
assert.ok(cache._parseCacheData.called)
assert.ok(cache._parseCacheData.firstCall[1], assertOptions)
})
t.test('should support fallback value if file does not exist', function() {
const assertFallback = { a: 1 }
let cache = createCache()
fsSync.readFileSync.throws(new Error('asdf'))
cache._parseCacheData = spy()
let output = cache.getSync('bla', assertFallback)
assert.strictEqual(output, assertFallback)
assert.notOk(cache._parseCacheData.called)
})
t.test('parser error should propogate', async function() {
const assertError = new Error('Hello')
let cache = createCache()
cache._parseCacheData = spy().throws(assertError)
assert.throws(function() {
cache.getSync('asdf')
}, assertError)
})
})
t.describe('#set()', function() {
t.test('should call promise writeFile', async function() {
const assertKey = 'asdf1234'
const assertInput = { hello: 'world' }
const assertContent = JSON.stringify(assertInput)
let cache = createCache()
cache._parseSetData = spy().returns(assertContent)
await cache.set(assertKey, assertInput)
assert.ok(fsPromises.writeFile.called)
assert.strictEqual(fsPromises.writeFile.firstCall[0], path.join(cache.cache_dir, cache.hash(assertKey)))
assert.strictEqual(fsPromises.writeFile.firstCall[1], assertContent)
assert.strictEqual(fsPromises.writeFile.firstCall[2]?.encoding, 'utf8')
assert.ok(cache._parseSetData.called)
assert.ok(cache._parseSetData.firstCall[0], assertInput)
})
t.test('should pass extra options to the parser', async function() {
const assertOptions = { a: 1 }
let cache = createCache()
cache._parseSetData = spy()
await cache.set('asdf', null, assertOptions)
assert.ok(cache._parseSetData.called)
assert.ok(cache._parseSetData.firstCall[1], assertOptions)
})
t.test('should pass extra options to the parser', async function() {
const assertEncoding = 'asdf'
let cache = createCache()
await cache.set('asdf', null, { encoding: assertEncoding })
assert.strictEqual(fsPromises.writeFile.firstCall[2]?.encoding, assertEncoding)
})
t.test('parse error should reject properly', async function() {
const assertError = new Error('what is up')
let cache = createCache()
cache._parseSetData = spy().throws(assertError)
// make sure it's properly promise wrapped
let inbetween = cache.set('asdf')
let err = await assert.isRejected(inbetween)
assert.strictEqual(err, assertError)
})
})
t.describe('#setSync()', function() {
t.test('should call sync writeFileSync', function() {
const assertKey = 'asdf1234'
const assertInput = { hello: 'world' }
const assertContent = JSON.stringify(assertInput)
let cache = createCache()
cache._parseSetData = spy().returns(assertContent)
cache.setSync(assertKey, assertInput)
assert.ok(fsSync.writeFileSync.called)
assert.strictEqual(fsSync.writeFileSync.firstCall[0], path.join(cache.cache_dir, cache.hash(assertKey)))
assert.strictEqual(fsSync.writeFileSync.firstCall[1], assertContent)
assert.strictEqual(fsSync.writeFileSync.firstCall[2]?.encoding, 'utf8')
assert.ok(cache._parseSetData.called)
assert.ok(cache._parseSetData.firstCall[0], assertInput)
})
t.test('should pass extra options to the parser', function() {
const assertOptions = { a: 1 }
let cache = createCache()
cache._parseSetData = spy()
cache.setSync('asdf', null, assertOptions)
assert.ok(cache._parseSetData.called)
assert.ok(cache._parseSetData.firstCall[1], assertOptions)
})
t.test('should pass extra options to the parser', function() {
const assertEncoding = 'asdf'
let cache = createCache()
cache.setSync('asdf', null, { encoding: assertEncoding })
assert.strictEqual(fsSync.writeFileSync.firstCall[2]?.encoding, assertEncoding)
})
t.test('parse error should throw', function() {
const assertError = new Error('what is up')
let cache = createCache()
cache._parseSetData = spy().throws(assertError)
assert.throws(function() {
cache.setSync('asdf')
}, assertError)
})
})
})