Files
vimpack/tests/install_spec.lua
T
unkin-agent ca55c9dd9f
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/lint Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
Validate archive entries and stage inside the pack root
- Reject archive members that are absolute, escape via .., are special files, or link outside the destination, before anything is written

- Stage under the pack root so the swap is a same-filesystem rename, with an EXDEV copy fallback; propagate registry auth errors and validate dir_name
2026-09-05 16:32:47 +10:00

182 lines
6.4 KiB
Lua

-- End-to-end install over file:// URLs: real curl, real tar, real swap.
local checksum = require('vimpack.checksum')
local config = require('vimpack.config')
local fsmod = require('vimpack.fs')
local installer = require('vimpack.installer')
local manifest = require('vimpack.manifest')
local plan = require('vimpack.plan')
local function make_tarball(root, version, body)
local src = vim.fs.joinpath(root, 'src', 'demo.nvim-' .. version, 'lua')
vim.fn.mkdir(src, 'p')
vim.fn.writefile({ body }, vim.fs.joinpath(src, 'demo.lua'))
local archive = vim.fs.joinpath(root, 'demo-' .. version .. '.tar.gz')
vim.fn.system({ 'tar', '-czf', archive, '-C', vim.fs.joinpath(root, 'src'), 'demo.nvim-' .. version })
return archive
end
local function install(cfg, data, pack_root)
local built = plan.build(cfg, data, fsmod.scan(pack_root))
local items = vim.list_extend(vim.deepcopy(built.install), built.update)
local results
installer.run(items, {
manifest = data,
pack_root = pack_root,
timeout = 30000,
concurrency = 2,
}, function(r)
results = r
end)
vim.wait(30000, function()
return results ~= nil
end)
return results, items
end
describe('install end to end', function()
it('downloads, extracts, swaps and records the manifest', function()
local root = tmpdir()
local pack_root = vim.fs.joinpath(root, 'pack')
local archive = make_tarball(root, '1.0.0', 'return 1')
local cfg = assert(config.normalize({
plugins = { { name = 'demo.nvim', version = '1.0.0', url = 'file://' .. archive } },
}))
local data = manifest.empty()
local results = install(cfg, data, pack_root)
assert_eq(1, #results)
assert_true(results[1].ok, tostring(results[1].err))
local installed = vim.fs.joinpath(pack_root, 'start', 'demo.nvim', 'lua', 'demo.lua')
assert_true(fsmod.exists(installed), 'expected ' .. installed)
assert_eq({ 'return 1' }, vim.fn.readfile(installed))
local entry = manifest.get(data, 'demo.nvim')
assert_eq('1.0.0', entry.version)
assert_eq(assert(checksum.sha256_file(archive)), entry.sha256)
-- Second pass is a no-op: nothing left to install.
local _, items = install(cfg, data, pack_root)
assert_eq(0, #items)
end)
it('replaces the old tree on a version bump', function()
local root = tmpdir()
local pack_root = vim.fs.joinpath(root, 'pack')
local data = manifest.empty()
local v1 = make_tarball(root, '1.0.0', 'return 1')
local cfg1 = assert(config.normalize({
plugins = { { name = 'demo.nvim', version = '1.0.0', url = 'file://' .. v1 } },
}))
assert_true(install(cfg1, data, pack_root)[1].ok)
local v2 = make_tarball(root, '2.0.0', 'return 2')
local cfg2 = assert(config.normalize({
plugins = { { name = 'demo.nvim', version = '2.0.0', url = 'file://' .. v2 } },
}))
local results = install(cfg2, data, pack_root)
assert_true(results[1].ok, tostring(results[1].err))
assert_eq({ 'return 2' }, vim.fn.readfile(vim.fs.joinpath(pack_root, 'start', 'demo.nvim', 'lua', 'demo.lua')))
assert_eq('2.0.0', manifest.get(data, 'demo.nvim').version)
end)
it('aborts on a checksum mismatch and keeps the previous install', function()
local root = tmpdir()
local pack_root = vim.fs.joinpath(root, 'pack')
local data = manifest.empty()
local v1 = make_tarball(root, '1.0.0', 'return 1')
assert_true(install(
assert(config.normalize({
plugins = { { name = 'demo.nvim', version = '1.0.0', url = 'file://' .. v1 } },
})),
data,
pack_root
)[1].ok)
local v2 = make_tarball(root, '2.0.0', 'return 2')
local results = install(
assert(config.normalize({
plugins = {
{ name = 'demo.nvim', version = '2.0.0', url = 'file://' .. v2, sha256 = string.rep('a', 64) },
},
})),
data,
pack_root
)
assert_true(not results[1].ok)
assert_match('checksum mismatch', results[1].err)
assert_eq({ 'return 1' }, vim.fn.readfile(vim.fs.joinpath(pack_root, 'start', 'demo.nvim', 'lua', 'demo.lua')))
assert_eq('1.0.0', manifest.get(data, 'demo.nvim').version)
end)
it('names the url when the download fails', function()
local root = tmpdir()
local missing = 'file://' .. vim.fs.joinpath(root, 'nope.tar.gz')
local results = install(
assert(config.normalize({
plugins = { { name = 'demo.nvim', version = '1.0.0', url = missing } },
})),
manifest.empty(),
vim.fs.joinpath(root, 'pack')
)
assert_true(not results[1].ok)
assert_match('download failed', results[1].err)
assert_match(missing, results[1].err)
end)
it('installs with the cache on a different filesystem from the pack root', function()
local root = tmpdir()
local pack_root = vim.fs.joinpath(root, 'pack')
local other = otherfs_dir(root)
if not other then
return
end
local real_cache_dir = fsmod.cache_dir
fsmod.cache_dir = function()
return vim.fs.joinpath(other, 'vimpack')
end
local archive = make_tarball(root, '1.0.0', 'return 1')
local cfg = assert(config.normalize({
plugins = { { name = 'demo.nvim', version = '1.0.0', url = 'file://' .. archive } },
}))
local data = manifest.empty()
local ok, results = pcall(install, cfg, data, pack_root)
fsmod.cache_dir = real_cache_dir
fsmod.rm_rf(other)
assert_true(ok, tostring(results))
assert_true(results[1].ok, tostring(results[1].err))
assert_eq({ 'return 1' }, vim.fn.readfile(vim.fs.joinpath(pack_root, 'start', 'demo.nvim', 'lua', 'demo.lua')))
end)
it('moves a plugin from start to opt', function()
local root = tmpdir()
local pack_root = vim.fs.joinpath(root, 'pack')
local data = manifest.empty()
local archive = make_tarball(root, '1.0.0', 'return 1')
assert_true(install(
assert(config.normalize({
plugins = { { name = 'demo.nvim', version = '1.0.0', url = 'file://' .. archive } },
})),
data,
pack_root
)[1].ok)
local results = install(
assert(config.normalize({
plugins = { { name = 'demo.nvim', version = '1.0.0', url = 'file://' .. archive, opt = true } },
})),
data,
pack_root
)
assert_true(results[1].ok, tostring(results[1].err))
assert_true(fsmod.exists(vim.fs.joinpath(pack_root, 'opt', 'demo.nvim', 'lua', 'demo.lua')))
assert_true(not fsmod.exists(vim.fs.joinpath(pack_root, 'start', 'demo.nvim')))
end)
end)