0
0
mirror of https://github.com/vim/vim.git synced 2025-09-25 03:54:15 -04:00

patch 8.0.0477: the client-server test may hang when failing

Problem:    The client-server test may hang when failing.
Solution:   Set a timer.  Add assert_report()
This commit is contained in:
Bram Moolenaar
2017-03-18 19:42:22 +01:00
parent 7a43cb9cb5
commit 42205551b1
9 changed files with 149 additions and 64 deletions

View File

@@ -1,4 +1,4 @@
*eval.txt* For Vim version 8.0. Last change: 2017 Mar 09 *eval.txt* For Vim version 8.0. Last change: 2017 Mar 18
VIM REFERENCE MANUAL by Bram Moolenaar VIM REFERENCE MANUAL by Bram Moolenaar
@@ -1986,15 +1986,22 @@ argidx() Number current index in the argument list
arglistid([{winnr} [, {tabnr}]]) Number argument list id arglistid([{winnr} [, {tabnr}]]) Number argument list id
argv({nr}) String {nr} entry of the argument list argv({nr}) String {nr} entry of the argument list
argv() List the argument list argv() List the argument list
assert_equal({exp}, {act} [, {msg}]) none assert {exp} is equal to {act} assert_equal({exp}, {act} [, {msg}])
assert_exception({error} [, {msg}]) none assert {error} is in v:exception none assert {exp} is equal to {act}
assert_exception({error} [, {msg}])
none assert {error} is in v:exception
assert_fails({cmd} [, {error}]) none assert {cmd} fails assert_fails({cmd} [, {error}]) none assert {cmd} fails
assert_false({actual} [, {msg}]) none assert {actual} is false assert_false({actual} [, {msg}])
none assert {actual} is false
assert_inrange({lower}, {upper}, {actual} [, {msg}]) assert_inrange({lower}, {upper}, {actual} [, {msg}])
none assert {actual} is inside the range none assert {actual} is inside the range
assert_match({pat}, {text} [, {msg}]) none assert {pat} matches {text} assert_match({pat}, {text} [, {msg}])
assert_notequal({exp}, {act} [, {msg}]) none assert {exp} is not equal {act} none assert {pat} matches {text}
assert_notmatch({pat}, {text} [, {msg}]) none assert {pat} not matches {text} assert_notequal({exp}, {act} [, {msg}])
none assert {exp} is not equal {act}
assert_notmatch({pat}, {text} [, {msg}])
none assert {pat} not matches {text}
assert_report({msg}) none report a test failure
assert_true({actual} [, {msg}]) none assert {actual} is true assert_true({actual} [, {msg}]) none assert {actual} is true
asin({expr}) Float arc sine of {expr} asin({expr}) Float arc sine of {expr}
atan({expr}) Float arc tangent of {expr} atan({expr}) Float arc tangent of {expr}
@@ -2583,6 +2590,9 @@ assert_notmatch({pattern}, {actual} [, {msg}])
The opposite of `assert_match()`: add an error message to The opposite of `assert_match()`: add an error message to
|v:errors| when {pattern} matches {actual}. |v:errors| when {pattern} matches {actual}.
assert_report({msg}) *assert_report()*
Report a test failure directly, using {msg}.
assert_true({actual} [, {msg}]) *assert_true()* assert_true({actual} [, {msg}]) *assert_true()*
When {actual} is not true an error message is added to When {actual} is not true an error message is added to
|v:errors|, like with |assert_equal()|. |v:errors|, like with |assert_equal()|.
@@ -3925,11 +3935,14 @@ foldtext() Returns a String, to be displayed for a closed fold. This is
|v:foldstart|, |v:foldend| and |v:folddashes| variables. |v:foldstart|, |v:foldend| and |v:folddashes| variables.
The returned string looks like this: > The returned string looks like this: >
+-- 45 lines: abcdef +-- 45 lines: abcdef
< The number of dashes depends on the foldlevel. The "45" is < The number of leading dashes depends on the foldlevel. The
the number of lines in the fold. "abcdef" is the text in the "45" is the number of lines in the fold. "abcdef" is the text
first non-blank line of the fold. Leading white space, "//" in the first non-blank line of the fold. Leading white space,
or "/*" and the text from the 'foldmarker' and 'commentstring' "//" or "/*" and the text from the 'foldmarker' and
options is removed. 'commentstring' options is removed.
When used to draw the actual foldtext, the rest of the line
will be filled with the fold char from the 'fillchars'
setting.
{not available when compiled without the |+folding| feature} {not available when compiled without the |+folding| feature}
foldtextresult({lnum}) *foldtextresult()* foldtextresult({lnum}) *foldtextresult()*

