Skip to content

Commit 7046fe1

Browse files
nlfisaacs
authored andcommitted
tests for npm cache command, and 2 tiny bugfixes
* Attach EUSAGE code to usage errors * add verify to completions PR-URL: #2122 Credit: @nlf Close: #2122 Reviewed-by: @isaacs
1 parent f0efe96 commit 7046fe1

File tree

2 files changed

+242
-10
lines changed

2 files changed

+242
-10
lines changed

lib/cache.js

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@ const usage = usageUtil('cache',
2222
const completion = (opts, cb) => {
2323
const argv = opts.conf.argv.remain
2424
if (argv.length === 2)
25-
return cb(null, ['add', 'clean'])
25+
return cb(null, ['add', 'clean', 'verify'])
2626

2727
// TODO - eventually...
2828
switch (argv[2]) {
29+
case 'verify':
2930
case 'clean':
3031
case 'add':
3132
return cb(null, [])
@@ -40,11 +41,11 @@ const cache = async (args) => {
4041
case 'rm': case 'clear': case 'clean':
4142
return await clean(args)
4243
case 'add':
43-
return await add(args, npm.prefix)
44+
return await add(args)
4445
case 'verify': case 'check':
4546
return await verify()
4647
default:
47-
throw usage
48+
throw Object.assign(new Error(usage), { code: 'EUSAGE' })
4849
}
4950
}
5051

@@ -77,22 +78,21 @@ with --force.`)
7778
// npm cache add <pkg> <ver>
7879
// npm cache add <tarball>
7980
// npm cache add <folder>
80-
const add = async (args, where) => {
81+
const add = async (args) => {
8182
const usage = 'Usage:\n' +
8283
' npm cache add <tarball-url>\n' +
8384
' npm cache add <pkg>@<ver>\n' +
8485
' npm cache add <tarball>\n' +
8586
' npm cache add <folder>\n'
8687
log.silly('cache add', 'args', args)
87-
const spec = args[0] +
88+
const spec = args[0] && args[0] +
8889
(args[1] === undefined || args[1] === null ? '' : `@${args[1]}`)
8990

90-
log.verbose('cache add', 'spec', spec)
9191
if (!spec)
92-
throw new Error(usage)
92+
throw Object.assign(new Error(usage), { code: 'EUSAGE' })
9393

94-
log.silly('cache add', 'parsed spec', spec)
95-
const opts = { ...npm.flatOptions, where }
94+
log.silly('cache add', 'spec', spec)
95+
const opts = { ...npm.flatOptions }
9696

9797
// we ask pacote for the thing, and then just throw the data
9898
// away so that it tee-pipes it into the cache like it does
@@ -109,7 +109,7 @@ const verify = async () => {
109109
? `~${cache.substr(process.env.HOME.length)}`
110110
: cache
111111
const stats = await cacache.verify(cache)
112-
output(`Cache verified and compressed (${prefix}):`)
112+
output(`Cache verified and compressed (${prefix})`)
113113
output(`Content verified: ${stats.verifiedContent} (${stats.keptSize} bytes)`)
114114
stats.badContentCount && output(`Corrupted content removed: ${stats.badContentCount}`)
115115
stats.reclaimedCount && output(`Content garbage-collected: ${stats.reclaimedCount} (${stats.reclaimedSize} bytes)`)

test/lib/cache.js

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
const t = require('tap')
2+
const requireInject = require('require-inject')
3+
const path = require('path')
4+
5+
const usageUtil = () => 'usage instructions'
6+
7+
const flatOptions = {
8+
force: false
9+
}
10+
11+
const npm = {
12+
flatOptions,
13+
cache: '/fake/path'
14+
}
15+
16+
let rimrafPath = ''
17+
const rimraf = (path, cb) => {
18+
rimrafPath = path
19+
return cb()
20+
}
21+
22+
let logOutput = []
23+
const npmlog = {
24+
silly: (...args) => {
25+
logOutput.push(['silly', ...args])
26+
}
27+
}
28+
29+
let tarballStreamSpec = ''
30+
let tarballStreamOpts = {}
31+
const pacote = {
32+
tarball: {
33+
stream: (spec, cb, opts) => {
34+
tarballStreamSpec = spec
35+
tarballStreamOpts = opts
36+
return cb({
37+
resume: () => {},
38+
promise: () => Promise.resolve()
39+
})
40+
}
41+
}
42+
}
43+
44+
let outputOutput = []
45+
const output = (msg) => {
46+
outputOutput.push(msg)
47+
}
48+
49+
let cacacheVerifyPath = ''
50+
const cacacheVerifyStats = {
51+
keptSize: 100,
52+
verifiedContent: 1,
53+
totalEntries: 1,
54+
runTime: { total: 2000 }
55+
}
56+
const cacache = {
57+
verify: (path) => {
58+
cacacheVerifyPath = path
59+
return cacacheVerifyStats
60+
}
61+
}
62+
63+
const mocks = {
64+
cacache,
65+
npmlog,
66+
pacote,
67+
rimraf,
68+
'../../lib/npm.js': npm,
69+
'../../lib/utils/output.js': output,
70+
'../../lib/utils/usage.js': usageUtil
71+
}
72+
73+
const cache = requireInject('../../lib/cache.js', mocks)
74+
75+
t.test('cache no args', t => {
76+
cache([], err => {
77+
t.equal(err.message, 'usage instructions', 'should throw usage instructions')
78+
t.end()
79+
})
80+
})
81+
82+
t.test('cache clean', t => {
83+
cache(['clean'], err => {
84+
t.match(err.message, 'the npm cache self-heals', 'should throw warning')
85+
t.end()
86+
})
87+
})
88+
89+
t.test('cache clean (force)', t => {
90+
flatOptions.force = true
91+
t.teardown(() => {
92+
rimrafPath = ''
93+
flatOptions.force = false
94+
})
95+
96+
cache(['clear'], err => {
97+
t.ifError(err)
98+
t.equal(rimrafPath, path.join(npm.cache, '_cacache'))
99+
t.end()
100+
})
101+
})
102+
103+
t.test('cache clean with arg', t => {
104+
cache(['rm', 'pkg'], err => {
105+
t.match(err.message, 'does not accept arguments', 'should throw error')
106+
t.end()
107+
})
108+
})
109+
110+
t.test('cache add no arg', t => {
111+
t.teardown(() => {
112+
logOutput = []
113+
})
114+
115+
cache(['add'], err => {
116+
t.strictSame(logOutput, [
117+
['silly', 'cache add', 'args', []],
118+
], 'logs correctly')
119+
t.equal(err.code, 'EUSAGE', 'throws usage error')
120+
t.end()
121+
})
122+
})
123+
124+
t.test('cache add pkg only', t => {
125+
t.teardown(() => {
126+
logOutput = []
127+
tarballStreamSpec = ''
128+
tarballStreamOpts = {}
129+
})
130+
131+
cache(['add', 'mypkg'], err => {
132+
t.ifError(err)
133+
t.strictSame(logOutput, [
134+
['silly', 'cache add', 'args', ['mypkg']],
135+
['silly', 'cache add', 'spec', 'mypkg']
136+
], 'logs correctly')
137+
t.equal(tarballStreamSpec, 'mypkg', 'passes the correct spec to pacote')
138+
t.same(tarballStreamOpts, flatOptions, 'passes the correct options to pacote')
139+
t.end()
140+
})
141+
})
142+
143+
t.test('cache add pkg w/ spec modifier', t => {
144+
t.teardown(() => {
145+
logOutput = []
146+
tarballStreamSpec = ''
147+
tarballStreamOpts = {}
148+
})
149+
150+
cache(['add', 'mypkg', 'latest'], err => {
151+
t.ifError(err)
152+
t.strictSame(logOutput, [
153+
['silly', 'cache add', 'args', ['mypkg', 'latest']],
154+
['silly', 'cache add', 'spec', 'mypkg@latest']
155+
], 'logs correctly')
156+
t.equal(tarballStreamSpec, 'mypkg@latest', 'passes the correct spec to pacote')
157+
t.same(tarballStreamOpts, flatOptions, 'passes the correct options to pacote')
158+
t.end()
159+
})
160+
})
161+
162+
t.test('cache verify', t => {
163+
t.teardown(() => {
164+
outputOutput = []
165+
cacacheVerifyPath = ''
166+
})
167+
168+
cache(['verify'], err => {
169+
t.ifError(err)
170+
t.match(outputOutput, [
171+
`Cache verified and compressed (${path.join(npm.cache, '_cacache')})`,
172+
'Content verified: 1 (100 bytes)',
173+
'Index entries: 1',
174+
'Finished in 2s'
175+
], 'prints correct output')
176+
t.end()
177+
})
178+
})
179+
180+
t.test('cache verify w/ extra output', t => {
181+
npm.cache = `${process.env.HOME}/fake/path`
182+
cacacheVerifyStats.badContentCount = 1
183+
cacacheVerifyStats.reclaimedCount = 2
184+
cacacheVerifyStats.reclaimedSize = 200
185+
cacacheVerifyStats.missingContent = 3
186+
t.teardown(() => {
187+
npm.cache = '/fake/path'
188+
outputOutput = []
189+
cacacheVerifyPath = ''
190+
delete cacacheVerifyStats.badContentCount
191+
delete cacacheVerifyStats.reclaimedCount
192+
delete cacacheVerifyStats.reclaimedSize
193+
delete cacacheVerifyStats.missingContent
194+
})
195+
196+
cache(['check'], err => {
197+
t.ifError(err)
198+
t.match(outputOutput, [
199+
`Cache verified and compressed (~${path.join('/fake/path', '_cacache')})`,
200+
'Content verified: 1 (100 bytes)',
201+
'Corrupted content removed: 1',
202+
'Content garbage-collected: 2 (200 bytes)',
203+
'Missing content: 3',
204+
'Index entries: 1',
205+
'Finished in 2s'
206+
], 'prints correct output')
207+
t.end()
208+
})
209+
})
210+
211+
t.test('cache completion', t => {
212+
const { completion } = cache
213+
214+
const testComp = (argv, expect) => {
215+
completion({ conf: { argv: { remain: argv } } }, (err, res) => {
216+
t.ifError(err)
217+
t.strictSame(res, expect, argv.join(' '))
218+
})
219+
}
220+
221+
testComp(['npm', 'cache'], [
222+
'add',
223+
'clean',
224+
'verify'
225+
])
226+
227+
testComp(['npm', 'cache', 'add'], [])
228+
testComp(['npm', 'cache', 'clean'], [])
229+
testComp(['npm', 'cache', 'verify'], [])
230+
231+
t.end()
232+
})

0 commit comments

Comments
 (0)