test: Improve test environment setup and error handling/reporting

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.
This commit is contained in:
Thiago de Arruda
2014-11-06 23:54:49 -03:00
parent 3e78fc9faf
commit 168a46fd31
8 changed files with 49 additions and 89 deletions

View File

@@ -4,7 +4,6 @@
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
local restart = helpers.restart
@@ -15,7 +14,6 @@ describe('server -> client', function()
clear()
cid = nvim('get_api_info')[1]
end)
teardown(restart)
describe('simple call', function()
it('works', function()
@@ -110,7 +108,7 @@ describe('server -> client', function()
return
end
notified = notified + 1
eq('notified', eval('rpcrequest('..cid..', "notify")'))
eq('notified!', eval('rpcrequest('..cid..', "notify")'))
end
run(on_request, on_notification, on_setup)

View File

@@ -1,10 +1,11 @@
require('coxpcall')
local Loop = require('nvim.loop')
local MsgpackStream = require('nvim.msgpack_stream')
local AsyncSession = require('nvim.async_session')
local Session = require('nvim.session')
local nvim_prog = os.getenv('NVIM_PROG') or 'build/bin/nvim'
local nvim_argv = {nvim_prog, '-u', 'NONE', '-N', '--embed'}
local nvim_argv = {nvim_prog, '-u', 'NONE', '-i', 'NONE', '-N', '--embed'}
if os.getenv('VALGRIND') then
local log_file = os.getenv('VALGRIND_LOG') or 'valgrind-%p.log'
@@ -23,74 +24,7 @@ if os.getenv('VALGRIND') then
nvim_argv = valgrind_argv
end
local session
local rawfeed
local function restart()
local loop = Loop.new()
local msgpack_stream = MsgpackStream.new(loop)
local async_session = AsyncSession.new(msgpack_stream)
session = Session.new(async_session)
loop:spawn(nvim_argv)
rawfeed([[:function BeforeEachTest()
set all&
redir => groups
silent augroup
redir END
for group in split(groups)
exe 'augroup '.group
autocmd!
augroup END
endfor
autocmd!
tabnew
let curbufnum = eval(bufnr('%'))
redir => buflist
silent ls!
redir END
let bufnums = []
for buf in split(buflist, '\n')
let bufnum = eval(split(buf, '[ u]')[0])
if bufnum != curbufnum
call add(bufnums, bufnum)
endif
endfor
if len(bufnums) > 0
exe 'silent bwipeout! '.join(bufnums, ' ')
endif
silent tabonly
for k in keys(g:)
exe 'unlet g:'.k
endfor
filetype plugin indent off
mapclear
mapclear!
abclear
comclear
let regs = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/-"'
let i = 0
while i < strlen(regs)
call setreg(regs[i], '')
let i = i+1
endwhile
redir => funcs
silent! function
redir END
for fname in split(funcs, '\n')
let matches = matchlist(fname, '\v^function ([^()<>]+)')
if type([]) == type(matches) && matches[1] !~ 'BeforeEachTest'
exe 'silent! delfunc '.matches[1]
endif
endfor
let options = ['shell', 'fileignorecase']
for option in options
exe 'set '.option.'&'
endfor
endfunction
]])
end
local loop_running, last_error
local session, loop_running, last_error
local function request(method, ...)
local status, rv = session:request(method, ...)
@@ -112,9 +46,32 @@ local function next_message()
return session:next_message()
end
local function call_and_stop_on_error(...)
local status, result = copcall(...)
if not status then
session:stop()
last_error = result
return ''
end
return result
end
local function run(request_cb, notification_cb, setup_cb)
local function on_request(method, args)
return call_and_stop_on_error(request_cb, method, args)
end
local function on_notification(method, args)
call_and_stop_on_error(notification_cb, method, args)
end
local function on_setup()
call_and_stop_on_error(setup_cb)
end
loop_running = true
session:run(request_cb, notification_cb, setup_cb)
session:run(on_request, on_notification, on_setup)
loop_running = false
if last_error then
local err = last_error
@@ -153,7 +110,7 @@ local function buffer_slice(start, stop, buffer_idx)
end
local function nvim_replace_termcodes(input)
return request('vim_replace_termcodes', input, false, true, true )
return request('vim_replace_termcodes', input, false, true, true)
end
local function dedent(str)
@@ -178,22 +135,29 @@ local function dedent(str)
return str
end
local function clear()
nvim_command('call BeforeEachTest()')
end
local function feed(...)
for _, v in ipairs({...}) do
nvim_feed(nvim_replace_termcodes(dedent(v)))
end
end
function rawfeed(...)
local function rawfeed(...)
for _, v in ipairs({...}) do
nvim_feed(dedent(v), 'nt')
end
end
local function clear()
if session then
session:request('vim_command', 'qa!')
end
local loop = Loop.new()
local msgpack_stream = MsgpackStream.new(loop)
local async_session = AsyncSession.new(msgpack_stream)
session = Session.new(async_session)
loop:spawn(nvim_argv)
end
local function insert(...)
nvim_feed('i', 'nt')
rawfeed(...)
@@ -271,12 +235,11 @@ local function curtab(method, ...)
return tabpage(method, tab, ...)
end
restart()
clear()
return {
clear = clear,
dedent = dedent,
restart = restart,
rawfeed = rawfeed,
insert = insert,
feed = feed,

View File

@@ -50,7 +50,7 @@ describe('argument list', function()
execute('%d')
execute('0put=@a')
execute('1d | $d')
execute('$d')
eq(dedent([[
start of test file Xxx1

View File

@@ -51,7 +51,7 @@ describe(':ball', function()
execute('bf')
execute('%d')
execute('0put=@a')
execute('1d | $d')
execute('$d')
expect([[
start of test file Xxx4

View File

@@ -31,7 +31,7 @@ describe('CTRL-W CTRL-I', function()
-- Clean buffer and put register
feed('ggdG"ap')
execute('1,2d')
execute('1d')
-- The buffer should now contain:
expect([[

View File

@@ -35,8 +35,8 @@ describe(':edit', function()
execute('%d')
execute('0put a')
-- Remove empty lines
execute('1d | $d')
-- Remove empty line
execute('$d')
-- The buffer should now contain
expect([[

View File

@@ -25,7 +25,7 @@ describe('writing and reading a file of over 100 Kbyte', function()
execute('6005yank A')
execute('%d')
execute('0put a')
execute('1d | $d')
execute('$d')
execute('w!')
expect([[

View File

@@ -2,11 +2,10 @@
-- other tests, so restart nvim in the teardown hook
local helpers = require('test.functional.helpers')
local restart, command, clear = helpers.restart, helpers.command, helpers.clear
local command, clear = helpers.command, helpers.clear
describe('options', function()
setup(clear)
teardown(restart)
it('is working', function()
command('options')