mirror of
https://github.com/neovim/neovim.git
synced 2024-12-21 03:35:02 -07:00
168a46fd31
During test setup, we used to call a vimscript function(BeforeEachTest) that attempted to restore Nvim to it's initial state as much as possible in order to provide a clean environment for running new tests. This approach has proven to be unreliable, as some tests leave state that can affect other tests, eventually causing failures that are difficult to debug. This commit changes the 'clear' function so it will restart Nvim every time it is called, which is a slower, but more reliable solution that will simplify spotting bugs in the future. Some other improvements/fixes were also performed: - Whenever an error is detected in a handler passed to "run()", the event loop will be stopped and the error will be propagated to the main thread. - Errors and the "cleanup()" function will always send a quit command to the current Nvim instance. This should prevent memory starvation when running tests under valgrind(where each Nvim instance can consume a lot of memory). - Fixed a wrong assertion in server_requests_spec.lua. Previously the failure was undetected in a notification handler. - Fixed some tests to expect fully clean registers. The deleted cleanup function used to put an empty string in every register, but that resulted in a extra line being added.
119 lines
3.8 KiB
Lua
119 lines
3.8 KiB
Lua
-- Tests for some server->client RPC scenarios. Note that unlike with
|
|
-- `rpcnotify`, to evaluate `rpcrequest` calls we need the client event loop to
|
|
-- be running.
|
|
local helpers = require('test.functional.helpers')
|
|
local clear, nvim, eval = helpers.clear, helpers.nvim, helpers.eval
|
|
local eq, run, stop = helpers.eq, helpers.run, helpers.stop
|
|
|
|
|
|
|
|
describe('server -> client', function()
|
|
local cid
|
|
|
|
before_each(function()
|
|
clear()
|
|
cid = nvim('get_api_info')[1]
|
|
end)
|
|
|
|
describe('simple call', function()
|
|
it('works', function()
|
|
local function on_setup()
|
|
eq({4, 5, 6}, eval('rpcrequest('..cid..', "scall", 1, 2, 3)'))
|
|
stop()
|
|
end
|
|
|
|
local function on_request(method, args)
|
|
eq('scall', method)
|
|
eq({1, 2, 3}, args)
|
|
nvim('command', 'let g:result = [4, 5, 6]')
|
|
return eval('g:result')
|
|
end
|
|
run(on_request, nil, on_setup)
|
|
end)
|
|
end)
|
|
|
|
describe('recursive call', function()
|
|
it('works', function()
|
|
local function on_setup()
|
|
nvim('set_var', 'result1', 0)
|
|
nvim('set_var', 'result2', 0)
|
|
nvim('set_var', 'result3', 0)
|
|
nvim('set_var', 'result4', 0)
|
|
nvim('command', 'let g:result1 = rpcrequest('..cid..', "rcall", 2)')
|
|
eq(4, nvim('get_var', 'result1'))
|
|
eq(8, nvim('get_var', 'result2'))
|
|
eq(16, nvim('get_var', 'result3'))
|
|
eq(32, nvim('get_var', 'result4'))
|
|
stop()
|
|
end
|
|
|
|
local function on_request(method, args)
|
|
eq('rcall', method)
|
|
local n = unpack(args) * 2
|
|
if n <= 16 then
|
|
local cmd
|
|
if n == 4 then
|
|
cmd = 'let g:result2 = rpcrequest('..cid..', "rcall", '..n..')'
|
|
elseif n == 8 then
|
|
cmd = 'let g:result3 = rpcrequest('..cid..', "rcall", '..n..')'
|
|
elseif n == 16 then
|
|
cmd = 'let g:result4 = rpcrequest('..cid..', "rcall", '..n..')'
|
|
end
|
|
nvim('command', cmd)
|
|
end
|
|
return n
|
|
end
|
|
run(on_request, nil, on_setup)
|
|
end)
|
|
end)
|
|
|
|
describe('requests and notifications interleaved', function()
|
|
-- This tests that the following scenario won't happen:
|
|
--
|
|
-- server->client [request ] (1)
|
|
-- client->server [request ] (2) triggered by (1)
|
|
-- server->client [notification] (3) triggered by (2)
|
|
-- server->client [response ] (4) response to (2)
|
|
-- client->server [request ] (4) triggered by (3)
|
|
-- server->client [request ] (5) triggered by (4)
|
|
-- client->server [response ] (6) response to (1)
|
|
--
|
|
-- If the above scenario ever happens, the client connection will be closed
|
|
-- because (6) is returned after request (5) is sent, and nvim
|
|
-- only deals with one server->client request at a time. (In other words,
|
|
-- the client cannot send a response to a request that is not at the top
|
|
-- of nvim's request stack).
|
|
--
|
|
-- But above scenario shoudn't happen by the way notifications are dealt in
|
|
-- Nvim: they are only sent after there are no pending server->client
|
|
-- request(the request stack fully unwinds). So (3) is only sent after the
|
|
-- client returns (6).
|
|
it('works', function()
|
|
local expected = 300
|
|
local notified = 0
|
|
local function on_setup()
|
|
eq('notified!', eval('rpcrequest('..cid..', "notify")'))
|
|
end
|
|
|
|
local function on_request(method, args)
|
|
eq('notify', method)
|
|
eq(1, eval('rpcnotify('..cid..', "notification")'))
|
|
return 'notified!'
|
|
end
|
|
|
|
local function on_notification(method, args)
|
|
eq('notification', method)
|
|
if notified == expected then
|
|
stop()
|
|
return
|
|
end
|
|
notified = notified + 1
|
|
eq('notified!', eval('rpcrequest('..cid..', "notify")'))
|
|
end
|
|
|
|
run(on_request, on_notification, on_setup)
|
|
eq(expected, notified)
|
|
end)
|
|
end)
|
|
end)
|