From c9cb49358bb65804c4d7f247f4b73e77e7b4a2cf Mon Sep 17 00:00:00 2001 From: David Balatero Date: Tue, 5 May 2026 13:57:56 -0400 Subject: [PATCH] test: unreliable pack_spec.after_each: "EBUSY: resource busy or locked" #39606 Problem: `EBUSY` during cleanup: Windows CI can intermittently fail `pack_spec.lua` with `EBUSY` while removing `site/pack/core/opt/plugindirs`. This can happen because: - the test Nvim session may still be alive when `after_each()` removes the pack directory - Windows does not allow removing a directory while another process still has an open handle below it - startup-time `vim.pack.add()` performs a real `git clone`, so process and file handle release timing can vary on slower runners Startup timeout: The startup tests can also fail before cleanup because they wait for `_G.done` with a fixed timeout. That timeout includes the time needed for startup to run `vim.pack.add()` and finish the local clone. Solution: Close before cleanup: Capture the pack, lockfile, and log paths while the test Nvim session is still available, then call `n.check_close()` before removing the pack directory. Extend Windows startup wait: Increase the `_G.done` retry budget only on Windows so startup-time `vim.pack.add()` has more time to finish on slower CI runners. (cherry picked from commit 19a2ef5afaf2e6c78dfb6302457116709dc49cc0) --- test/functional/plugin/pack_spec.lua | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/test/functional/plugin/pack_spec.lua b/test/functional/plugin/pack_spec.lua index 1b97921273..4559ae7715 100644 --- a/test/functional/plugin/pack_spec.lua +++ b/test/functional/plugin/pack_spec.lua @@ -413,9 +413,17 @@ describe('vim.pack', function() end) after_each(function() - n.rmdir(pack_get_dir()) - pcall(vim.fs.rm, get_lock_path(), { force = true }) + local pack_dir = pack_get_dir() + local lock_path = get_lock_path() local log_path = vim.fs.joinpath(fn.stdpath('log'), 'nvim-pack.log') + + -- Wait for neovim to close before removing directories so it can release + -- the file handles it has open. We don't want to conflict with open files + -- when we remove dirs below. + n.check_close() + + n.rmdir(pack_dir) + pcall(vim.fs.rm, lock_path, { force = true }) pcall(vim.fs.rm, log_path, { force = true }) end) @@ -879,7 +887,7 @@ describe('vim.pack', function() local function assert_works() -- Should auto-install but wait before executing code after it n.clear({ args_rm = { '-u' } }) - t.retry(nil, 5000, function() + t.retry(nil, t.is_os('win') and 30000 or 5000, function() eq(true, exec_lua('return _G.done')) end) assert_loaded()