Elisp:在ert中运行测试时,sleep-for不会阻塞

rne*_*way 3 emacs elisp ert

我正在尝试使用需要睡眠的ert来设置一些测试,以便后台进程继续进行.我尝试过使用sleep-foraccept-process-output.两者都不可靠.这是一个小例子.

此测试只是休眠5秒钟,然后检查至少3秒钟.使用sleep-for它立即完成并失败.如果shell-command取消注释,则需要5秒才能成功!这里发生了什么?

(ert-deftest timetest ()
  (let ((now (cadr (current-time))))
    ;(shell-command "sleep 5")
    (sleep-for 5)
    (should (< now (- (cadr (current-time)) 3)))))
Run Code Online (Sandbox Code Playgroud)

编辑:

当我测试前面的例子时,我的环境肯定有些奇怪.这个稍微改变的示例包含一个像我需要测试的后台进程,但失败了.我以交互方式测试它并使用命令:

emacs --batch -l example.el -f ert-run-tests-batch-and-exit
Run Code Online (Sandbox Code Playgroud)
(ert-deftest timetest ()
  (let ((now (cadr (current-time))))
    (start-process "echo" "*echo*" "echo" "hello world")
    (sleep-for 5)
    (should (< now (- (cadr (current-time)) 3)))))
Run Code Online (Sandbox Code Playgroud)

输出是:

Test timetest condition:
    (ert-test-failed
     ((should
       (< now
          (- ... 3)))
      :form
      (< 55177 55174)
      :value nil))
   FAILED  1/1  timetest

Ran 1 tests, 0 results as expected, 1 unexpected (2013-02-05 09:57:29+0000)

1 unexpected results:
   FAILED  timetest
Run Code Online (Sandbox Code Playgroud)

EDIT2:

似乎表示进程输出的新版本足以中断sleep-for:

(ert-deftest timetest ()
  (let ((now (cadr (current-time))))
    (start-process "yes" "*yes*" "yes")
    (sleep-for 1) ;; This sleep-for may be interrupted by process *output*
    (sleep-for 5) ;; This sleep-for is also interrupted
    (should (< now (- (cadr (current-time)) 3)))))
Run Code Online (Sandbox Code Playgroud)

EDIT3:

心情沉重,我发布了另一个版本:

(ert-deftest timetest ()
  (let ((now (cadr (current-time)))
        (process-connection-type nil))
    (start-process "tmp" "*tmp*" "bash" "-c" "sleep 1; echo hi")
    (sleep-for 5)
    (should (< now (- (cadr (current-time)) 3)))))
Run Code Online (Sandbox Code Playgroud)

似乎很清楚,sleep-for不能依靠阻止.

syo*_*hex 6

我认为sleep-for当进程退出时会中断.

以下测试失败,因为sleep-for在2秒后中断.

(ert-deftest timetest ()
  (let ((now (cadr (current-time))))
    (start-process "sleep" "*sleep*" "sleep" "2") ;; Fail
    (sleep-for 5)
    (should (< now (- (cadr (current-time)) 3)))))
Run Code Online (Sandbox Code Playgroud)

但是接下来的测试通过,因为sleep-for在4秒后中断.

(ert-deftest timetest ()
  (let ((now (cadr (current-time))))
    (start-process "sleep" "*sleep*" "sleep" "4") ;; Success
    (sleep-for 5)
    (should (< now (- (cadr (current-time)) 3)))))
Run Code Online (Sandbox Code Playgroud)

所以我认为你可以写下面的测试

(ert-deftest timetest ()
  (let ((now (cadr (current-time))))
    (start-process "echo" "*echo*" "echo" "hello world")
    (sleep-for 1) ;; This sleep-for may be interrupted by process exited
    (sleep-for 5) ;; This sleep-for can sleep 5 seconds
    (should (< now (- (cadr (current-time)) 3)))))
Run Code Online (Sandbox Code Playgroud)

EDIT1

第二次测试是通过设置传递process-connection-typenil.(但我无法理解这种行为)

(ert-deftest timetest ()
  (let ((now (cadr (current-time)))
        (process-connection-type nil))
    (start-process "yes" "*yes*" "yes")
    (sleep-for 5)
    (should (< now (- (cadr (current-time)) 3)))))
Run Code Online (Sandbox Code Playgroud)

请看文件

EDIT2

在第3次测试中,我们需要3次sleep-for因为sleep-for被中断2次,但这很脆弱.所以我写测试如下.如果sleep-for被中断多次,则可以通过该测试.而我用float-time而不是current-time 因为第二元素current-time可以包裹arround.

(ert-deftest timetest ()
  (let ((now (float-time))
        (process-connection-type nil))
    (start-process "tmp" "*tmp*" "bash" "-c" "sleep 1; echo hi")
    (while (< (- (float-time) now) 5)
      (sleep-for 1))
    (should (< now (- (float-time) 3)))))
Run Code Online (Sandbox Code Playgroud)