View File

@@ -9083,6 +9083,17 @@ assert_bool(typval_T *argvars, int isTrue)
} }
} }
void
assert_report(typval_T *argvars)
{
garray_T ga;
prepare_assert_error(&ga);
ga_concat(&ga, get_tv_string(&argvars[0]));
assert_error(&ga);
ga_clear(&ga);
}
void void
assert_exception(typval_T *argvars) assert_exception(typval_T *argvars)
{ {

View File

@@ -52,6 +52,7 @@ static void f_assert_inrange(typval_T *argvars, typval_T *rettv);
static void f_assert_match(typval_T *argvars, typval_T *rettv); static void f_assert_match(typval_T *argvars, typval_T *rettv);
static void f_assert_notequal(typval_T *argvars, typval_T *rettv); static void f_assert_notequal(typval_T *argvars, typval_T *rettv);
static void f_assert_notmatch(typval_T *argvars, typval_T *rettv); static void f_assert_notmatch(typval_T *argvars, typval_T *rettv);
static void f_assert_report(typval_T *argvars, typval_T *rettv);
static void f_assert_true(typval_T *argvars, typval_T *rettv); static void f_assert_true(typval_T *argvars, typval_T *rettv);
#ifdef FEAT_FLOAT #ifdef FEAT_FLOAT
static void f_asin(typval_T *argvars, typval_T *rettv); static void f_asin(typval_T *argvars, typval_T *rettv);
@@ -483,6 +484,7 @@ static struct fst
{"assert_match", 2, 3, f_assert_match}, {"assert_match", 2, 3, f_assert_match},
{"assert_notequal", 2, 3, f_assert_notequal}, {"assert_notequal", 2, 3, f_assert_notequal},
{"assert_notmatch", 2, 3, f_assert_notmatch}, {"assert_notmatch", 2, 3, f_assert_notmatch},
{"assert_report", 1, 1, f_assert_report},
{"assert_true", 1, 2, f_assert_true}, {"assert_true", 1, 2, f_assert_true},
#ifdef FEAT_FLOAT #ifdef FEAT_FLOAT
{"atan", 1, 1, f_atan}, {"atan", 1, 1, f_atan},
@@ -1313,6 +1315,15 @@ f_assert_notmatch(typval_T *argvars, typval_T *rettv UNUSED)
assert_match_common(argvars, ASSERT_NOTMATCH); assert_match_common(argvars, ASSERT_NOTMATCH);
} }
/*
* "assert_report(msg)" function
*/
static void
f_assert_report(typval_T *argvars, typval_T *rettv UNUSED)
{
assert_report(argvars);
}
/* /*
* "assert_true(actual[, msg])" function * "assert_true(actual[, msg])" function
*/ */

View File

