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

fix: isolate full and corgi packuments in packumentCache #369

Merged
merged 1 commit into from
May 7, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 7 additions & 6 deletions lib/registry.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const fullDoc = 'application/json'
const MISSING_TIME_CUTOFF = '2015-01-01T00:00:00.000Z'

class RegistryFetcher extends Fetcher {
#cacheKey
constructor (spec, opts) {
super(spec, opts)

Expand All @@ -32,8 +33,8 @@ class RegistryFetcher extends Fetcher {
this.packumentCache = this.opts.packumentCache || null

this.registry = fetch.pickRegistry(spec, opts)
this.packumentUrl = removeTrailingSlashes(this.registry) + '/' +
this.spec.escapedName
this.packumentUrl = `${removeTrailingSlashes(this.registry)}/${this.spec.escapedName}`
this.#cacheKey = `${this.fullMetadata ? 'full' : 'corgi'}:${this.packumentUrl}`

const parsed = new URL(this.registry)
const regKey = `//${parsed.host}${parsed.pathname}`
Expand Down Expand Up @@ -78,8 +79,8 @@ class RegistryFetcher extends Fetcher {
// note this might be either an in-flight promise for a request,
// or the actual packument, but we never want to make more than
// one request at a time for the same thing regardless.
if (this.packumentCache?.has(this.packumentUrl)) {
return this.packumentCache.get(this.packumentUrl)
if (this.packumentCache?.has(this.#cacheKey)) {
return this.packumentCache.get(this.#cacheKey)
}

// npm-registry-fetch the packument
Expand All @@ -99,10 +100,10 @@ class RegistryFetcher extends Fetcher {
if (contentLength) {
packument._contentLength = Number(contentLength)
}
this.packumentCache?.set(this.packumentUrl, packument)
this.packumentCache?.set(this.#cacheKey, packument)
return packument
} catch (err) {
this.packumentCache?.delete(this.packumentUrl)
this.packumentCache?.delete(this.#cacheKey)
if (err.code !== 'E404' || this.fullMetadata) {
throw err
}
Expand Down
114 changes: 71 additions & 43 deletions test/registry.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,57 +22,62 @@ const MockedRegistryFetcher = t.mock('../lib/registry.js', {

const port = 18000 + (+process.env.TAP_CHILD_ID || 0)
const me = t.testdir()
const registry = `http://localhost:${port}/`
const cache = me + '/cache'

t.test('start mock registry', { bail: true }, t => {
mr({
port,
mocks: {
get: {
'/no-integrity/-/no-integrity-1.2.3.tgz': [
200,
`${__dirname}/fixtures/abbrev-1.1.1.tgz`,
],
let mockServer
t.before(() => {
return new Promise((resolve, reject) => {
mr({
port,
mocks: {
get: {
'/no-integrity/-/no-integrity-1.2.3.tgz': [
200,
`${__dirname}/fixtures/abbrev-1.1.1.tgz`,
],
},
},
},

plugin (server) {
server.get('/thing-is-not-here').many().reply(404, { error: 'not found' })
server.get('/no-tarball').many().reply(200, {
name: 'no-tarball',
'dist-tags': { latest: '1.2.3' },
versions: {
'1.2.3': {
name: 'no-tarball',
version: '1.2.3',
plugin (server) {
server.get('/thing-is-not-here').many().reply(404, { error: 'not found' })
server.get('/no-tarball').many().reply(200, {
name: 'no-tarball',
'dist-tags': { latest: '1.2.3' },
versions: {
'1.2.3': {
name: 'no-tarball',
version: '1.2.3',
},
},
},
})
server.get('/no-integrity').many().reply(200, {
name: 'no-integrity',
'dist-tags': { latest: '1.2.3' },
versions: {
'1.2.3': {
name: 'no-integrity',
version: '1.2.3',
dist: {
tarball: `${registry}no-integrity/-/no-integrity-1.2.3.tgz`,
})
server.get('/no-integrity').many().reply(200, {
name: 'no-integrity',
'dist-tags': { latest: '1.2.3' },
versions: {
'1.2.3': {
name: 'no-integrity',
version: '1.2.3',
dist: {
tarball: `${registry}no-integrity/-/no-integrity-1.2.3.tgz`,
},
},
},
},
})
},
}, (er, s) => {
if (er) {
throw er
}

t.parent.teardown(() => s.close())
t.end()
})
},
}, (err, s) => {
if (err) {
return reject(err)
}
mockServer = s
resolve()
})
})
})

const registry = `http://localhost:${port}/`
const cache = me + '/cache'
t.teardown(() => {
mockServer?.close()
})

t.test('underscore, no tag or version', t => {
const f = new RegistryFetcher('underscore', { registry, cache, fullReadJson: true })
Expand Down Expand Up @@ -1207,11 +1212,34 @@ t.test('packument that has been cached', async t => {
},
},
}
const packumentCache = new Map([[packumentUrl, packument]])
const packumentCache = new Map([[`corgi:${packumentUrl}`, packument]])
const f = new RegistryFetcher('asdf@1.2', { registry, cache, packumentCache })
t.equal(await f.packument(), packument, 'got cached packument')
})

t.test('corgi packument is not cached as full packument', async t => {
const packumentUrl = `${registry}underscore`
const packument = {
name: 'underscore',
versions: {
'1.5.1': {
cached: true,
name: 'underscore',
version: '1.5.1',
},
},
}
const packumentCache = new Map([[`corgi:${packumentUrl}`, packument]])
const f = new RegistryFetcher('underscore', {
packumentCache,
registry,
cache,
fullMetadata: true,
})
t.notEqual(await f.packument(), packument, 'did not get cached packument')
t.ok(packumentCache.has(`full:${packumentUrl}`), 'full packument is also now cached')
})

t.test('packument that falls back to fullMetadata', t => {
const http = require('http')
const packument = {
Expand Down