Skip to content

Commit

Permalink
chore: add failing publish global self smoke test
Browse files Browse the repository at this point in the history
  • Loading branch information
lukekarrys committed Jun 5, 2023
1 parent 12f678c commit 903b1c3
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 35 deletions.
1 change: 1 addition & 0 deletions DEPENDENCIES.md
Original file line number Diff line number Diff line change
Expand Up @@ -690,6 +690,7 @@ graph LR;
npmcli-mock-globals-->npmcli-eslint-config["@npmcli/eslint-config"];
npmcli-mock-globals-->npmcli-template-oss["@npmcli/template-oss"];
npmcli-mock-globals-->tap;
npmcli-mock-registry-->json-stringify-safe;
npmcli-mock-registry-->nock;
npmcli-mock-registry-->npm-package-arg;
npmcli-mock-registry-->npmcli-arborist["@npmcli/arborist"];
Expand Down
7 changes: 4 additions & 3 deletions mock-registry/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const pacote = require('pacote')
const Arborist = require('@npmcli/arborist')
const npa = require('npm-package-arg')
const Nock = require('nock')
const stringify = require('json-stringify-safe')

class MockRegistry {
#tap
Expand Down Expand Up @@ -39,7 +40,7 @@ class MockRegistry {
// mocked with a 404, 500, etc.
// XXX: this is opt-in currently because it breaks some existing CLI
// tests. We should work towards making this the default for all tests.
t.fail(`Unmatched request: ${JSON.stringify(req, null, 2)}`)
t.fail(`Unmatched request: ${stringify(req, null, 2)}`)
}
}

Expand Down Expand Up @@ -337,9 +338,9 @@ class MockRegistry {
}
nock = nock.reply(200, manifest)
if (tarballs) {
for (const version in tarballs) {
for (const [version, tarball] of Object.entries(tarballs)) {
const m = manifest.versions[version]
nock = await this.tarball({ manifest: m, tarball: tarballs[version] })
nock = await this.tarball({ manifest: m, tarball })
}
}
this.nock = nock
Expand Down
1 change: 1 addition & 0 deletions mock-registry/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"@npmcli/arborist": "^6.1.1",
"@npmcli/eslint-config": "^4.0.1",
"@npmcli/template-oss": "4.14.1",
"json-stringify-safe": "^5.0.1",
"nock": "^13.3.0",
"npm-package-arg": "^10.1.0",
"pacote": "^15.0.8",
Expand Down
1 change: 1 addition & 0 deletions package-lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@
"@npmcli/arborist": "^6.1.1",
"@npmcli/eslint-config": "^4.0.1",
"@npmcli/template-oss": "4.14.1",
"json-stringify-safe": "^5.0.1",
"nock": "^13.3.0",
"npm-package-arg": "^10.1.0",
"pacote": "^15.0.8",
Expand Down
35 changes: 27 additions & 8 deletions smoke-tests/test/fixtures/setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const httpProxy = require('http-proxy')

const { SMOKE_PUBLISH_NPM, SMOKE_PUBLISH_TARBALL, CI, PATH, Path, TAP_CHILD_ID = '0' } = process.env
const PROXY_PORT = 12345 + (+TAP_CHILD_ID)
const HTTP_PROXY = `http://localhost:${PROXY_PORT}`
const HTTP_PROXY = `http://localhost:${PROXY_PORT}/`

const NODE_PATH = process.execPath
const CLI_ROOT = resolve(process.cwd(), '..')
Expand Down Expand Up @@ -64,12 +64,13 @@ const getCleanPaths = async () => {
})
}