@@ -596,6 +596,10 @@ ServerWait(
if (seconds >= 0 && (now - start) >= seconds) if (seconds >= 0 && (now - start) >= seconds)
break; break;
#ifdef FEAT_TIMERS
check_due_timer();
#endif
/* Just look out for the answer without calling back into Vim */ /* Just look out for the answer without calling back into Vim */
if (localLoop) if (localLoop)
{ {

View File

@@ -2570,6 +2570,9 @@ serverGetReply(HWND server, int *expr_res, int remove, int wait)
/* Loop until we receive a reply */ /* Loop until we receive a reply */
while (reply_received == 0) while (reply_received == 0)
{ {
#ifdef FEAT_TIMERS
check_due_timer();
#endif
/* Wait for a SendMessage() call to us. This could be the reply /* Wait for a SendMessage() call to us. This could be the reply
* we are waiting for. Use a timeout of a second, to catch the * we are waiting for. Use a timeout of a second, to catch the
* situation that the server died unexpectedly. */ * situation that the server died unexpectedly. */

View File

@@ -123,6 +123,7 @@ void assert_equal_common(typval_T *argvars, assert_type_T atype);
void assert_match_common(typval_T *argvars, assert_type_T atype); void assert_match_common(typval_T *argvars, assert_type_T atype);
void assert_inrange(typval_T *argvars); void assert_inrange(typval_T *argvars);
void assert_bool(typval_T *argvars, int isTrue); void assert_bool(typval_T *argvars, int isTrue);
void assert_report(typval_T *argvars);
void assert_exception(typval_T *argvars); void assert_exception(typval_T *argvars);
void assert_fails(typval_T *argvars); void assert_fails(typval_T *argvars);
void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv, char_u *exp_str, typval_T *exp_tv, typval_T *got_tv, assert_type_T atype); void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv, char_u *exp_str, typval_T *exp_tv, typval_T *got_tv, assert_type_T atype);

View File

@@ -86,7 +86,7 @@ function GetAllocId(name)
return lnum - top - 1 return lnum - top - 1
endfunc endfunc
function RunTheTest(test) func RunTheTest(test)
echo 'Executing ' . a:test echo 'Executing ' . a:test
" Avoid stopping at the "hit enter" prompt " Avoid stopping at the "hit enter" prompt
@@ -142,6 +142,60 @@ function RunTheTest(test)
set nomodified set nomodified
endfunc endfunc
func AfterTheTest()
if len(v:errors) > 0
let s:fail += 1
call add(s:errors, 'Found errors in ' . s:test . ':')
call extend(s:errors, v:errors)
let v:errors = []
endif
endfunc
" This function can be called by a test if it wants to abort testing.
func FinishTesting()
call AfterTheTest()
" Don't write viminfo on exit.
set viminfo=
if s:fail == 0
" Success, create the .res file so that make knows it's done.
exe 'split ' . fnamemodify(g:testname, ':r') . '.res'
write
endif
if len(s:errors) > 0
" Append errors to test.log
split test.log
call append(line('$'), '')
call append(line('$'), 'From ' . g:testname . ':')
call append(line('$'), s:errors)
write
endif
let message = 'Executed ' . s:done . (s:done > 1 ? ' tests' : ' test')
echo message
call add(s:messages, message)
if s:fail > 0
let message = s:fail . ' FAILED:'
echo message
call add(s:messages, message)
call extend(s:messages, s:errors)
endif
" Add SKIPPED messages
call extend(s:messages, s:skipped)
" Append messages to the file "messages"
split messages
call append(line('$'), '')
call append(line('$'), 'From ' . g:testname . ':')
call append(line('$'), s:messages)
write
qall!
endfunc
" Source the test script. First grab the file name, in case the script " Source the test script. First grab the file name, in case the script
" navigates away. g:testname can be used by the tests. " navigates away. g:testname can be used by the tests.
let g:testname = expand('%') let g:testname = expand('%')
@@ -164,6 +218,7 @@ endif
" Names of flaky tests. " Names of flaky tests.
let s:flaky = [ let s:flaky = [
\ 'Test_client_server()',
\ 'Test_close_and_exit_cb()', \ 'Test_close_and_exit_cb()',
\ 'Test_collapse_buffers()', \ 'Test_collapse_buffers()',
\ 'Test_communicate()', \ 'Test_communicate()',
@@ -197,52 +252,9 @@ for s:test in sort(s:tests)
call RunTheTest(s:test) call RunTheTest(s:test)
endif endif
if len(v:errors) > 0 call AfterTheTest()
let s:fail += 1
call add(s:errors, 'Found errors in ' . s:test . ':')
call extend(s:errors, v:errors)
let v:errors = []
endif
endfor endfor
" Don't write viminfo on exit. call FinishTesting()
set viminfo=
if s:fail == 0
" Success, create the .res file so that make knows it's done.
exe 'split ' . fnamemodify(g:testname, ':r') . '.res'
write
endif
if len(s:errors) > 0
" Append errors to test.log
split test.log
call append(line('$'), '')
call append(line('$'), 'From ' . g:testname . ':')
call append(line('$'), s:errors)
write
endif
let message = 'Executed ' . s:done . (s:done > 1 ? ' tests' : ' test')
echo message
call add(s:messages, message)
if s:fail > 0
let message = s:fail . ' FAILED:'
echo message
call add(s:messages, message)
call extend(s:messages, s:errors)
endif
" Add SKIPPED messages
call extend(s:messages, s:skipped)
" Append messages to the file "messages"
split messages
call append(line('$'), '')
call append(line('$'), 'From ' . g:testname . ':')
call append(line('$'), s:messages)
write
qall!
" vim: shiftwidth=2 sts=2 expandtab " vim: shiftwidth=2 sts=2 expandtab

View File

@@ -6,29 +6,46 @@ endif
source shared.vim source shared.vim
let s:where = 0
func Abort(id)
call assert_report('Test timed out at ' . s:where)
call FinishTesting()
endfunc
func Test_client_server() func Test_client_server()
let cmd = GetVimCommand() let cmd = GetVimCommand()
if cmd == '' if cmd == ''
return return
endif endif
let name = 'XVIMTEXT'
" Some of these commands may hang when failing.
call timer_start(10000, 'Abort')
let s:where = 1
let name = 'XVIMTEST'
let cmd .= ' --servername ' . name let cmd .= ' --servername ' . name
let g:job = job_start(cmd, {'stoponexit': 'kill', 'out_io': 'null'}) let g:job = job_start(cmd, {'stoponexit': 'kill', 'out_io': 'null'})
call WaitFor('job_status(g:job) == "run"') call WaitFor('job_status(g:job) == "run"')
if job_status(g:job) != 'run' if job_status(g:job) != 'run'
call assert_true(0, 'Cannot run the Vim server') call assert_report('Cannot run the Vim server')
return return
endif endif
let s:where = 2
" Takes a short while for the server to be active. " Takes a short while for the server to be active.
call WaitFor('serverlist() =~ "' . name . '"') call WaitFor('serverlist() =~ "' . name . '"')
call assert_match(name, serverlist()) call assert_match(name, serverlist())
let s:where = 3
call remote_foreground(name) call remote_foreground(name)
let s:where = 4
call remote_send(name, ":let testvar = 'yes'\<CR>") call remote_send(name, ":let testvar = 'yes'\<CR>")
let s:where = 5
call WaitFor('remote_expr("' . name . '", "testvar") == "yes"') call WaitFor('remote_expr("' . name . '", "testvar") == "yes"')
let s:where = 6
call assert_equal('yes', remote_expr(name, "testvar")) call assert_equal('yes', remote_expr(name, "testvar"))
let s:where = 7
if has('unix') && has('gui') && !has('gui_running') if has('unix') && has('gui') && !has('gui_running')
" Running in a terminal and the GUI is avaiable: Tell the server to open " Running in a terminal and the GUI is avaiable: Tell the server to open
@@ -36,29 +53,40 @@ func Test_client_server()
" Need to wait for the GUI to start up, otherwise the send hangs in trying " Need to wait for the GUI to start up, otherwise the send hangs in trying
" to send to the terminal window. " to send to the terminal window.
call remote_send(name, ":gui -f\<CR>") call remote_send(name, ":gui -f\<CR>")
let s:where = 8
sleep 500m sleep 500m
call remote_send(name, ":let testvar = 'maybe'\<CR>") call remote_send(name, ":let testvar = 'maybe'\<CR>")
let s:where = 9
call WaitFor('remote_expr("' . name . '", "testvar") == "maybe"') call WaitFor('remote_expr("' . name . '", "testvar") == "maybe"')
let s:where = 10
call assert_equal('maybe', remote_expr(name, "testvar")) call assert_equal('maybe', remote_expr(name, "testvar"))
let s:where = 11
endif endif
call assert_fails('call remote_send("XXX", ":let testvar = ''yes''\<CR>")', 'E241') call assert_fails('call remote_send("XXX", ":let testvar = ''yes''\<CR>")', 'E241')
let s:where = 12
" Expression evaluated locally. " Expression evaluated locally.
if v:servername == '' if v:servername == ''
call remote_startserver('MYSELF') call remote_startserver('MYSELF')
let s:where = 13
call assert_equal('MYSELF', v:servername) call assert_equal('MYSELF', v:servername)
endif endif
let g:testvar = 'myself' let g:testvar = 'myself'
call assert_equal('myself', remote_expr(v:servername, 'testvar')) call assert_equal('myself', remote_expr(v:servername, 'testvar'))
let s:where = 14
call remote_send(name, ":call server2client(expand('<client>'), 'got it')\<CR>", 'g:myserverid') call remote_send(name, ":call server2client(expand('<client>'), 'got it')\<CR>", 'g:myserverid')
let s:where = 15
call assert_equal('got it', remote_read(g:myserverid)) call assert_equal('got it', remote_read(g:myserverid))
let s:where = 16
call remote_send(name, ":qa!\<CR>") call remote_send(name, ":qa!\<CR>")
let s:where = 17
call WaitFor('job_status(g:job) == "dead"') call WaitFor('job_status(g:job) == "dead"')
let s:where = 18
if job_status(g:job) != 'dead' if job_status(g:job) != 'dead'
call assert_true(0, 'Server did not exit') call assert_report('Server did not exit')
call job_stop(g:job, 'kill') call job_stop(g:job, 'kill')
endif endif
endfunc endfunc

View File

@@ -764,6 +764,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
477,
/**/ /**/
476, 476,
/**/ /**/