1" Test for channel functions. 2scriptencoding utf-8 3 4if !has('channel') 5 finish 6endif 7 8" This test requires the Python command to run the test server. 9" This most likely only works on Unix and Windows. 10if has('unix') 11 " We also need the job feature or the pkill command to make sure the server 12 " can be stopped. 13 if !(executable('python') && (has('job') || executable('pkill'))) 14 finish 15 endif 16 let s:python = 'python' 17elseif has('win32') 18 " Use Python Launcher for Windows (py.exe) if available. 19 if executable('py.exe') 20 let s:python = 'py.exe' 21 elseif executable('python.exe') 22 let s:python = 'python.exe' 23 else 24 finish 25 endif 26else 27 " Can't run this test. 28 finish 29endif 30 31let s:chopt = {} 32 33" Run "testfunc" after sarting the server and stop the server afterwards. 34func s:run_server(testfunc, ...) 35 " The Python program writes the port number in Xportnr. 36 call delete("Xportnr") 37 38 if a:0 == 1 39 let arg = ' ' . a:1 40 else 41 let arg = '' 42 endif 43 let cmd = s:python . " test_channel.py" . arg 44 45 try 46 if has('job') 47 let s:job = job_start(cmd, {"stoponexit": "hup"}) 48 call job_setoptions(s:job, {"stoponexit": "kill"}) 49 elseif has('win32') 50 exe 'silent !start cmd /c start "test_channel" ' . cmd 51 else 52 exe 'silent !' . cmd . '&' 53 endif 54 55 " Wait for up to 2 seconds for the port number to be there. 56 let l = [] 57 for i in range(200) 58 try 59 let l = readfile("Xportnr") 60 catch 61 endtry 62 if len(l) >= 1 63 break 64 endif 65 sleep 10m 66 endfor 67 call delete("Xportnr") 68 69 if len(l) == 0 70 " Can't make the connection, give up. 71 call assert_false(1, "Can't start test_channel.py") 72 return -1 73 endif 74 let port = l[0] 75 76 call call(function(a:testfunc), [port]) 77 catch 78 call assert_false(1, "Caught exception: " . v:exception) 79 finally 80 call s:kill_server() 81 endtry 82endfunc 83 84func s:kill_server() 85 if has('job') 86 if exists('s:job') 87 call job_stop(s:job) 88 unlet s:job 89 endif 90 elseif has('win32') 91 call system('taskkill /IM ' . s:python . ' /T /F /FI "WINDOWTITLE eq test_channel"') 92 else 93 call system("pkill -f test_channel.py") 94 endif 95endfunc 96 97let s:responseMsg = '' 98func s:RequestHandler(handle, msg) 99 let s:responseHandle = a:handle 100 let s:responseMsg = a:msg 101endfunc 102 103" Wait for up to a second for "expr" to become true. 104func s:waitFor(expr) 105 for i in range(100) 106 try 107 if eval(a:expr) 108 return 109 endif 110 catch 111 endtry 112 sleep 10m 113 endfor 114endfunc 115 116func s:communicate(port) 117 let handle = ch_open('localhost:' . a:port, s:chopt) 118 if ch_status(handle) == "fail" 119 call assert_false(1, "Can't open channel") 120 return 121 endif 122 if has('job') 123 " check that getjob without a job is handled correctly 124 call assert_equal('no process', string(ch_getjob(handle))) 125 endif 126 let dict = ch_info(handle) 127 call assert_true(dict.id != 0) 128 call assert_equal('open', dict.status) 129 call assert_equal(a:port, string(dict.port)) 130 call assert_equal('open', dict.sock_status) 131 call assert_equal('socket', dict.sock_io) 132 133 " Simple string request and reply. 134 call assert_equal('got it', ch_evalexpr(handle, 'hello!')) 135 136 " Malformed command should be ignored. 137 call assert_equal('ok', ch_evalexpr(handle, 'malformed1')) 138 call assert_equal('ok', ch_evalexpr(handle, 'malformed2')) 139 call assert_equal('ok', ch_evalexpr(handle, 'malformed3')) 140 141 " split command should work 142 call assert_equal('ok', ch_evalexpr(handle, 'split')) 143 call s:waitFor('exists("g:split")') 144 call assert_equal(123, g:split) 145 146 " Request that triggers sending two ex commands. These will usually be 147 " handled before getting the response, but it's not guaranteed, thus wait a 148 " tiny bit for the commands to get executed. 149 call assert_equal('ok', ch_evalexpr(handle, 'make change')) 150 call s:waitFor('"added2" == getline("$")') 151 call assert_equal('added1', getline(line('$') - 1)) 152 call assert_equal('added2', getline('$')) 153 154 " Request command "foo bar", which fails silently. 155 call assert_equal('ok', ch_evalexpr(handle, 'bad command')) 156 call s:waitFor('v:errmsg =~ "E492"') 157 call assert_match('E492:.*foo bar', v:errmsg) 158 159 call assert_equal('ok', ch_evalexpr(handle, 'do normal', {'timeout': 100})) 160 call s:waitFor('"added more" == getline("$")') 161 call assert_equal('added more', getline('$')) 162 163 " Send a request with a specific handler. 164 call ch_sendexpr(handle, 'hello!', {'callback': 's:RequestHandler'}) 165 call s:waitFor('exists("s:responseHandle")') 166 if !exists('s:responseHandle') 167 call assert_false(1, 's:responseHandle was not set') 168 else 169 call assert_equal(handle, s:responseHandle) 170 unlet s:responseHandle 171 endif 172 call assert_equal('got it', s:responseMsg) 173 174 let s:responseMsg = '' 175 call ch_sendexpr(handle, 'hello!', {'callback': function('s:RequestHandler')}) 176 call s:waitFor('exists("s:responseHandle")') 177 if !exists('s:responseHandle') 178 call assert_false(1, 's:responseHandle was not set') 179 else 180 call assert_equal(handle, s:responseHandle) 181 unlet s:responseHandle 182 endif 183 call assert_equal('got it', s:responseMsg) 184 185 " Collect garbage, tests that our handle isn't collected. 186 call garbagecollect() 187 188 " check setting options (without testing the effect) 189 call ch_setoptions(handle, {'callback': 's:NotUsed'}) 190 call ch_setoptions(handle, {'timeout': 1111}) 191 call ch_setoptions(handle, {'mode': 'json'}) 192 call assert_fails("call ch_setoptions(handle, {'waittime': 111})", "E475") 193 call ch_setoptions(handle, {'callback': ''}) 194 195 " Send an eval request that works. 196 call assert_equal('ok', ch_evalexpr(handle, 'eval-works')) 197 sleep 10m 198 call assert_equal([-1, 'foo123'], ch_evalexpr(handle, 'eval-result')) 199 200 " Send an eval request with special characters. 201 call assert_equal('ok', ch_evalexpr(handle, 'eval-special')) 202 sleep 10m 203 call assert_equal([-2, "foo\x7f\x10\x01bar"], ch_evalexpr(handle, 'eval-result')) 204 205 " Send an eval request to get a line with special characters. 206 call setline(3, "a\nb\<CR>c\x01d\x7fe") 207 call assert_equal('ok', ch_evalexpr(handle, 'eval-getline')) 208 sleep 10m 209 call assert_equal([-3, "a\nb\<CR>c\x01d\x7fe"], ch_evalexpr(handle, 'eval-result')) 210 211 " Send an eval request that fails. 212 call assert_equal('ok', ch_evalexpr(handle, 'eval-fails')) 213 sleep 10m 214 call assert_equal([-4, 'ERROR'], ch_evalexpr(handle, 'eval-result')) 215 216 " Send an eval request that works but can't be encoded. 217 call assert_equal('ok', ch_evalexpr(handle, 'eval-error')) 218 sleep 10m 219 call assert_equal([-5, 'ERROR'], ch_evalexpr(handle, 'eval-result')) 220 221 " Send a bad eval request. There will be no response. 222 call assert_equal('ok', ch_evalexpr(handle, 'eval-bad')) 223 sleep 10m 224 call assert_equal([-5, 'ERROR'], ch_evalexpr(handle, 'eval-result')) 225 226 " Send an expr request 227 call assert_equal('ok', ch_evalexpr(handle, 'an expr')) 228 call s:waitFor('"three" == getline("$")') 229 call assert_equal('one', getline(line('$') - 2)) 230 call assert_equal('two', getline(line('$') - 1)) 231 call assert_equal('three', getline('$')) 232 233 " Request a redraw, we don't check for the effect. 234 call assert_equal('ok', ch_evalexpr(handle, 'redraw')) 235 call assert_equal('ok', ch_evalexpr(handle, 'redraw!')) 236 237 call assert_equal('ok', ch_evalexpr(handle, 'empty-request')) 238 239 " Reading while there is nothing available. 240 call assert_equal(v:none, ch_read(handle, {'timeout': 0})) 241 let start = reltime() 242 call assert_equal(v:none, ch_read(handle, {'timeout': 333})) 243 let elapsed = reltime(start) 244 call assert_true(reltimefloat(elapsed) > 0.3) 245 call assert_true(reltimefloat(elapsed) < 0.6) 246 247 " Send without waiting for a response, then wait for a response. 248 call ch_sendexpr(handle, 'wait a bit') 249 let resp = ch_read(handle) 250 call assert_equal(type([]), type(resp)) 251 call assert_equal(type(11), type(resp[0])) 252 call assert_equal('waited', resp[1]) 253 254 " make the server quit, can't check if this works, should not hang. 255 call ch_sendexpr(handle, '!quit!') 256endfunc 257 258func Test_communicate() 259 call ch_log('Test_communicate()') 260 call s:run_server('s:communicate') 261endfunc 262 263" Test that we can open two channels. 264func s:two_channels(port) 265 let handle = ch_open('localhost:' . a:port, s:chopt) 266 if ch_status(handle) == "fail" 267 call assert_false(1, "Can't open channel") 268 return 269 endif 270 271 call assert_equal('got it', ch_evalexpr(handle, 'hello!')) 272 273 let newhandle = ch_open('localhost:' . a:port, s:chopt) 274 if ch_status(newhandle) == "fail" 275 call assert_false(1, "Can't open second channel") 276 return 277 endif 278 call assert_equal('got it', ch_evalexpr(newhandle, 'hello!')) 279 call assert_equal('got it', ch_evalexpr(handle, 'hello!')) 280 281 call ch_close(handle) 282 call assert_equal('got it', ch_evalexpr(newhandle, 'hello!')) 283 284 call ch_close(newhandle) 285endfunc 286 287func Test_two_channels() 288 call ch_log('Test_two_channels()') 289 call s:run_server('s:two_channels') 290endfunc 291 292" Test that a server crash is handled gracefully. 293func s:server_crash(port) 294 let handle = ch_open('localhost:' . a:port, s:chopt) 295 if ch_status(handle) == "fail" 296 call assert_false(1, "Can't open channel") 297 return 298 endif 299 300 call ch_evalexpr(handle, '!crash!') 301 302 sleep 10m 303endfunc 304 305func Test_server_crash() 306 call ch_log('Test_server_crash()') 307 call s:run_server('s:server_crash') 308endfunc 309 310""""""""" 311 312let s:reply = "" 313func s:Handler(chan, msg) 314 unlet s:reply 315 let s:reply = a:msg 316endfunc 317 318func s:channel_handler(port) 319 let handle = ch_open('localhost:' . a:port, s:chopt) 320 if ch_status(handle) == "fail" 321 call assert_false(1, "Can't open channel") 322 return 323 endif 324 325 " Test that it works while waiting on a numbered message. 326 call assert_equal('ok', ch_evalexpr(handle, 'call me')) 327 call s:waitFor('"we called you" == s:reply') 328 call assert_equal('we called you', s:reply) 329 330 " Test that it works while not waiting on a numbered message. 331 call ch_sendexpr(handle, 'call me again') 332 call s:waitFor('"we did call you" == s:reply') 333 call assert_equal('we did call you', s:reply) 334endfunc 335 336func Test_channel_handler() 337 call ch_log('Test_channel_handler()') 338 let s:chopt.callback = 's:Handler' 339 call s:run_server('s:channel_handler') 340 let s:chopt.callback = function('s:Handler') 341 call s:run_server('s:channel_handler') 342 unlet s:chopt.callback 343endfunc 344 345""""""""" 346 347let s:ch_reply = '' 348func s:ChHandler(chan, msg) 349 unlet s:ch_reply 350 let s:ch_reply = a:msg 351endfunc 352 353let s:zero_reply = '' 354func s:OneHandler(chan, msg) 355 unlet s:zero_reply 356 let s:zero_reply = a:msg 357endfunc 358 359func s:channel_zero(port) 360 let handle = ch_open('localhost:' . a:port, s:chopt) 361 if ch_status(handle) == "fail" 362 call assert_false(1, "Can't open channel") 363 return 364 endif 365 366 " Check that eval works. 367 call assert_equal('got it', ch_evalexpr(handle, 'hello!')) 368 369 " Check that eval works if a zero id message is sent back. 370 let s:ch_reply = '' 371 call assert_equal('sent zero', ch_evalexpr(handle, 'send zero')) 372 if s:has_handler 373 call s:waitFor('"zero index" == s:ch_reply') 374 call assert_equal('zero index', s:ch_reply) 375 else 376 sleep 20m 377 call assert_equal('', s:ch_reply) 378 endif 379 380 " Check that handler works if a zero id message is sent back. 381 let s:ch_reply = '' 382 let s:zero_reply = '' 383 call ch_sendexpr(handle, 'send zero', {'callback': 's:OneHandler'}) 384 call s:waitFor('"sent zero" == s:zero_reply') 385 if s:has_handler 386 call assert_equal('zero index', s:ch_reply) 387 else 388 call assert_equal('', s:ch_reply) 389 endif 390 call assert_equal('sent zero', s:zero_reply) 391endfunc 392 393func Test_zero_reply() 394 call ch_log('Test_zero_reply()') 395 " Run with channel handler 396 let s:has_handler = 1 397 let s:chopt.callback = 's:ChHandler' 398 call s:run_server('s:channel_zero') 399 unlet s:chopt.callback 400 401 " Run without channel handler 402 let s:has_handler = 0 403 call s:run_server('s:channel_zero') 404endfunc 405 406""""""""" 407 408let s:reply1 = "" 409func s:HandleRaw1(chan, msg) 410 unlet s:reply1 411 let s:reply1 = a:msg 412endfunc 413 414let s:reply2 = "" 415func s:HandleRaw2(chan, msg) 416 unlet s:reply2 417 let s:reply2 = a:msg 418endfunc 419 420let s:reply3 = "" 421func s:HandleRaw3(chan, msg) 422 unlet s:reply3 423 let s:reply3 = a:msg 424endfunc 425 426func s:raw_one_time_callback(port) 427 let handle = ch_open('localhost:' . a:port, s:chopt) 428 if ch_status(handle) == "fail" 429 call assert_false(1, "Can't open channel") 430 return 431 endif 432 call ch_setoptions(handle, {'mode': 'raw'}) 433 434 " The message are sent raw, we do our own JSON strings here. 435 call ch_sendraw(handle, "[1, \"hello!\"]", {'callback': 's:HandleRaw1'}) 436 call s:waitFor('s:reply1 != ""') 437 call assert_equal("[1, \"got it\"]", s:reply1) 438 call ch_sendraw(handle, "[2, \"echo something\"]", {'callback': 's:HandleRaw2'}) 439 call ch_sendraw(handle, "[3, \"wait a bit\"]", {'callback': 's:HandleRaw3'}) 440 call s:waitFor('s:reply2 != ""') 441 call assert_equal("[2, \"something\"]", s:reply2) 442 " wait for the 200 msec delayed reply 443 call s:waitFor('s:reply3 != ""') 444 call assert_equal("[3, \"waited\"]", s:reply3) 445endfunc 446 447func Test_raw_one_time_callback() 448 call ch_log('Test_raw_one_time_callback()') 449 call s:run_server('s:raw_one_time_callback') 450endfunc 451 452""""""""" 453 454" Test that trying to connect to a non-existing port fails quickly. 455func Test_connect_waittime() 456 call ch_log('Test_connect_waittime()') 457 let start = reltime() 458 let handle = ch_open('localhost:9876', s:chopt) 459 if ch_status(handle) != "fail" 460 " Oops, port does exists. 461 call ch_close(handle) 462 else 463 let elapsed = reltime(start) 464 call assert_true(reltimefloat(elapsed) < 1.0) 465 endif 466 467 " We intend to use a socket that doesn't exist and wait for half a second 468 " before giving up. If the socket does exist it can fail in various ways. 469 " Check for "Connection reset by peer" to avoid flakyness. 470 let start = reltime() 471 try 472 let handle = ch_open('localhost:9867', {'waittime': 500}) 473 if ch_status(handle) != "fail" 474 " Oops, port does exists. 475 call ch_close(handle) 476 else 477 " Failed connection should wait about 500 msec. Can be longer if the 478 " computer is busy with other things. 479 let elapsed = reltime(start) 480 call assert_true(reltimefloat(elapsed) > 0.3) 481 call assert_true(reltimefloat(elapsed) < 1.5) 482 endif 483 catch 484 if v:exception !~ 'Connection reset by peer' 485 call assert_false(1, "Caught exception: " . v:exception) 486 endif 487 endtry 488endfunc 489 490""""""""" 491 492func Test_raw_pipe() 493 if !has('job') 494 return 495 endif 496 call ch_log('Test_raw_pipe()') 497 let job = job_start(s:python . " test_channel_pipe.py", {'mode': 'raw'}) 498 call assert_equal("run", job_status(job)) 499 try 500 " For a change use the job where a channel is expected. 501 call ch_sendraw(job, "echo something\n") 502 let msg = ch_readraw(job) 503 call assert_equal("something\n", substitute(msg, "\r", "", 'g')) 504 505 call ch_sendraw(job, "double this\n") 506 let msg = ch_readraw(job) 507 call assert_equal("this\nAND this\n", substitute(msg, "\r", "", 'g')) 508 509 let reply = ch_evalraw(job, "quit\n", {'timeout': 100}) 510 call assert_equal("Goodbye!\n", substitute(reply, "\r", "", 'g')) 511 finally 512 call job_stop(job) 513 endtry 514 515 let s:job = job 516 call s:waitFor('"dead" == job_status(s:job)') 517 let info = job_info(job) 518 call assert_equal("dead", info.status) 519 call assert_equal("term", info.stoponexit) 520endfunc 521 522func Test_nl_pipe() 523 if !has('job') 524 return 525 endif 526 call ch_log('Test_nl_pipe()') 527 let job = job_start([s:python, "test_channel_pipe.py"]) 528 call assert_equal("run", job_status(job)) 529 try 530 let handle = job_getchannel(job) 531 call ch_sendraw(handle, "echo something\n") 532 call assert_equal("something", ch_readraw(handle)) 533 534 call ch_sendraw(handle, "echoerr wrong\n") 535 call assert_equal("wrong", ch_readraw(handle, {'part': 'err'})) 536 537 call ch_sendraw(handle, "double this\n") 538 call assert_equal("this", ch_readraw(handle)) 539 call assert_equal("AND this", ch_readraw(handle)) 540 541 let reply = ch_evalraw(handle, "quit\n") 542 call assert_equal("Goodbye!", reply) 543 finally 544 call job_stop(job) 545 endtry 546endfunc 547 548func Test_nl_err_to_out_pipe() 549 if !has('job') 550 return 551 endif 552 call ch_logfile('Xlog') 553 call ch_log('Test_nl_err_to_out_pipe()') 554 let job = job_start(s:python . " test_channel_pipe.py", {'err_io': 'out'}) 555 call assert_equal("run", job_status(job)) 556 try 557 let handle = job_getchannel(job) 558 call ch_sendraw(handle, "echo something\n") 559 call assert_equal("something", ch_readraw(handle)) 560 561 call ch_sendraw(handle, "echoerr wrong\n") 562 call assert_equal("wrong", ch_readraw(handle)) 563 finally 564 call job_stop(job) 565 call ch_logfile('') 566 let loglines = readfile('Xlog') 567 call assert_true(len(loglines) > 10) 568 let found_test = 0 569 let found_send = 0 570 let found_recv = 0 571 let found_stop = 0 572 for l in loglines 573 if l =~ 'Test_nl_err_to_out_pipe' 574 let found_test = 1 575 endif 576 if l =~ 'SEND on.*echo something' 577 let found_send = 1 578 endif 579 if l =~ 'RECV on.*something' 580 let found_recv = 1 581 endif 582 if l =~ 'Stopping job with' 583 let found_stop = 1 584 endif 585 endfor 586 call assert_equal(1, found_test) 587 call assert_equal(1, found_send) 588 call assert_equal(1, found_recv) 589 call assert_equal(1, found_stop) 590 call delete('Xlog') 591 endtry 592endfunc 593 594func Test_nl_read_file() 595 if !has('job') 596 return 597 endif 598 call ch_log('Test_nl_read_file()') 599 call writefile(['echo something', 'echoerr wrong', 'double this'], 'Xinput') 600 let job = job_start(s:python . " test_channel_pipe.py", 601 \ {'in_io': 'file', 'in_name': 'Xinput'}) 602 call assert_equal("run", job_status(job)) 603 try 604 let handle = job_getchannel(job) 605 call assert_equal("something", ch_readraw(handle)) 606 call assert_equal("wrong", ch_readraw(handle, {'part': 'err'})) 607 call assert_equal("this", ch_readraw(handle)) 608 call assert_equal("AND this", ch_readraw(handle)) 609 finally 610 call job_stop(job) 611 call delete('Xinput') 612 endtry 613endfunc 614 615func Test_nl_write_out_file() 616 if !has('job') 617 return 618 endif 619 call ch_log('Test_nl_write_out_file()') 620 let job = job_start(s:python . " test_channel_pipe.py", 621 \ {'out_io': 'file', 'out_name': 'Xoutput'}) 622 call assert_equal("run", job_status(job)) 623 try 624 let handle = job_getchannel(job) 625 call ch_sendraw(handle, "echo line one\n") 626 call ch_sendraw(handle, "echo line two\n") 627 call ch_sendraw(handle, "double this\n") 628 call s:waitFor('len(readfile("Xoutput")) > 2') 629 call assert_equal(['line one', 'line two', 'this', 'AND this'], readfile('Xoutput')) 630 finally 631 call job_stop(job) 632 call delete('Xoutput') 633 endtry 634endfunc 635 636func Test_nl_write_err_file() 637 if !has('job') 638 return 639 endif 640 call ch_log('Test_nl_write_err_file()') 641 let job = job_start(s:python . " test_channel_pipe.py", 642 \ {'err_io': 'file', 'err_name': 'Xoutput'}) 643 call assert_equal("run", job_status(job)) 644 try 645 let handle = job_getchannel(job) 646 call ch_sendraw(handle, "echoerr line one\n") 647 call ch_sendraw(handle, "echoerr line two\n") 648 call ch_sendraw(handle, "doubleerr this\n") 649 call s:waitFor('len(readfile("Xoutput")) > 2') 650 call assert_equal(['line one', 'line two', 'this', 'AND this'], readfile('Xoutput')) 651 finally 652 call job_stop(job) 653 call delete('Xoutput') 654 endtry 655endfunc 656 657func Test_nl_write_both_file() 658 if !has('job') 659 return 660 endif 661 call ch_log('Test_nl_write_both_file()') 662 let job = job_start(s:python . " test_channel_pipe.py", 663 \ {'out_io': 'file', 'out_name': 'Xoutput', 'err_io': 'out'}) 664 call assert_equal("run", job_status(job)) 665 try 666 let handle = job_getchannel(job) 667 call ch_sendraw(handle, "echoerr line one\n") 668 call ch_sendraw(handle, "echo line two\n") 669 call ch_sendraw(handle, "double this\n") 670 call ch_sendraw(handle, "doubleerr that\n") 671 call s:waitFor('len(readfile("Xoutput")) > 5') 672 call assert_equal(['line one', 'line two', 'this', 'AND this', 'that', 'AND that'], readfile('Xoutput')) 673 finally 674 call job_stop(job) 675 call delete('Xoutput') 676 endtry 677endfunc 678 679func Run_test_pipe_to_buffer(use_name) 680 if !has('job') 681 return 682 endif 683 call ch_log('Test_pipe_to_buffer()') 684 let options = {'out_io': 'buffer'} 685 if a:use_name 686 let options['out_name'] = 'pipe-output' 687 let firstline = 'Reading from channel output...' 688 else 689 sp pipe-output 690 let options['out_buf'] = bufnr('%') 691 quit 692 let firstline = '' 693 endif 694 let job = job_start(s:python . " test_channel_pipe.py", options) 695 call assert_equal("run", job_status(job)) 696 try 697 let handle = job_getchannel(job) 698 call ch_sendraw(handle, "echo line one\n") 699 call ch_sendraw(handle, "echo line two\n") 700 call ch_sendraw(handle, "double this\n") 701 call ch_sendraw(handle, "quit\n") 702 sp pipe-output 703 call s:waitFor('line("$") >= 6') 704 if getline('$') == 'DETACH' 705 $del 706 endif 707 call assert_equal([firstline, 'line one', 'line two', 'this', 'AND this', 'Goodbye!'], getline(1, '$')) 708 bwipe! 709 finally 710 call job_stop(job) 711 endtry 712endfunc 713 714func Test_pipe_to_buffer_name() 715 call Run_test_pipe_to_buffer(1) 716endfunc 717 718func Test_pipe_to_buffer_nr() 719 call Run_test_pipe_to_buffer(0) 720endfunc 721 722func Run_test_pipe_err_to_buffer(use_name) 723 if !has('job') 724 return 725 endif 726 call ch_log('Test_pipe_err_to_buffer()') 727 let options = {'err_io': 'buffer'} 728 if a:use_name 729 let options['err_name'] = 'pipe-err' 730 let firstline = 'Reading from channel error...' 731 else 732 sp pipe-err 733 let options['err_buf'] = bufnr('%') 734 quit 735 let firstline = '' 736 endif 737 let job = job_start(s:python . " test_channel_pipe.py", options) 738 call assert_equal("run", job_status(job)) 739 try 740 let handle = job_getchannel(job) 741 call ch_sendraw(handle, "echoerr line one\n") 742 call ch_sendraw(handle, "echoerr line two\n") 743 call ch_sendraw(handle, "doubleerr this\n") 744 call ch_sendraw(handle, "quit\n") 745 sp pipe-err 746 call s:waitFor('line("$") >= 5') 747 call assert_equal([firstline, 'line one', 'line two', 'this', 'AND this'], getline(1, '$')) 748 bwipe! 749 finally 750 call job_stop(job) 751 endtry 752endfunc 753 754func Test_pipe_err_to_buffer_name() 755 call Run_test_pipe_err_to_buffer(1) 756endfunc 757 758func Test_pipe_err_to_buffer_nr() 759 call Run_test_pipe_err_to_buffer(0) 760endfunc 761 762func Test_pipe_both_to_buffer() 763 if !has('job') 764 return 765 endif 766 call ch_log('Test_pipe_both_to_buffer()') 767 let job = job_start(s:python . " test_channel_pipe.py", 768 \ {'out_io': 'buffer', 'out_name': 'pipe-err', 'err_io': 'out'}) 769 call assert_equal("run", job_status(job)) 770 try 771 let handle = job_getchannel(job) 772 call ch_sendraw(handle, "echo line one\n") 773 call ch_sendraw(handle, "echoerr line two\n") 774 call ch_sendraw(handle, "double this\n") 775 call ch_sendraw(handle, "doubleerr that\n") 776 call ch_sendraw(handle, "quit\n") 777 sp pipe-err 778 call s:waitFor('line("$") >= 7') 779 call assert_equal(['Reading from channel output...', 'line one', 'line two', 'this', 'AND this', 'that', 'AND that', 'Goodbye!'], getline(1, '$')) 780 bwipe! 781 finally 782 call job_stop(job) 783 endtry 784endfunc 785 786func Run_test_pipe_from_buffer(use_name) 787 if !has('job') 788 return 789 endif 790 call ch_log('Test_pipe_from_buffer()') 791 792 sp pipe-input 793 call setline(1, ['echo one', 'echo two', 'echo three']) 794 let options = {'in_io': 'buffer', 'block_write': 1} 795 if a:use_name 796 let options['in_name'] = 'pipe-input' 797 else 798 let options['in_buf'] = bufnr('%') 799 endif 800 801 let job = job_start(s:python . " test_channel_pipe.py", options) 802 call assert_equal("run", job_status(job)) 803 try 804 let handle = job_getchannel(job) 805 call assert_equal('one', ch_read(handle)) 806 call assert_equal('two', ch_read(handle)) 807 call assert_equal('three', ch_read(handle)) 808 bwipe! 809 finally 810 call job_stop(job) 811 endtry 812endfunc 813 814func Test_pipe_from_buffer_name() 815 call Run_test_pipe_from_buffer(1) 816endfunc 817 818func Test_pipe_from_buffer_nr() 819 call Run_test_pipe_from_buffer(0) 820endfunc 821 822func Test_pipe_to_nameless_buffer() 823 if !has('job') 824 return 825 endif 826 call ch_log('Test_pipe_to_nameless_buffer()') 827 let job = job_start(s:python . " test_channel_pipe.py", 828 \ {'out_io': 'buffer'}) 829 call assert_equal("run", job_status(job)) 830 try 831 let handle = job_getchannel(job) 832 call ch_sendraw(handle, "echo line one\n") 833 call ch_sendraw(handle, "echo line two\n") 834 exe ch_getbufnr(handle, "out") . 'sbuf' 835 call s:waitFor('line("$") >= 3') 836 call assert_equal(['Reading from channel output...', 'line one', 'line two'], getline(1, '$')) 837 bwipe! 838 finally 839 call job_stop(job) 840 endtry 841endfunc 842 843func Test_pipe_to_buffer_json() 844 if !has('job') 845 return 846 endif 847 call ch_log('Test_pipe_to_buffer_json()') 848 let job = job_start(s:python . " test_channel_pipe.py", 849 \ {'out_io': 'buffer', 'out_mode': 'json'}) 850 call assert_equal("run", job_status(job)) 851 try 852 let handle = job_getchannel(job) 853 call ch_sendraw(handle, "echo [0, \"hello\"]\n") 854 call ch_sendraw(handle, "echo [-2, 12.34]\n") 855 exe ch_getbufnr(handle, "out") . 'sbuf' 856 call s:waitFor('line("$") >= 3') 857 call assert_equal(['Reading from channel output...', '[0,"hello"]', '[-2,12.34]'], getline(1, '$')) 858 bwipe! 859 finally 860 call job_stop(job) 861 endtry 862endfunc 863 864" Wait a little while for the last line, minus "offset", to equal "line". 865func s:wait_for_last_line(line, offset) 866 for i in range(100) 867 if getline(line('$') - a:offset) == a:line 868 break 869 endif 870 sleep 10m 871 endfor 872endfunc 873 874func Test_pipe_io_two_buffers() 875 if !has('job') 876 return 877 endif 878 call ch_log('Test_pipe_io_two_buffers()') 879 880 " Create two buffers, one to read from and one to write to. 881 split pipe-output 882 set buftype=nofile 883 split pipe-input 884 set buftype=nofile 885 886 let job = job_start(s:python . " test_channel_pipe.py", 887 \ {'in_io': 'buffer', 'in_name': 'pipe-input', 'in_top': 0, 888 \ 'out_io': 'buffer', 'out_name': 'pipe-output', 889 \ 'block_write': 1}) 890 call assert_equal("run", job_status(job)) 891 try 892 exe "normal Gaecho hello\<CR>" 893 exe bufwinnr('pipe-output') . "wincmd w" 894 call s:wait_for_last_line('hello', 0) 895 call assert_equal('hello', getline('$')) 896 897 exe bufwinnr('pipe-input') . "wincmd w" 898 exe "normal Gadouble this\<CR>" 899 exe bufwinnr('pipe-output') . "wincmd w" 900 call s:wait_for_last_line('AND this', 0) 901 call assert_equal('this', getline(line('$') - 1)) 902 call assert_equal('AND this', getline('$')) 903 904 bwipe! 905 exe bufwinnr('pipe-input') . "wincmd w" 906 bwipe! 907 finally 908 call job_stop(job) 909 endtry 910endfunc 911 912func Test_pipe_io_one_buffer() 913 if !has('job') 914 return 915 endif 916 call ch_log('Test_pipe_io_one_buffer()') 917 918 " Create one buffer to read from and to write to. 919 split pipe-io 920 set buftype=nofile 921 922 let job = job_start(s:python . " test_channel_pipe.py", 923 \ {'in_io': 'buffer', 'in_name': 'pipe-io', 'in_top': 0, 924 \ 'out_io': 'buffer', 'out_name': 'pipe-io', 925 \ 'block_write': 1}) 926 call assert_equal("run", job_status(job)) 927 try 928 exe "normal Goecho hello\<CR>" 929 call s:wait_for_last_line('hello', 1) 930 call assert_equal('hello', getline(line('$') - 1)) 931 932 exe "normal Gadouble this\<CR>" 933 call s:wait_for_last_line('AND this', 1) 934 call assert_equal('this', getline(line('$') - 2)) 935 call assert_equal('AND this', getline(line('$') - 1)) 936 937 bwipe! 938 finally 939 call job_stop(job) 940 endtry 941endfunc 942 943func Test_pipe_null() 944 if !has('job') 945 return 946 endif 947 call ch_log('Test_pipe_null()') 948 949 " We cannot check that no I/O works, we only check that the job starts 950 " properly. 951 let job = job_start(s:python . " test_channel_pipe.py something", 952 \ {'in_io': 'null'}) 953 call assert_equal("run", job_status(job)) 954 try 955 call assert_equal('something', ch_read(job)) 956 finally 957 call job_stop(job) 958 endtry 959 960 let job = job_start(s:python . " test_channel_pipe.py err-out", 961 \ {'out_io': 'null'}) 962 call assert_equal("run", job_status(job)) 963 try 964 call assert_equal('err-out', ch_read(job, {"part": "err"})) 965 finally 966 call job_stop(job) 967 endtry 968 969 let job = job_start(s:python . " test_channel_pipe.py something", 970 \ {'err_io': 'null'}) 971 call assert_equal("run", job_status(job)) 972 try 973 call assert_equal('something', ch_read(job)) 974 finally 975 call job_stop(job) 976 endtry 977 978 let job = job_start(s:python . " test_channel_pipe.py something", 979 \ {'out_io': 'null', 'err_io': 'out'}) 980 call assert_equal("run", job_status(job)) 981 call job_stop(job) 982 983 let job = job_start(s:python . " test_channel_pipe.py something", 984 \ {'in_io': 'null', 'out_io': 'null', 'err_io': 'null'}) 985 call assert_equal("run", job_status(job)) 986 call assert_equal('channel fail', string(job_getchannel(job))) 987 call assert_equal('fail', ch_status(job)) 988 call job_stop(job) 989endfunc 990 991func Test_reuse_channel() 992 if !has('job') 993 return 994 endif 995 call ch_log('Test_reuse_channel()') 996 997 let job = job_start(s:python . " test_channel_pipe.py") 998 call assert_equal("run", job_status(job)) 999 let handle = job_getchannel(job) 1000 try 1001 call ch_sendraw(handle, "echo something\n") 1002 call assert_equal("something", ch_readraw(handle)) 1003 finally 1004 call job_stop(job) 1005 endtry 1006 1007 let job = job_start(s:python . " test_channel_pipe.py", {'channel': handle}) 1008 call assert_equal("run", job_status(job)) 1009 let handle = job_getchannel(job) 1010 try 1011 call ch_sendraw(handle, "echo again\n") 1012 call assert_equal("again", ch_readraw(handle)) 1013 finally 1014 call job_stop(job) 1015 endtry 1016endfunc 1017 1018func Test_out_cb() 1019 if !has('job') 1020 return 1021 endif 1022 call ch_log('Test_out_cb()') 1023 1024 let dict = {'thisis': 'dict: '} 1025 func dict.outHandler(chan, msg) dict 1026 let s:outmsg = self.thisis . a:msg 1027 endfunc 1028 func dict.errHandler(chan, msg) dict 1029 let s:errmsg = self.thisis . a:msg 1030 endfunc 1031 let job = job_start(s:python . " test_channel_pipe.py", 1032 \ {'out_cb': dict.outHandler, 1033 \ 'out_mode': 'json', 1034 \ 'err_cb': dict.errHandler, 1035 \ 'err_mode': 'json'}) 1036 call assert_equal("run", job_status(job)) 1037 try 1038 let s:outmsg = '' 1039 let s:errmsg = '' 1040 call ch_sendraw(job, "echo [0, \"hello\"]\n") 1041 call ch_sendraw(job, "echoerr [0, \"there\"]\n") 1042 call s:waitFor('s:outmsg != ""') 1043 call assert_equal("dict: hello", s:outmsg) 1044 call s:waitFor('s:errmsg != ""') 1045 call assert_equal("dict: there", s:errmsg) 1046 finally 1047 call job_stop(job) 1048 endtry 1049endfunc 1050 1051"""""""""" 1052 1053let s:unletResponse = '' 1054func s:UnletHandler(handle, msg) 1055 let s:unletResponse = a:msg 1056 unlet s:channelfd 1057endfunc 1058 1059" Test that "unlet handle" in a handler doesn't crash Vim. 1060func s:unlet_handle(port) 1061 let s:channelfd = ch_open('localhost:' . a:port, s:chopt) 1062 call ch_sendexpr(s:channelfd, "test", {'callback': function('s:UnletHandler')}) 1063 call s:waitFor('"what?" == s:unletResponse') 1064 call assert_equal('what?', s:unletResponse) 1065endfunc 1066 1067func Test_unlet_handle() 1068 call ch_log('Test_unlet_handle()') 1069 call s:run_server('s:unlet_handle') 1070endfunc 1071 1072"""""""""" 1073 1074let s:unletResponse = '' 1075func s:CloseHandler(handle, msg) 1076 let s:unletResponse = a:msg 1077 call ch_close(s:channelfd) 1078endfunc 1079 1080" Test that "unlet handle" in a handler doesn't crash Vim. 1081func s:close_handle(port) 1082 let s:channelfd = ch_open('localhost:' . a:port, s:chopt) 1083 call ch_sendexpr(s:channelfd, "test", {'callback': function('s:CloseHandler')}) 1084 call s:waitFor('"what?" == s:unletResponse') 1085 call assert_equal('what?', s:unletResponse) 1086endfunc 1087 1088func Test_close_handle() 1089 call ch_log('Test_close_handle()') 1090 call s:run_server('s:close_handle') 1091endfunc 1092 1093"""""""""" 1094 1095func Test_open_fail() 1096 call ch_log('Test_open_fail()') 1097 silent! let ch = ch_open("noserver") 1098 echo ch 1099 let d = ch 1100endfunc 1101 1102"""""""""" 1103 1104func s:open_delay(port) 1105 " Wait up to a second for the port to open. 1106 let s:chopt.waittime = 1000 1107 let channel = ch_open('localhost:' . a:port, s:chopt) 1108 unlet s:chopt.waittime 1109 if ch_status(channel) == "fail" 1110 call assert_false(1, "Can't open channel") 1111 return 1112 endif 1113 call assert_equal('got it', ch_evalexpr(channel, 'hello!')) 1114 call ch_close(channel) 1115endfunc 1116 1117func Test_open_delay() 1118 call ch_log('Test_open_delay()') 1119 " The server will wait half a second before creating the port. 1120 call s:run_server('s:open_delay', 'delay') 1121endfunc 1122 1123""""""""" 1124 1125function MyFunction(a,b,c) 1126 let s:call_ret = [a:a, a:b, a:c] 1127endfunc 1128 1129function s:test_call(port) 1130 let handle = ch_open('localhost:' . a:port, s:chopt) 1131 if ch_status(handle) == "fail" 1132 call assert_false(1, "Can't open channel") 1133 return 1134 endif 1135 1136 let s:call_ret = [] 1137 call assert_equal('ok', ch_evalexpr(handle, 'call-func')) 1138 call s:waitFor('len(s:call_ret) > 0') 1139 call assert_equal([1, 2, 3], s:call_ret) 1140endfunc 1141 1142func Test_call() 1143 call ch_log('Test_call()') 1144 call s:run_server('s:test_call') 1145endfunc 1146 1147""""""""" 1148 1149let s:job_exit_ret = 'not yet' 1150function MyExitCb(job, status) 1151 let s:job_exit_ret = 'done' 1152endfunc 1153 1154function s:test_exit_callback(port) 1155 call job_setoptions(s:job, {'exit_cb': 'MyExitCb'}) 1156 let s:exit_job = s:job 1157 call assert_equal('MyExitCb', job_info(s:job)['exit_cb']) 1158endfunc 1159 1160func Test_exit_callback() 1161 if has('job') 1162 call ch_log('Test_exit_callback()') 1163 call s:run_server('s:test_exit_callback') 1164 1165 " wait up to a second for the job to exit 1166 for i in range(100) 1167 if s:job_exit_ret == 'done' 1168 break 1169 endif 1170 sleep 10m 1171 " calling job_status() triggers the callback 1172 call job_status(s:exit_job) 1173 endfor 1174 1175 call assert_equal('done', s:job_exit_ret) 1176 call assert_equal('dead', job_info(s:exit_job).status) 1177 unlet s:exit_job 1178 endif 1179endfunc 1180 1181""""""""" 1182 1183let s:ch_close_ret = 'alive' 1184function MyCloseCb(ch) 1185 let s:ch_close_ret = 'closed' 1186endfunc 1187 1188function s:test_close_callback(port) 1189 let handle = ch_open('localhost:' . a:port, s:chopt) 1190 if ch_status(handle) == "fail" 1191 call assert_false(1, "Can't open channel") 1192 return 1193 endif 1194 call ch_setoptions(handle, {'close_cb': 'MyCloseCb'}) 1195 1196 call assert_equal('', ch_evalexpr(handle, 'close me')) 1197 call s:waitFor('"closed" == s:ch_close_ret') 1198 call assert_equal('closed', s:ch_close_ret) 1199endfunc 1200 1201func Test_close_callback() 1202 call ch_log('Test_close_callback()') 1203 call s:run_server('s:test_close_callback') 1204endfunc 1205 1206func Test_job_start_invalid() 1207 call assert_fails('call job_start($x)', 'E474:') 1208 call assert_fails('call job_start("")', 'E474:') 1209endfunc 1210 1211" Uncomment this to see what happens, output is in src/testdir/channellog. 1212" call ch_logfile('channellog', 'w') 1213