Skip to content

Commit 5390048

Browse files
ruyadornoisaacs
authored andcommittedOct 28, 2019
test: Add to lib/verify.js test coverage
- Adds missing tests for unknown errors when validating, checking sri streams and rebuilding buckets - Add checks for hash collisions - Brings test coverage of `lib/verify.js` to 100% PR-URL: #24 Credit: @ruyadorno Close: #24 Reviewed-by: @isaacs
1 parent fee725d commit 5390048

File tree

2 files changed

+159
-1
lines changed

2 files changed

+159
-1
lines changed
 

‎lib/verify.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ function verify (cache, opts) {
5050

5151
return steps
5252
.reduce((promise, step, i) => {
53-
const label = step.name || `step #${i}`
53+
const label = step.name
5454
const start = new Date()
5555
return promise.then((stats) => {
5656
return step(cache, opts).then((s) => {
@@ -208,6 +208,7 @@ function rebuildIndex (cache, opts) {
208208
}
209209
const buckets = {}
210210
for (const k in entries) {
211+
/* istanbul ignore else */
211212
if (hasOwnProperty(entries, k)) {
212213
const hashed = index.hashKey(k)
213214
const entry = entries[k]

‎test/verify.js

+157
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const index = require('../lib/entry-index')
77
const fs = require('graceful-fs')
88
const path = require('path')
99
const Tacks = require('tacks')
10+
const requireInject = require('require-inject')
1011
const { test } = require('tap')
1112
const testDir = require('./util/test-dir')(__filename)
1213
const ssri = require('ssri')
@@ -29,6 +30,13 @@ const stat = util.promisify(fs.stat)
2930
const appendFile = util.promisify(fs.appendFile)
3031
const writeFile = util.promisify(fs.writeFile)
3132

33+
// defines reusable errors
34+
const genericError = new Error('ERR')
35+
genericError.code = 'ERR'
36+
37+
// helpers
38+
const getVerify = (opts) => requireInject('../lib/verify', opts)
39+
3240
function mockCache () {
3341
const fixture = new Tacks(
3442
CacheContent({
@@ -264,6 +272,93 @@ test('writes a file with last verification time', (t) => {
264272

265273
test('fixes permissions and users on cache contents')
266274

275+
test('missing file error when validating cache content', (t) => {
276+
const missingFileError = new Error('ENOENT')
277+
missingFileError.code = 'ENOENT'
278+
const mockVerify = getVerify({
279+
'graceful-fs': Object.assign({}, fs, {
280+
stat: (path, cb) => {
281+
cb(missingFileError)
282+
}
283+
})
284+
})
285+
286+
t.plan(1)
287+
mockCache().then(() => {
288+
t.resolveMatch(
289+
mockVerify(CACHE),
290+
{
291+
verifiedContent: 0,
292+
rejectedEntries: 1,
293+
totalEntries: 0
294+
},
295+
'should reject entry'
296+
)
297+
})
298+
})
299+
300+
test('unknown error when validating content', (t) => {
301+
const mockVerify = getVerify({
302+
'graceful-fs': Object.assign({}, fs, {
303+
stat: (path, cb) => {
304+
cb(genericError)
305+
}
306+
})
307+
})
308+
309+
t.plan(1)
310+
mockCache().then(() => {
311+
t.rejects(
312+
mockVerify(CACHE),
313+
genericError,
314+
'should throw any unknown errors'
315+
)
316+
})
317+
})
318+
319+
test('unknown error when checking sri stream', (t) => {
320+
const mockVerify = getVerify({
321+
ssri: Object.assign({}, ssri, {
322+
checkStream: () => Promise.reject(genericError)
323+
})
324+
})
325+
326+
t.plan(1)
327+
mockCache().then(() => {
328+
t.rejects(
329+
mockVerify(CACHE),
330+
genericError,
331+
'should throw any unknown errors'
332+
)
333+
})
334+
})
335+
336+
test('unknown error when rebuilding bucket', (t) => {
337+
// rebuild bucket uses stat after content-validation
338+
// shouldFail controls the right time to mock the error
339+
let shouldFail = false
340+
const mockVerify = getVerify({
341+
'graceful-fs': Object.assign({}, fs, {
342+
stat: (path, cb) => {
343+
if (shouldFail) {
344+
return cb(genericError)
345+
}
346+
fs.stat(path, cb)
347+
shouldFail = true
348+
}
349+
})
350+
})
351+
352+
t.plan(1)
353+
mockCache().then(() => {
354+
t.rejects(
355+
mockVerify(CACHE),
356+
genericError,
357+
'should throw any unknown errors'
358+
)
359+
})
360+
})
361+
267362
test('re-builds the index with the size parameter', (t) => {
268363
const KEY2 = KEY + 'aaa'
269364
const KEY3 = KEY + 'bbb'
@@ -312,3 +407,65 @@ test('re-builds the index with the size parameter', (t) => {
312407
})
313408
})
314409
})
410+
411+
test('hash collisions', (t) => {
412+
const mockVerify = getVerify({
413+
'../lib/entry-index': Object.assign({}, index, {
414+
hashKey: () => 'aaa'
415+
})
416+
})
417+
418+
t.plan(1)
419+
mockCache()
420+
.then(() =>
421+
index.insert(CACHE, 'foo', INTEGRITY, {
422+
metadata: 'foo'
423+
}))
424+
.then(() => mockVerify(CACHE))
425+
.then((stats) => {
426+
t.deepEqual(
427+
{
428+
verifiedContent: stats.verifiedContent,
429+
rejectedEntries: stats.rejectedEntries,
430+
totalEntries: stats.totalEntries
431+
},
432+
{
433+
verifiedContent: 1,
434+
rejectedEntries: 0,
435+
totalEntries: 2
436+
},
437+
'should resolve with no errors'
438+
)
439+
})
440+
})
441+
442+
test('hash collisions excluded', (t) => {
443+
const mockVerify = getVerify({
444+
'../lib/entry-index': Object.assign({}, index, {
445+
hashKey: () => 'aaa'
446+
})
447+
})
448+
449+
t.plan(1)
450+
mockCache()
451+
.then(() =>
452+
index.insert(CACHE, 'foo', INTEGRITY, {
453+
metadata: 'foo'
454+
}))
455+
.then(() => mockVerify(CACHE, { filter: () => null }))
456+
.then((stats) => {
457+
t.deepEqual(
458+
{
459+
verifiedContent: stats.verifiedContent,
460+
rejectedEntries: stats.rejectedEntries,
461+
totalEntries: stats.totalEntries
462+
},
463+
{
464+
verifiedContent: 0,
465+
rejectedEntries: 2,
466+
totalEntries: 0
467+
},
468+
'should resolve while also excluding filtered out entries'
469+
)
470+
})
471+
})

0 commit comments

Comments
 (0)
Please sign in to comment.