diff options
| author | Jim Porter | 2022-07-17 20:25:00 -0700 |
|---|---|---|
| committer | Jim Porter | 2022-08-05 17:58:54 -0700 |
| commit | d7b89ea4077d4fe677ba0577245328819ee79cdc (patch) | |
| tree | d4e499042bdf2f301be7f2d7ec05f0d1bfd8d44b /test/src/process-tests.el | |
| parent | b70369c557efed3dcd86dc64a2e73e3480dea6af (diff) | |
| download | emacs-d7b89ea4077d4fe677ba0577245328819ee79cdc.tar.gz emacs-d7b89ea4077d4fe677ba0577245328819ee79cdc.zip | |
Allow creating processes where only one of stdin or stdout is a PTY
* src/lisp.h (emacs_spawn):
* src/callproc.c (emacs_spawn): Add PTY_IN and PTY_OUT arguments to
specify which streams should be set up as a PTY.
(call_process): Adjust call to 'emacs_spawn'.
* src/process.h (Lisp_Process): Replace 'pty_flag' with 'pty_in' and
'pty_out'.
* src/process.c (is_pty_from_symbol): New function.
(make-process): Allow :connection-type to be a cons cell, and allow
using a stderr process with a PTY for stdin/stdout.
(create_process): Handle creating a process where only one of stdin or
stdout is a PTY.
* lisp/eshell/esh-proc.el (eshell-needs-pipe, eshell-needs-pipe-p):
Remove.
(eshell-gather-process-output): Use 'make-process' and set
':connection-type' as needed by the value of 'eshell-in-pipeline-p'.
* lisp/net/tramp.el (tramp-handle-make-process):
* lisp/net/tramp-adb.el (tramp-adb-handle-make-process):
* lisp/net/tramp-sh.el (tramp-sh-handle-make-process): Don't signal an
error when ':connection-type' is a cons cell.
* test/src/process-tests.el
(process-test-sentinel-wait-function-working-p): Allow passing PROC
in, and rework into...
(process-test-wait-for-sentinel): ... this.
(process-test-sentinel-accept-process-output)
(process-test-sentinel-sit-for, process-test-quoted-batfile)
(process-test-stderr-filter): Use 'process-test-wait-for-sentinel'.
(make/process/test-connection-type): New function.
(make-process/connection-type/pty, make-process/connection-type/pty-2)
(make-process/connection-type/pipe)
(make-process/connection-type/pipe-2)
(make-process/connection-type/in-pty)
(make-process/connection-type/out-pty)
(make-process/connection-type/pty-with-stderr-buffer)
(make-process/connection-type/out-pty-with-stderr-buffer): New tests.
* test/lisp/eshell/esh-proc-tests.el (esh-proc-test--detect-pty-cmd):
New variable.
(esh-proc-test/pipeline-connection-type/no-pipeline)
(esh-proc-test/pipeline-connection-type/first)
(esh-proc-test/pipeline-connection-type/middle)
(esh-proc-test/pipeline-connection-type/last): New tests.
* doc/lispref/processes.texi (Asynchronous Processes): Document new
':connection-type' behavior.
(Output from Processes): Remove caveat about ':stderr' forcing
'make-process' to use pipes.
* etc/NEWS: Announce this change (bug#56025).
Diffstat (limited to 'test/src/process-tests.el')
| -rw-r--r-- | test/src/process-tests.el | 121 |
1 files changed, 86 insertions, 35 deletions
diff --git a/test/src/process-tests.el b/test/src/process-tests.el index aab95b2d733..b801563feb7 100644 --- a/test/src/process-tests.el +++ b/test/src/process-tests.el | |||
| @@ -38,10 +38,11 @@ | |||
| 38 | ;; Timeout in seconds; the test fails if the timeout is reached. | 38 | ;; Timeout in seconds; the test fails if the timeout is reached. |
| 39 | (defvar process-test-sentinel-wait-timeout 2.0) | 39 | (defvar process-test-sentinel-wait-timeout 2.0) |
| 40 | 40 | ||
| 41 | ;; Start a process that exits immediately. Call WAIT-FUNCTION, | 41 | (defun process-test-wait-for-sentinel (proc exit-status &optional wait-function) |
| 42 | ;; possibly multiple times, to wait for the process to complete. | 42 | "Set a sentinel on PROC and wait for it to be called with EXIT-STATUS. |
| 43 | (defun process-test-sentinel-wait-function-working-p (wait-function) | 43 | Call WAIT-FUNCTION, possibly multiple times, to wait for the |
| 44 | (let ((proc (start-process "test" nil "bash" "-c" "exit 20")) | 44 | process to complete." |
| 45 | (let ((wait-function (or wait-function #'accept-process-output)) | ||
| 45 | (sentinel-called nil) | 46 | (sentinel-called nil) |
| 46 | (start-time (float-time))) | 47 | (start-time (float-time))) |
| 47 | (set-process-sentinel proc (lambda (_proc _msg) | 48 | (set-process-sentinel proc (lambda (_proc _msg) |
| @@ -50,21 +51,22 @@ | |||
| 50 | (> (- (float-time) start-time) | 51 | (> (- (float-time) start-time) |
| 51 | process-test-sentinel-wait-timeout))) | 52 | process-test-sentinel-wait-timeout))) |
| 52 | (funcall wait-function)) | 53 | (funcall wait-function)) |
| 53 | (cl-assert (eq (process-status proc) 'exit)) | 54 | (should sentinel-called) |
| 54 | (cl-assert (= (process-exit-status proc) 20)) | 55 | (should (eq (process-status proc) 'exit)) |
| 55 | sentinel-called)) | 56 | (should (= (process-exit-status proc) exit-status)))) |
| 56 | 57 | ||
| 57 | (ert-deftest process-test-sentinel-accept-process-output () | 58 | (ert-deftest process-test-sentinel-accept-process-output () |
| 58 | (skip-unless (executable-find "bash")) | 59 | (skip-unless (executable-find "bash")) |
| 59 | (with-timeout (60 (ert-fail "Test timed out")) | 60 | (with-timeout (60 (ert-fail "Test timed out")) |
| 60 | (should (process-test-sentinel-wait-function-working-p | 61 | (let ((proc (start-process "test" nil "bash" "-c" "exit 20"))) |
| 61 | #'accept-process-output)))) | 62 | (should (process-test-wait-for-sentinel proc 20))))) |
| 62 | 63 | ||
| 63 | (ert-deftest process-test-sentinel-sit-for () | 64 | (ert-deftest process-test-sentinel-sit-for () |
| 64 | (skip-unless (executable-find "bash")) | 65 | (skip-unless (executable-find "bash")) |
| 65 | (with-timeout (60 (ert-fail "Test timed out")) | 66 | (with-timeout (60 (ert-fail "Test timed out")) |
| 66 | (should | 67 | (let ((proc (start-process "test" nil "bash" "-c" "exit 20"))) |
| 67 | (process-test-sentinel-wait-function-working-p (lambda () (sit-for 0.01 t)))))) | 68 | (should (process-test-wait-for-sentinel |
| 69 | proc 20 (lambda () (sit-for 0.01 t))))))) | ||
| 68 | 70 | ||
| 69 | (when (eq system-type 'windows-nt) | 71 | (when (eq system-type 'windows-nt) |
| 70 | (ert-deftest process-test-quoted-batfile () | 72 | (ert-deftest process-test-quoted-batfile () |
| @@ -97,17 +99,8 @@ | |||
| 97 | "echo hello stderr! >&2; " | 99 | "echo hello stderr! >&2; " |
| 98 | "exit 20")) | 100 | "exit 20")) |
| 99 | :buffer stdout-buffer | 101 | :buffer stdout-buffer |
| 100 | :stderr stderr-buffer)) | 102 | :stderr stderr-buffer))) |
| 101 | (sentinel-called nil) | 103 | (process-test-wait-for-sentinel proc 20) |
| 102 | (start-time (float-time))) | ||
| 103 | (set-process-sentinel proc (lambda (_proc _msg) | ||
| 104 | (setq sentinel-called t))) | ||
| 105 | (while (not (or sentinel-called | ||
| 106 | (> (- (float-time) start-time) | ||
| 107 | process-test-sentinel-wait-timeout))) | ||
| 108 | (accept-process-output)) | ||
| 109 | (cl-assert (eq (process-status proc) 'exit)) | ||
| 110 | (cl-assert (= (process-exit-status proc) 20)) | ||
| 111 | (should (with-current-buffer stdout-buffer | 104 | (should (with-current-buffer stdout-buffer |
| 112 | (goto-char (point-min)) | 105 | (goto-char (point-min)) |
| 113 | (looking-at "hello stdout!"))) | 106 | (looking-at "hello stdout!"))) |
| @@ -118,8 +111,7 @@ | |||
| 118 | (ert-deftest process-test-stderr-filter () | 111 | (ert-deftest process-test-stderr-filter () |
| 119 | (skip-unless (executable-find "bash")) | 112 | (skip-unless (executable-find "bash")) |
| 120 | (with-timeout (60 (ert-fail "Test timed out")) | 113 | (with-timeout (60 (ert-fail "Test timed out")) |
| 121 | (let* ((sentinel-called nil) | 114 | (let* ((stderr-sentinel-called nil) |
| 122 | (stderr-sentinel-called nil) | ||
| 123 | (stdout-output nil) | 115 | (stdout-output nil) |
| 124 | (stderr-output nil) | 116 | (stderr-output nil) |
| 125 | (stdout-buffer (generate-new-buffer "*stdout*")) | 117 | (stdout-buffer (generate-new-buffer "*stdout*")) |
| @@ -131,23 +123,14 @@ | |||
| 131 | (concat "echo hello stdout!; " | 123 | (concat "echo hello stdout!; " |
| 132 | "echo hello stderr! >&2; " | 124 | "echo hello stderr! >&2; " |
| 133 | "exit 20")) | 125 | "exit 20")) |
| 134 | :stderr stderr-proc)) | 126 | :stderr stderr-proc))) |
| 135 | (start-time (float-time))) | ||
| 136 | (set-process-filter proc (lambda (_proc input) | 127 | (set-process-filter proc (lambda (_proc input) |
| 137 | (push input stdout-output))) | 128 | (push input stdout-output))) |
| 138 | (set-process-sentinel proc (lambda (_proc _msg) | ||
| 139 | (setq sentinel-called t))) | ||
| 140 | (set-process-filter stderr-proc (lambda (_proc input) | 129 | (set-process-filter stderr-proc (lambda (_proc input) |
| 141 | (push input stderr-output))) | 130 | (push input stderr-output))) |
| 142 | (set-process-sentinel stderr-proc (lambda (_proc _input) | 131 | (set-process-sentinel stderr-proc (lambda (_proc _input) |
| 143 | (setq stderr-sentinel-called t))) | 132 | (setq stderr-sentinel-called t))) |
| 144 | (while (not (or sentinel-called | 133 | (process-test-wait-for-sentinel proc 20) |
| 145 | (> (- (float-time) start-time) | ||
| 146 | process-test-sentinel-wait-timeout))) | ||
| 147 | (accept-process-output)) | ||
| 148 | (cl-assert (eq (process-status proc) 'exit)) | ||
| 149 | (cl-assert (= (process-exit-status proc) 20)) | ||
| 150 | (should sentinel-called) | ||
| 151 | (should (equal 1 (with-current-buffer stdout-buffer | 134 | (should (equal 1 (with-current-buffer stdout-buffer |
| 152 | (point-max)))) | 135 | (point-max)))) |
| 153 | (should (equal "hello stdout!\n" | 136 | (should (equal "hello stdout!\n" |
| @@ -289,6 +272,74 @@ | |||
| 289 | (error :got-error)))) | 272 | (error :got-error)))) |
| 290 | (should have-called-debugger)))) | 273 | (should have-called-debugger)))) |
| 291 | 274 | ||
| 275 | (defun make-process/test-connection-type (ttys &rest args) | ||
| 276 | "Make a process and check whether its standard streams match TTYS. | ||
| 277 | This calls `make-process', passing ARGS to adjust how the process | ||
| 278 | is created. TTYS should be a list of 3 boolean values, | ||
| 279 | indicating whether the subprocess's stdin, stdout, and stderr | ||
| 280 | should be a TTY, respectively." | ||
| 281 | (declare (indent 1)) | ||
| 282 | (let* (;; MS-Windows doesn't support communicating via pty. | ||
| 283 | (ttys (if (eq system-type 'windows-nt) '(nil nil nil) ttys)) | ||
| 284 | (expected-output (concat (and (nth 0 ttys) "stdin\n") | ||
| 285 | (and (nth 1 ttys) "stdout\n") | ||
| 286 | (and (nth 2 ttys) "stderr\n"))) | ||
| 287 | (stdout-buffer (generate-new-buffer "*stdout*")) | ||
| 288 | (proc (apply | ||
| 289 | #'make-process | ||
| 290 | :name "test" | ||
| 291 | :command (list "sh" "-c" | ||
| 292 | (concat "if [ -t 0 ]; then echo stdin; fi; " | ||
| 293 | "if [ -t 1 ]; then echo stdout; fi; " | ||
| 294 | "if [ -t 2 ]; then echo stderr; fi")) | ||
| 295 | :buffer stdout-buffer | ||
| 296 | args))) | ||
| 297 | (process-test-wait-for-sentinel proc 0) | ||
| 298 | (should (equal (with-current-buffer stdout-buffer (buffer-string)) | ||
| 299 | expected-output)))) | ||
| 300 | |||
| 301 | (ert-deftest make-process/connection-type/pty () | ||
| 302 | (skip-unless (executable-find "sh")) | ||
| 303 | (make-process/test-connection-type '(t t t) | ||
| 304 | :connection-type 'pty)) | ||
| 305 | |||
| 306 | (ert-deftest make-process/connection-type/pty-2 () | ||
| 307 | (skip-unless (executable-find "sh")) | ||
| 308 | (make-process/test-connection-type '(t t t) | ||
| 309 | :connection-type '(pty . pty))) | ||
| 310 | |||
| 311 | (ert-deftest make-process/connection-type/pipe () | ||
| 312 | (skip-unless (executable-find "sh")) | ||
| 313 | (make-process/test-connection-type '(nil nil nil) | ||
| 314 | :connection-type 'pipe)) | ||
| 315 | |||
| 316 | (ert-deftest make-process/connection-type/pipe-2 () | ||
| 317 | (skip-unless (executable-find "sh")) | ||
| 318 | (make-process/test-connection-type '(nil nil nil) | ||
| 319 | :connection-type '(pipe . pipe))) | ||
| 320 | |||
| 321 | (ert-deftest make-process/connection-type/in-pty () | ||
| 322 | (skip-unless (executable-find "sh")) | ||
| 323 | (make-process/test-connection-type '(t nil nil) | ||
| 324 | :connection-type '(pty . pipe))) | ||
| 325 | |||
| 326 | (ert-deftest make-process/connection-type/out-pty () | ||
| 327 | (skip-unless (executable-find "sh")) | ||
| 328 | (make-process/test-connection-type '(nil t t) | ||
| 329 | :connection-type '(pipe . pty))) | ||
| 330 | |||
| 331 | (ert-deftest make-process/connection-type/pty-with-stderr-buffer () | ||
| 332 | (skip-unless (executable-find "sh")) | ||
| 333 | (let ((stderr-buffer (generate-new-buffer "*stderr*"))) | ||
| 334 | (make-process/test-connection-type '(t t nil) | ||
| 335 | :connection-type 'pty :stderr stderr-buffer))) | ||
| 336 | |||
| 337 | (ert-deftest make-process/connection-type/out-pty-with-stderr-buffer () | ||
| 338 | (skip-unless (executable-find "sh")) | ||
| 339 | (let ((stderr-buffer (generate-new-buffer "*stderr*"))) | ||
| 340 | (make-process/test-connection-type '(nil t nil) | ||
| 341 | :connection-type '(pipe . pty) :stderr stderr-buffer))) | ||
| 342 | |||
| 292 | (ert-deftest make-process/file-handler/found () | 343 | (ert-deftest make-process/file-handler/found () |
| 293 | "Check that the `:file-handler’ argument of `make-process’ | 344 | "Check that the `:file-handler’ argument of `make-process’ |
| 294 | works as expected if a file name handler is found." | 345 | works as expected if a file name handler is found." |