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

feat: add result cache consumer #341

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions lua/neotest/client/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,16 @@ function neotest.Client:is_running(position_id, args)
return #self:_get_running_adapters(position_id) > 0
end

---Loads results for all adapters into state
---@async
---@param all_results table<string, neotest.Result>
---@return nil
function neotest.Client:load_results(all_results)
for adapter_id, adapter_results in pairs(all_results) do
self._state:update_results(adapter_id, adapter_results)
end
end

---@param position_id string
---@return string[]
---@private
Expand Down
2 changes: 2 additions & 0 deletions lua/neotest/config/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ local js_watch_query = [[

---@class neotest.Config.state
---@field enabled boolean
---@field fetch_cached_results_on_startup boolean

---@class neotest.Config.output_panel
---@field enabled boolean
Expand Down Expand Up @@ -281,6 +282,7 @@ local default_config = {
},
state = {
enabled = true,
fetch_cached_results_on_startup = false
},
watch = {
enabled = true,
Expand Down
1 change: 1 addition & 0 deletions lua/neotest/consumers/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ neotest.consumers = {
quickfix = require("neotest.consumers.quickfix"),
state = require("neotest.consumers.state"),
watch = require("neotest.consumers.watch"),
result_cache = require("neotest.consumers.result_cache"),
}

return neotest.consumers
122 changes: 122 additions & 0 deletions lua/neotest/consumers/result_cache.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
local nio = require("nio")
local lib = require("neotest.lib")
local Path = require("plenary.path")
local config = require("neotest.config")

---@private
---@type neotest.Client
local client

local neotest = {}

local plugin = "neotest"
local consumer = "result_cache"
local result_cache_file_name = "results.json"

local plugin_cache = Path:new(vim.fn.stdpath("cache")):joinpath(plugin)
local consumer_cache = plugin_cache:joinpath(consumer)

---@toc_entry Result Cache Consumer
---@text
--- A consumer providing a simple interface to cache and fetch test results.
--- The cache is persisted across Neovim sessions.
---@class neotest.consumers.result_cache
neotest.result_cache = {}

---@private
---@async
---@return nil
local function _cache_output_tmp_file(output_file_tmp_path, output_file_cache_path)
if not lib.files.exists(output_file_cache_path) then
nio.uv.fs_copyfile(output_file_tmp_path, output_file_cache_path)
end
end

---@private
---@async
---@param adapter_id string neotest adapter_id
---@return Path adapter_cache_path safe adapter cache path
local function _adapter_cache_path(adapter_id)
local adapter_cache_name
if vim.base64 then
adapter_cache_name = vim.base64.encode(adapter_id)
else
adapter_cache_name = adapter_id:gsub("[:/]", "")
end
return consumer_cache:joinpath(adapter_cache_name)
end
--- Cache test results to cache file
---@async
---@return nil
function neotest.result_cache:cache()
plugin_cache:mkdir()
consumer_cache:mkdir()

local results_to_cache = {}
for _, adapter_id in pairs(client:get_adapters()) do
local adapter_cache_path = _adapter_cache_path(adapter_id)
adapter_cache_path:mkdir()
local adapter_results = client:get_results(adapter_id)
for key, result in pairs(adapter_results) do
if result.output then
local result_output = Path:new(result.output)
local result_filename =
vim.split(tostring(result_output), tostring(result_output:parent()))[2]
local output_file_cache_path = adapter_cache_path:joinpath(result_filename:sub(2))
_cache_output_tmp_file(result.output, tostring(output_file_cache_path))
adapter_results[key].output = tostring(output_file_cache_path)
end
end
results_to_cache[adapter_id] = adapter_results

local result_cache_file_path = adapter_cache_path:joinpath(result_cache_file_name)
lib.files.write(tostring(result_cache_file_path), vim.json.encode(results_to_cache))
vim.notify("Test results cached.")
end
end

neotest.result_cache.cache = nio.create(neotest.result_cache.cache, 1)

--- Clear cached test results
---@async
---@return nil
function neotest.result_cache:clear()
Willem-J-an marked this conversation as resolved.
Show resolved Hide resolved
local cache_files = lib.files.find(tostring(consumer_cache))
for _, file in pairs(cache_files) do
os.remove(file)
end
end

neotest.result_cache.clear = nio.create(neotest.result_cache.clear, 1)

--- Loads previously cached test results
---@async
---@return nil
function neotest.result_cache:fetch()
Willem-J-an marked this conversation as resolved.
Show resolved Hide resolved
for _, adapter_id in pairs(client:get_adapters()) do
local result_cache_file_path = _adapter_cache_path(adapter_id):joinpath(result_cache_file_name)

if result_cache_file_path:exists() then
local cached_results = vim.json.decode(lib.files.read(tostring(result_cache_file_path)))
client:load_results(cached_results)
end
end
end

neotest.result_cache.fetch = nio.create(neotest.result_cache.fetch, 1)

neotest.result_cache = setmetatable(neotest.result_cache, {
---@param client_ neotest.Client
__call = function(_, client_)
client = client_

if config.state.fetch_results_on_startup then
client.listeners.started = function()
neotest.result_cache:fetch()
end
end
return neotest.result_cache
end,
})

return neotest.result_cache