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

时间:2013-02-05 00:13:03

标签: 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)))))

编辑:

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

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

输出是:

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

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)))))

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)))))

很明显,sleep-for不能依赖于阻止。

4 个答案:

答案 0 :(得分: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)))))

但是通过了测试,因为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)))))

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

(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)))))

EDIT1

通过将process-connection-type设置为nil来通过第二次测试。 (但我无法理解这种行为)

(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)))))

请参阅document

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)))))

答案 1 :(得分:2)

我刚刚复制到* scratch *并使用ert-run-tests-interactively运行该测试。我无法重现你的问题。你有一个旧版本的测试在内存中挥之不去吗?

编辑:我在OS X 10.8上使用Emacs 24.2.1

更新:运行更新的代码。一些非常奇怪的事情正在发生。我的跑步中大约有四分之一在进行。

更新:我可以验证@ syohex的答案:添加第二个电话sleep-for对我有效。

答案 2 :(得分:2)

此错误将在下一个Emacs(25.1?24.6 ??)中修复。请参阅2015年6月的this commit。(我实际上并没有尝试过。)

在修复之前,请使用

(call-process "/usr/bin/sleep" nil nil nil "<seconds>")

而不是'sleep-for'。这很可靠。

错误报告位于original(#15990)和duplicate(#20935),其中报告了此修复程序。

答案 3 :(得分:0)

查看https://github.com/rejeep/ert-async.el

然后你可以这样做:

(ert-deftest-async timetest (done)
  (call-async-command done))