Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🥅 improve error handling for decode failures, add tests #3

Merged
merged 3 commits into from
May 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,16 @@ module.exports = function (Adapter) {
if (error)
return error.code === 'ENOENT' ? resolve() : reject(error)

record = msgpack.decode(buffer)
if(buffer.length === 0) {
return reject(new Error(`Decode record failed. File is empty: ${filePath}`))
}
else {
try {
record = msgpack.decode(buffer)
} catch (e) {
return reject(new Error(`Decode record failed. File is corrupt: ${filePath}`, { cause: e }))
}
}

if (!(type in self.db)) self.db[type] = {}

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"lint": "eslint index.js",
"postpublish": "npm run tag",
"tag": "git tag `npm v fortune-fs version` && git push origin --tags",
"test": "npm run lint && node test.js"
"test": "npm run lint && node test/test.js"
},
"dependencies": {
"lockfile": "^1.0.4",
Expand Down
22 changes: 0 additions & 22 deletions test.js

This file was deleted.

1 change: 1 addition & 0 deletions test/corrupt-file
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
‚¢id£bar
Empty file added test/empty-file
Empty file.
111 changes: 111 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
'use strict'

var testAdapter = require('fortune/test/adapter')
var fsAdapter = require('../index')
const fortune = require('fortune')
const fs = require('node:fs')
const run = require('tapdance')

testAdapter(fsAdapter)

run((assert, comment) => {
comment('concurrentReads validation')

const concurrentReads = 1

const store = fortune({}, {
adapter: [fsAdapter, { concurrentReads }],
})

assert(store.adapter.options.concurrentReads === concurrentReads, `adapter has expected concurrentReads value --- expected: ${store.adapter.options.concurrentReads} --- actual: ${concurrentReads}`)

let thrown = false
let expectedError

try {
fortune({}, {
adapter: [fsAdapter, { concurrentReads: 0 }],
})
} catch (e) {
thrown = true
expectedError = e.message === 'concurrentReads must be > 0'
if(!expectedError) {
// only log the error if it was something we did not expect
console.error(e)
}
}

assert(thrown, 'concurrentReads 0 is not valid')
assert(expectedError, 'got expected error for concurrentReads 0')
});

(async () => {

run(async (assert, comment) => {
comment('msgpack decode validation')

const type = 'foo'
const schema = {}
schema[type] = { bar: Boolean }

const store = fortune(
schema,
{ adapter: [fsAdapter] })

const emptyID = 1
const validID = 3
const corruptID = 6

fs.mkdirSync(`db/${type}`, { recursive: true })
fs.copyFileSync('test/empty-file', `db/${type}/${emptyID}`)
fs.copyFileSync('test/valid-file', `db/${type}/${validID}`)
fs.copyFileSync('test/corrupt-file', `db/${type}/${corruptID}`)

let error = null

try {
await store.find(type, [emptyID])
} catch (e) {
error = e
}

assert(error.message.includes('Decode record failed. File is empty'), `empty error message is present: ${error.message}`)

error = null

try {
await store.find(type, [corruptID])
} catch (e) {
error = e
}

assert(error.message.includes('Decode record failed. File is corrupt'), `corrupt error message is present ${error.message}`)

let result = await store.find(type, [validID])
assert(result.payload.records.length === 1, 'valid record is found')

error = null

try {
await store.update(type, [{ id: emptyID }])
} catch (e) {
error = e
}

assert(error, 'trying to update an empty file fails: ' + error)

error = null

try {
await store.update(type, [{ id: corruptID }])
} catch (e) {
error = e
}

assert(error, 'trying to update a corrupt file fails: ' + error)

result = await store.create(type, [{ id: emptyID }, {id: corruptID}])
assert(result.payload.records.length === 2, 'successfully replaced empty and corrupt files via store.create()')
})

})()
1 change: 1 addition & 0 deletions test/valid-file
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
‚¢id£barÃ
Loading