mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
channel: Delay notifications to avoid client race conditions
It is currently possible for a client to send a response that doesn't match the current server->client request(at the top of the stack). This commit fixes that by delaying notifications to until the first `channel_send_call` invocation returns. Also remove the "call stack" size check, vim will already break if the call stack goes too deep.
This commit is contained in:
@@ -2,8 +2,10 @@
|
||||
-- `rpcnotify`, to evaluate `rpcrequest` calls we need the client event loop to
|
||||
-- be running.
|
||||
local helpers = require('test.functional.helpers')
|
||||
local clear, nvim, eval, eq, run, stop = helpers.clear, helpers.nvim,
|
||||
helpers.eval, helpers.eq, helpers.run, helpers.stop
|
||||
local clear, nvim, eval = helpers.clear, helpers.nvim, helpers.eval
|
||||
local eq, run, stop = helpers.eq, helpers.run, helpers.stop
|
||||
local restart = helpers.restart
|
||||
|
||||
|
||||
|
||||
describe('server -> client', function()
|
||||
@@ -13,6 +15,7 @@ describe('server -> client', function()
|
||||
clear()
|
||||
cid = nvim('get_api_info')[1]
|
||||
end)
|
||||
teardown(restart)
|
||||
|
||||
describe('simple call', function()
|
||||
it('works', function()
|
||||
@@ -65,4 +68,53 @@ describe('server -> client', function()
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user