const createRegistry = async (t, { debug } = {}) => {
const createRegistry = async (t, { debug, ...opts } = {}) => {
const registry = new MockRegistry({
tap: t,
registry: 'http://smoke-test-registry.club/',
debug,
strict: true,
...opts,
})

const proxy = httpProxy.createProxyServer({})
Expand All @@ -81,7 +82,7 @@ const createRegistry = async (t, { debug } = {}) => {
return registry
}

module.exports = async (t, { testdir = {}, debug } = {}) => {
module.exports = async (t, { testdir = {}, debug, registry: _registry = {} } = {}) => {
const debugLog = debug || CI ? (...a) => console.error(...a) : () => {}
const cleanPaths = await getCleanPaths()

Expand All @@ -105,7 +106,7 @@ module.exports = async (t, { testdir = {}, debug } = {}) => {
globalNodeModules: join(root, 'global', GLOBAL_NODE_MODULES),
}

const registry = await createRegistry(t, { debug })
const registry = await createRegistry(t, { ..._registry, debug })

// update notifier should never be written
t.afterEach((t) => {
Expand Down Expand Up @@ -168,7 +169,13 @@ module.exports = async (t, { testdir = {}, debug } = {}) => {
return stdout
}

const baseNpm = async ({ cwd, cmd, argv = [], proxy = true, ...opts } = {}, ...args) => {
const baseNpm = async (baseOpts, ...args) => {
const hasMoreOpts = args[args.length - 1] && typeof args[args.length - 1] === 'object'
const { cwd, cmd, argv = [], proxy = true, ...opts } = {
...baseOpts,
...hasMoreOpts ? args.pop() : {},
}

const isGlobal = args.some(a => ['-g', '--global', '--global=true'].includes(a))

const defaultFlags = [
Expand Down Expand Up @@ -218,6 +225,10 @@ module.exports = async (t, { testdir = {}, debug } = {}) => {
argv: [NPM_PATH],
}, ...args)

const npmLocalError = async () => {
throw new Error('npmLocal cannot be called during smoke-publish')
}

// helpers for reading/writing files and their source
const readFile = async (f) => {
const file = await fs.readFile(join(paths.project, f), 'utf-8')
Expand All @@ -226,15 +237,22 @@ module.exports = async (t, { testdir = {}, debug } = {}) => {

return {
npmPath,
npmLocal: SMOKE_PUBLISH_NPM ? async () => {
throw new Error('npmLocal cannot be called during smoke-publish')
} : npmLocal,
npmLocal: SMOKE_PUBLISH_NPM ? npmLocalError : npmLocal,
npm: SMOKE_PUBLISH_NPM ? npmPath : npm,
spawn: baseSpawn,
readFile,
getPath,
paths,
registry,
npmLocalTarball: async () => {
if (SMOKE_PUBLISH_TARBALL) {
return SMOKE_PUBLISH_TARBALL
}
if (SMOKE_PUBLISH_NPM) {
return await npmLocalError()
}
return await npmLocal('pack', `--pack-destination=${root}`).then(r => join(root, r))
},
}
}

Expand All @@ -244,3 +262,4 @@ module.exports.CLI_ROOT = CLI_ROOT
module.exports.WINDOWS = WINDOWS
module.exports.SMOKE_PUBLISH = !!SMOKE_PUBLISH_NPM
module.exports.SMOKE_PUBLISH_TARBALL = SMOKE_PUBLISH_TARBALL
module.exports.HTTP_PROXY = HTTP_PROXY
96 changes: 72 additions & 24 deletions smoke-tests/test/npm-replace-global.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,40 +10,46 @@ const which = async (cmd, opts) => {
return path ? join(dirname(path), basename(path, extname(path))) : null
}

t.test('npm replace global', async t => {
const setupNpmGlobal = async (t, opts) => {
const mock = await setup(t, opts)

return {
...mock,
getPaths: async () => {
const binContents = await fs.readdir(mock.paths.globalBin).then(results => results
.filter(p => p !== '.npmrc' && p !== 'node_modules')
.map(p => basename(p, extname(p)))
.reduce((set, p) => set.add(p), new Set()))

return {
npmRoot: await mock.npmPath('help').then(setup.getNpmRoot),
pathNpm: await which('npm', { path: mock.getPath(), nothrow: true }),
globalNpm: await which('npm', { nothrow: true }),
pathNpx: await which('npx', { path: mock.getPath(), nothrow: true }),
globalNpx: await which('npx', { nothrow: true }),
binContents: [...binContents],
nodeModulesContents: await fs.readdir(join(mock.paths.globalNodeModules, 'npm')),
}
},
}
}

t.test('pack and replace global self', async t => {
const {
npm,
npmLocal,
npmLocalTarball,
npmPath,
getPath,
paths: { root, globalBin, globalNodeModules },
} = await setup(t, {
getPaths,
paths: { globalBin, globalNodeModules },
} = await setupNpmGlobal(t, {
testdir: {
project: {
'package.json': { name: 'npm', version: '999.999.999' },
},
},
})

const getPaths = async () => {
const binContents = await fs.readdir(globalBin).then(results => results
.filter(p => p !== '.npmrc' && p !== 'node_modules')
.map(p => basename(p, extname(p)))
.reduce((set, p) => set.add(p), new Set()))

return {
npmRoot: await npmPath('help').then(setup.getNpmRoot),
pathNpm: await which('npm', { path: getPath(), nothrow: true }),
globalNpm: await which('npm', { nothrow: true }),
pathNpx: await which('npx', { path: getPath(), nothrow: true }),
globalNpx: await which('npx', { nothrow: true }),
binContents: [...binContents],
nodeModulesContents: await fs.readdir(join(globalNodeModules, 'npm')),
}
}

const tarball = setup.SMOKE_PUBLISH_TARBALL ??
await npmLocal('pack', `--pack-destination=${root}`).then(r => join(root, r))
const tarball = await npmLocalTarball()

await npm('install', tarball, '--global')

Expand Down Expand Up @@ -80,3 +86,45 @@ t.test('npm replace global', async t => {
t.strictSame(postPaths.binContents, [], 'bin is empty')
t.strictSame(postPaths.nodeModulesContents, ['package.json'], 'contents is only package.json')
})

t.test('publish and replace global self', async t => {
const {
npm,
registry,
npmLocal,
npmLocalTarball,
getPaths,
} = await setupNpmGlobal(t, {
testdir: {
home: {
'.npmrc': `${setup.HTTP_PROXY.slice(5)}:_authToken = test-token`,
},
},
})

const tarball = await npmLocalTarball()

let publishedPackument = null
const pkg = require('../../package.json')
const { name, version } = pkg

registry.nock.put('/npm', body => {
if (body._id === 'npm' && body.versions[version]) {
publishedPackument = body.versions[version]
return true
}
return false
}).reply(201, {})
await npmLocal('publish', { proxy: true })

await registry.package({
manifest: registry.manifest({ name, packuments: [publishedPackument] }),
tarballs: { [version]: tarball },
times: 2,
})

await npm('install', 'npm', '--global', '--prefer-online')

// this throws right now
await getPaths()
})

0 comments on commit 903b1c3

Please sign in to comment.