mirror of
https://github.com/vale981/emacs-jupyter
synced 2025-03-05 15:41:37 -05:00
Revert "Remove tests related to jupyter-kernel-process
, ioloop
, comm
, zmq
, and channels
"
This reverts commit 1381d7975d2c47ebcec1359dc24e443aa5af0fa2.
This commit is contained in:
parent
56ada9392b
commit
db0f3678ac
2 changed files with 520 additions and 1 deletions
|
@ -468,6 +468,58 @@
|
|||
msg)
|
||||
(cons "idle" "foo")))))
|
||||
|
||||
;;; Channels
|
||||
|
||||
(ert-deftest jupyter-zmq-channel ()
|
||||
:tags '(channels zmq)
|
||||
(let* ((port (car (jupyter-available-local-ports 1)))
|
||||
(channel (jupyter-zmq-channel
|
||||
:type :shell
|
||||
:endpoint (format "tcp://127.0.0.1:%s" port))))
|
||||
(ert-info ("Starting the channel")
|
||||
(should-not (jupyter-alive-p channel))
|
||||
(jupyter-start channel :identity "foo")
|
||||
(should (jupyter-alive-p channel))
|
||||
(should (equal (zmq-socket-get (oref channel socket)
|
||||
zmq-ROUTING-ID)
|
||||
"foo")))
|
||||
(ert-info ("Stopping the channel")
|
||||
(let ((sock (oref channel socket)))
|
||||
(jupyter-stop channel)
|
||||
(should-not (jupyter-alive-p channel))
|
||||
;; Ensure the socket was disconnected
|
||||
(should-error (zmq-send sock "foo" zmq-NOBLOCK) :type 'zmq-EAGAIN)))))
|
||||
|
||||
(ert-deftest jupyter-hb-channel ()
|
||||
:tags '(channels)
|
||||
(should (eq (oref (jupyter-hb-channel) type) :hb))
|
||||
(let* ((port (car (jupyter-available-local-ports 1)))
|
||||
(channel (jupyter-hb-channel
|
||||
:endpoint (format "tcp://127.0.0.1:%s" port)
|
||||
:session (jupyter-session)))
|
||||
(died-cb-called nil)
|
||||
(jupyter-hb-max-failures 1))
|
||||
(oset channel time-to-dead 0.1)
|
||||
(should-not (jupyter-alive-p channel))
|
||||
(should-not (jupyter-hb-beating-p channel))
|
||||
(should (oref channel paused))
|
||||
(oset channel beating t)
|
||||
(jupyter-start channel)
|
||||
(jupyter-hb-on-kernel-dead channel (lambda () (setq died-cb-called t)))
|
||||
(should (jupyter-alive-p channel))
|
||||
;; `jupyter-hb-unpause' needs to explicitly called
|
||||
(should (oref channel paused))
|
||||
(jupyter-hb-unpause channel)
|
||||
(sleep-for 0.2)
|
||||
;; It seems the timers are run after returning from the first `sleep-for'
|
||||
;; call.
|
||||
(sleep-for 0.1)
|
||||
(should (oref channel paused))
|
||||
(should-not (oref channel beating))
|
||||
(should died-cb-called)
|
||||
(should (jupyter-alive-p channel))
|
||||
(should-not (jupyter-hb-beating-p channel))))
|
||||
|
||||
;;; GC
|
||||
|
||||
(ert-deftest jupyter-weak-ref ()
|
||||
|
@ -517,6 +569,151 @@
|
|||
(lambda (_) nil)))
|
||||
(should-error (jupyter-locate-python))))
|
||||
|
||||
;; FIXME: Revisit after transition
|
||||
(ert-deftest jupyter-kernel-process ()
|
||||
:tags '(kernel)
|
||||
;; TODO: `jupyter-do-interrupt'
|
||||
(ert-info ("`jupyter-do-launch', `jupyter-do-shutdown'")
|
||||
(cl-macrolet
|
||||
((confirm-shutdown-state
|
||||
()
|
||||
`(progn
|
||||
(should-not (jupyter-alive-p kernel))
|
||||
(should (jupyter-kernel-spec kernel))
|
||||
(should-not (jupyter-kernel-session kernel))
|
||||
(should-not (process-live-p (jupyter-process kernel)))))
|
||||
(confirm-launch-state
|
||||
()
|
||||
`(progn
|
||||
(should (jupyter-alive-p kernel))
|
||||
(should (jupyter-kernel-spec kernel))
|
||||
(should (jupyter-kernel-session kernel))
|
||||
(should (process-live-p (jupyter-process kernel))))))
|
||||
(let ((kernel (jupyter-kernel-process
|
||||
:spec (jupyter-guess-kernelspec "python"))))
|
||||
(confirm-shutdown-state)
|
||||
(jupyter-launch kernel)
|
||||
(confirm-launch-state)
|
||||
(jupyter-do-shutdown kernel)
|
||||
(confirm-shutdown-state))))
|
||||
;; (let (called)
|
||||
;; (let* ((plist '(:argv ["sleep" "60"] :env nil :interrupt_mode "signal"))
|
||||
;; (kernel (jupyter-kernel
|
||||
;; :spec (make-jupyter-kernelspec
|
||||
;; :name "sleep"
|
||||
;; :plist plist))))
|
||||
;; (let ((jupyter-long-timeout 0.01))
|
||||
;; (jupyter-launch kernel))
|
||||
;; (cl-letf (((symbol-function #'interrupt-process)
|
||||
;; (lambda (&rest args)
|
||||
;; (setq called t))))
|
||||
;; (jupyter-do-interrupt kernel))
|
||||
;; (should called)
|
||||
;; (setq called nil)
|
||||
;; (jupyter-do-shutdown kernel)))
|
||||
)
|
||||
|
||||
|
||||
|
||||
;; (let ((kernel (jupyter--kernel-process
|
||||
;; :spec (jupyter-guess-kernelspec "python"))))
|
||||
;; (ert-info ("Session set after kernel starts")
|
||||
;; (should-not (jupyter-kernel-alive-p kernel))
|
||||
;; (jupyter-start-kernel kernel)
|
||||
;; (should (jupyter-kernel-alive-p kernel))
|
||||
;; (should (oref kernel session))
|
||||
;; (jupyter-kill-kernel kernel)
|
||||
;; (should-not (jupyter-kernel-alive-p kernel)))
|
||||
;; (ert-info ("Can we communicate?")
|
||||
;; (let ((manager (jupyter-kernel-manager :kernel kernel)))
|
||||
;; (jupyter-start-kernel manager)
|
||||
;; (unwind-protect
|
||||
;; (let ((jupyter-current-client
|
||||
;; (jupyter-make-client manager 'jupyter-kernel-client)))
|
||||
;; (jupyter-start-channels jupyter-current-client)
|
||||
;; (unwind-protect
|
||||
;; (progn
|
||||
;; (jupyter-wait-until-startup jupyter-current-client)
|
||||
;; (should (equal (jupyter-eval "1 + 1") "2")))
|
||||
;; (jupyter-stop-channels jupyter-current-client)))
|
||||
;; (jupyter-shutdown-kernel manager)))))
|
||||
|
||||
(ert-deftest jupyter-delete-connection-files ()
|
||||
:tags '(kernel process)
|
||||
(let ((jupyter--kernel-processes
|
||||
(cl-loop repeat 2
|
||||
collect (list nil (make-temp-file "jupyter-test")))))
|
||||
(jupyter-delete-connection-files)
|
||||
(should-not
|
||||
(cl-loop for (_ conn-file) in jupyter--kernel-processes
|
||||
thereis (file-exists-p conn-file)))))
|
||||
|
||||
(ert-deftest jupyter-kernel-process/connection-file-management ()
|
||||
:tags '(kernel process)
|
||||
(let (jupyter--kernel-processes)
|
||||
(pcase-let ((`(,kernelA ,kernelB)
|
||||
(cl-loop
|
||||
repeat 2
|
||||
collect (jupyter-kernel :spec "python"))))
|
||||
(jupyter-launch kernelA)
|
||||
(should (= (length jupyter--kernel-processes) 1))
|
||||
(unwind-protect
|
||||
(pcase-let* ((`(,processA ,conn-fileA) (car jupyter--kernel-processes))
|
||||
(process-bufferA (process-buffer processA)))
|
||||
(should (eq processA (jupyter-kernel-process-process kernelA)))
|
||||
(jupyter-do-shutdown kernelA)
|
||||
(should-not (process-live-p processA))
|
||||
(should (file-exists-p conn-fileA))
|
||||
(should (buffer-live-p process-bufferA))
|
||||
(jupyter-launch kernelB)
|
||||
(should-not (buffer-live-p process-bufferA))
|
||||
(should-not (file-exists-p conn-fileA))
|
||||
(should (= (length jupyter--kernel-processes) 1))
|
||||
(pcase-let ((`(,processB ,conn-fileB)
|
||||
(car jupyter--kernel-processes)))
|
||||
(should-not (eq processA processB))
|
||||
(should-not (string= conn-fileA conn-fileB))))
|
||||
(jupyter-do-shutdown kernelA)
|
||||
(jupyter-do-shutdown kernelB)))))
|
||||
|
||||
(ert-deftest jupyter-kernel-process/on-unexpected-exit ()
|
||||
:tags '(kernel process)
|
||||
(skip-unless nil)
|
||||
(let ((kernel (jupyter-kernel :spec "python"))
|
||||
called)
|
||||
(jupyter-launch
|
||||
kernel (lambda (kernel)
|
||||
(setq called t)))
|
||||
(let ((process (jupyter--kernel-process kernel)))
|
||||
(kill-process process)
|
||||
(sleep-for 0.01)
|
||||
(should called))))
|
||||
|
||||
(ert-deftest jupyter-session-with-random-ports ()
|
||||
:tags '(kernel)
|
||||
(let ((session (jupyter-session-with-random-ports)))
|
||||
(should (jupyter-session-p session))
|
||||
(let ((process-exists
|
||||
(cl-loop
|
||||
for p in (process-list)
|
||||
thereis (string= (process-name p)
|
||||
"jupyter-session-with-random-ports"))))
|
||||
(should-not process-exists))
|
||||
(cl-destructuring-bind (&key hb_port stdin_port
|
||||
control_port shell_port iopub_port
|
||||
&allow-other-keys)
|
||||
(jupyter-session-conn-info session)
|
||||
;; Verify the ports are open for us
|
||||
(cl-loop
|
||||
for port in (list hb_port stdin_port
|
||||
control_port shell_port iopub_port)
|
||||
for proc = (make-network-process
|
||||
:name "jupyter-test"
|
||||
:server t
|
||||
:host "127.0.0.1"
|
||||
:service port)
|
||||
do (delete-process proc)))))
|
||||
|
||||
(ert-deftest jupyter-expand-environment-variables ()
|
||||
:tags '(kernel)
|
||||
(let ((process-environment
|
||||
|
@ -582,6 +779,89 @@
|
|||
|
||||
;;; Client
|
||||
|
||||
;; TODO: Different values of the session argument
|
||||
;;
|
||||
;; FIXME: Re-work after refactoring the kernelspec -> connectable kernel code paths.
|
||||
(ert-deftest jupyter-comm-initialize ()
|
||||
:tags '(client init)
|
||||
(skip-unless nil)
|
||||
(jupyter-test-with-python-client client
|
||||
(with-slots (session kcomm) client
|
||||
(ert-info ("Client session")
|
||||
(should (string= (jupyter-session-key session)
|
||||
(plist-get conn-info :key)))
|
||||
(should (equal (jupyter-session-conn-info session)
|
||||
conn-info)))
|
||||
(ert-info ("Heartbeat channel initialized")
|
||||
(should (eq session (oref (oref kcomm hb) session)))
|
||||
(should (string= (oref (oref kcomm hb) endpoint)
|
||||
(format "tcp://127.0.0.1:%d"
|
||||
(plist-get conn-info :hb_port)))))
|
||||
(ert-info ("Shell, iopub, stdin initialized")
|
||||
(cl-loop
|
||||
for channel in '(:shell :iopub :stdin)
|
||||
for port_sym = (intern (concat (symbol-name channel) "_port"))
|
||||
do
|
||||
(should (plist-member (plist-get channels channel) :alive-p))
|
||||
(should (plist-member (plist-get channels channel) :endpoint))
|
||||
(should
|
||||
(string= (plist-get (plist-get channels channel) :endpoint)
|
||||
(format "tcp://127.0.0.1:%d"
|
||||
(plist-get conn-info port_sym))))))
|
||||
(ert-info ("Initialization stops any running channels")
|
||||
(should-not (jupyter-channels-running-p client))
|
||||
(jupyter-start-channels client)
|
||||
(should (jupyter-channels-running-p client))
|
||||
(jupyter-comm-initialize client conn-info)
|
||||
(should-not (jupyter-channels-running-p client)))
|
||||
(ert-info ("Invalid signature scheme")
|
||||
(plist-put conn-info :signature_scheme "hmac-foo")
|
||||
(should-error (jupyter-comm-initialize client conn-info))))))
|
||||
|
||||
(ert-deftest jupyter-write-connection-file ()
|
||||
:tags '(client)
|
||||
(let* ((conn-info '(:kernel_name "python"
|
||||
:transport "tcp" :ip "127.0.0.1"
|
||||
:signature_scheme "hmac-sha256"
|
||||
:key "00a2cadb-3da7-45d2-b394-dbd01b5f80eb"
|
||||
:hb_port 45473 :stdin_port 40175
|
||||
:control_port 36301
|
||||
:shell_port 39263 :iopub_port 36731))
|
||||
(conn-file (jupyter-write-connection-file
|
||||
(jupyter-session
|
||||
:conn-info conn-info))))
|
||||
(should (file-exists-p conn-file))
|
||||
(should (string= (file-name-directory conn-file) (jupyter-runtime-directory)))
|
||||
(should (equal (jupyter-read-plist conn-file) conn-info))))
|
||||
|
||||
;; FIXME: Revisit after transition
|
||||
(ert-deftest jupyter-client-channels ()
|
||||
:tags '(client channels)
|
||||
(skip-unless nil)
|
||||
(ert-info ("Starting/stopping channels")
|
||||
;; FIXME: Without a new client, I'm getting
|
||||
;;
|
||||
;; (zmq-EFSM "Operation cannot be accomplished in current state")
|
||||
;;
|
||||
;; on the `jupyter-connect-repl' test pretty consistently.
|
||||
(let ((jupyter-test-with-new-client t))
|
||||
(jupyter-test-with-python-client client
|
||||
(jupyter-stop-channels client)
|
||||
(cl-loop
|
||||
for channel in '(:hb :shell :iopub :stdin)
|
||||
for alive-p = (jupyter-alive-p client channel)
|
||||
do (should-not alive-p))
|
||||
(jupyter-start-channels client)
|
||||
(cl-loop
|
||||
for channel in '(:hb :shell :iopub :stdin)
|
||||
for alive-p = (jupyter-alive-p client channel)
|
||||
do (should alive-p))
|
||||
(jupyter-stop-channels client)
|
||||
(cl-loop
|
||||
for channel in '(:hb :shell :iopub :stdin)
|
||||
for alive-p = (jupyter-alive-p client channel)
|
||||
do (should-not alive-p))))))
|
||||
|
||||
(ert-deftest jupyter-inhibited-handlers ()
|
||||
:tags '(client handlers)
|
||||
(jupyter-test-with-python-client client
|
||||
|
@ -658,6 +938,182 @@
|
|||
(should (jupyter-request-idle-p req))
|
||||
(should (null jupyter-test-idle-sync-hook)))))
|
||||
|
||||
;;; IOloop
|
||||
|
||||
(ert-deftest jupyter-ioloop-lifetime ()
|
||||
:tags '(ioloop)
|
||||
(let ((ioloop (jupyter-ioloop))
|
||||
(jupyter-default-timeout 2))
|
||||
(should-not (process-live-p (oref ioloop process)))
|
||||
(jupyter-ioloop-start ioloop #'ignore)
|
||||
(should (equal (jupyter-ioloop-last-event ioloop) '(start)))
|
||||
(with-slots (process) ioloop
|
||||
(should (process-live-p process))
|
||||
(jupyter-ioloop-stop ioloop)
|
||||
(should (equal (jupyter-ioloop-last-event ioloop) '(quit)))
|
||||
(sleep-for 0.1)
|
||||
(should-not (process-live-p process)))))
|
||||
|
||||
(defvar jupyter-ioloop-test-handler-called nil
|
||||
"Flag variable used for testing the `juyter-ioloop'.")
|
||||
|
||||
(defun jupyter-test-ioloop-start (ioloop)
|
||||
(jupyter-ioloop-start
|
||||
ioloop (lambda (event)
|
||||
(should (equal (cadr event) "message"))
|
||||
(setq jupyter-ioloop-test-handler-called t))))
|
||||
|
||||
(ert-deftest jupyter-ioloop-wait-until ()
|
||||
:tags '(ioloop)
|
||||
(let ((ioloop (jupyter-ioloop)))
|
||||
(should-not (jupyter-ioloop-last-event ioloop))
|
||||
(jupyter-test-ioloop-start ioloop)
|
||||
(should (equal (jupyter-ioloop-last-event ioloop) '(start)))
|
||||
(jupyter-ioloop-stop ioloop)))
|
||||
|
||||
(ert-deftest jupyter-ioloop-callbacks ()
|
||||
:tags '(ioloop)
|
||||
(ert-info ("Callback added before starting the ioloop")
|
||||
(let ((ioloop (jupyter-ioloop)))
|
||||
(setq jupyter-ioloop-test-handler-called nil)
|
||||
(jupyter-ioloop-add-callback ioloop
|
||||
`(lambda () (zmq-prin1 (list 'test "message"))))
|
||||
(jupyter-test-ioloop-start ioloop)
|
||||
(jupyter-ioloop-stop ioloop)
|
||||
(should jupyter-ioloop-test-handler-called)))
|
||||
(ert-info ("Callback added after starting the ioloop")
|
||||
(let ((ioloop (jupyter-ioloop)))
|
||||
(setq jupyter-ioloop-test-handler-called nil)
|
||||
(jupyter-test-ioloop-start ioloop)
|
||||
(should (process-live-p (oref ioloop process)))
|
||||
(jupyter-ioloop-add-callback ioloop
|
||||
`(lambda () (zmq-prin1 (list 'test "message"))))
|
||||
(jupyter-ioloop-wait-until ioloop 'test #'identity)
|
||||
(jupyter-ioloop-stop ioloop)
|
||||
(should jupyter-ioloop-test-handler-called))))
|
||||
|
||||
(ert-deftest jupyter-ioloop-setup ()
|
||||
:tags '(ioloop)
|
||||
(let ((ioloop (jupyter-ioloop)))
|
||||
(setq jupyter-ioloop-test-handler-called nil)
|
||||
(jupyter-ioloop-add-setup ioloop
|
||||
(zmq-prin1 (list 'test "message")))
|
||||
(jupyter-test-ioloop-start ioloop)
|
||||
(jupyter-ioloop-stop ioloop)
|
||||
(should jupyter-ioloop-test-handler-called)))
|
||||
|
||||
(ert-deftest jupyter-ioloop-teardown ()
|
||||
:tags '(ioloop)
|
||||
(let ((ioloop (jupyter-ioloop)))
|
||||
(setq jupyter-ioloop-test-handler-called nil)
|
||||
(jupyter-ioloop-add-teardown ioloop
|
||||
(zmq-prin1 (list 'test "message")))
|
||||
(jupyter-test-ioloop-start ioloop)
|
||||
(jupyter-ioloop-stop ioloop)
|
||||
(should jupyter-ioloop-test-handler-called)))
|
||||
|
||||
(ert-deftest jupyter-ioloop-add-event ()
|
||||
:tags '(ioloop)
|
||||
(let ((ioloop (jupyter-ioloop)))
|
||||
(setq jupyter-ioloop-test-handler-called nil)
|
||||
(jupyter-ioloop-add-event ioloop test (data)
|
||||
"Echo DATA back to the parent process."
|
||||
(list 'test data))
|
||||
(jupyter-test-ioloop-start ioloop)
|
||||
(jupyter-send ioloop 'test "message")
|
||||
(jupyter-ioloop-stop ioloop)
|
||||
(should jupyter-ioloop-test-handler-called)))
|
||||
|
||||
(ert-deftest jupyter-channel-ioloop-send-event ()
|
||||
:tags '(ioloop)
|
||||
(jupyter-test-channel-ioloop
|
||||
(ioloop (jupyter-zmq-channel-ioloop))
|
||||
(cl-letf (((symbol-function #'jupyter-send)
|
||||
(lambda (_channel _msg-type _msg msg-id) msg-id)))
|
||||
(setq jupyter-channel-ioloop-session (jupyter-session :key "foo"))
|
||||
(push (jupyter-zmq-channel :type :shell) jupyter-channel-ioloop-channels)
|
||||
(let* ((msg-id (jupyter-new-uuid))
|
||||
(event `(list 'send :shell :execute-request '(msg) ,msg-id)))
|
||||
(jupyter-test-ioloop-eval-event ioloop event)
|
||||
(ert-info ("Return value to parent process")
|
||||
(let ((result (read (buffer-string))))
|
||||
(should (equal result `(sent :shell ,msg-id)))))))))
|
||||
|
||||
(ert-deftest jupyter-channel-ioloop-start-channel-event ()
|
||||
:tags '(ioloop)
|
||||
(jupyter-test-channel-ioloop
|
||||
(ioloop (jupyter-zmq-channel-ioloop))
|
||||
(setq jupyter-channel-ioloop-session (jupyter-session :key "foo"))
|
||||
(let ((channel-endpoint "tcp://127.0.0.1:5555"))
|
||||
(ert-info ("start-channel event creates channel")
|
||||
(should (null jupyter-channel-ioloop-channels))
|
||||
(let ((event `(list 'start-channel :shell ,channel-endpoint)))
|
||||
(jupyter-test-ioloop-eval-event ioloop event))
|
||||
(should-not (null jupyter-channel-ioloop-channels))
|
||||
(let ((channel (object-assoc :shell :type jupyter-channel-ioloop-channels)))
|
||||
(should (jupyter-zmq-channel-p channel))))
|
||||
(let ((channel (object-assoc :shell :type jupyter-channel-ioloop-channels)))
|
||||
(with-slots (type socket endpoint) channel
|
||||
(ert-info ("Verify the requested channel was started")
|
||||
(should (eq type :shell))
|
||||
(should (zmq-socket-p socket))
|
||||
(should (equal endpoint channel-endpoint))
|
||||
(should (equal (zmq-socket-get socket zmq-LAST-ENDPOINT) channel-endpoint))
|
||||
(ert-info ("Identity of socket matches session")
|
||||
(should (equal (zmq-socket-get socket zmq-IDENTITY)
|
||||
(jupyter-session-id jupyter-channel-ioloop-session)))))
|
||||
(ert-info ("Ensure the channel was added to the poller")
|
||||
;; FIXME: Does it make sense to have this side effect as part of starting
|
||||
;; a channel? It makes it so that we don't reference any `zmq' functions
|
||||
;; in `jupyter-channel-ioloop'.
|
||||
(should-error
|
||||
(zmq-poller-add jupyter-ioloop-poller socket (list zmq-POLLIN))
|
||||
:type 'zmq-EINVAL)))
|
||||
(ert-info ("Return value to parent process")
|
||||
(let ((result (read (buffer-string))))
|
||||
(should (equal result `(start-channel :shell)))))))))
|
||||
|
||||
(ert-deftest jupyter-channel-ioloop-stop-channel-event ()
|
||||
:tags '(ioloop)
|
||||
(jupyter-test-channel-ioloop
|
||||
(ioloop (jupyter-zmq-channel-ioloop))
|
||||
(setq jupyter-channel-ioloop-session (jupyter-session :key "foo"))
|
||||
(let ((event `(list 'start-channel :shell "tcp://127.0.0.1:5556")))
|
||||
(jupyter-test-ioloop-eval-event ioloop event)
|
||||
(erase-buffer))
|
||||
(let* ((channel (object-assoc :shell :type jupyter-channel-ioloop-channels))
|
||||
(socket (oref channel socket)))
|
||||
(ert-info ("Verify the requested channel stops")
|
||||
(should (jupyter-alive-p channel))
|
||||
(should (progn (zmq-poller-modify
|
||||
jupyter-ioloop-poller
|
||||
(oref channel socket) (list zmq-POLLIN zmq-POLLOUT))
|
||||
t))
|
||||
(jupyter-test-ioloop-eval-event ioloop `(list 'stop-channel :shell))
|
||||
(should-not (jupyter-alive-p channel)))
|
||||
(ert-info ("Ensure the channel was removed from the poller")
|
||||
(should-error
|
||||
(zmq-poller-modify jupyter-ioloop-poller socket (list zmq-POLLIN))
|
||||
:type 'zmq-EINVAL))
|
||||
(ert-info ("Return value to parent process")
|
||||
(let ((result (read (buffer-string))))
|
||||
(should (equal result `(stop-channel :shell))))))))
|
||||
|
||||
(ert-deftest jupyter-zmq-channel-ioloop-send-fast ()
|
||||
:tags '(ioloop queue)
|
||||
(jupyter-test-with-python-client client
|
||||
(let ((jupyter-current-client client))
|
||||
(jupyter-send client :execute-request :code "1 + 1")
|
||||
(jupyter-send client :execute-request :code "1 + 1")
|
||||
(jupyter-send client :execute-request :code "1 + 1")
|
||||
(let ((req (jupyter-send client :execute-request :code "1 + 1")))
|
||||
(should
|
||||
(equal
|
||||
(jupyter-message-data
|
||||
(jupyter-wait-until-received :execute-result req jupyter-long-timeout)
|
||||
:text/plain)
|
||||
"2"))))))
|
||||
|
||||
;;; Completion
|
||||
|
||||
(ert-deftest jupyter-completion-number-p ()
|
||||
|
|
|
@ -26,6 +26,9 @@
|
|||
|
||||
;;; Code:
|
||||
|
||||
(require 'zmq)
|
||||
(require 'jupyter-zmq-channel-ioloop)
|
||||
(require 'jupyter-kernel-process)
|
||||
(require 'jupyter-repl)
|
||||
(require 'jupyter-server)
|
||||
(require 'jupyter-org-client)
|
||||
|
@ -258,6 +261,29 @@ running BODY."
|
|||
`(jupyter-test-with-kernel-repl "python" ,client
|
||||
,@body))
|
||||
|
||||
(defun jupyter-test-ioloop-eval-event (ioloop event)
|
||||
(eval
|
||||
`(progn
|
||||
,@(oref ioloop setup)
|
||||
,(jupyter-ioloop--event-dispatcher ioloop event))))
|
||||
|
||||
(defmacro jupyter-test-channel-ioloop (ioloop &rest body)
|
||||
(declare (indent 1))
|
||||
(let ((var (car ioloop))
|
||||
(val (cadr ioloop)))
|
||||
(with-temp-buffer
|
||||
`(let* ((,var ,val)
|
||||
(standard-output (current-buffer))
|
||||
(jupyter-channel-ioloop-channels nil)
|
||||
(jupyter-channel-ioloop-session nil)
|
||||
;; Needed so that `jupyter-ioloop-environment-p' passes
|
||||
(jupyter-ioloop-stdin t)
|
||||
(jupyter-ioloop-poller (zmq-poller)))
|
||||
(unwind-protect
|
||||
(progn ,@body)
|
||||
(zmq-poller-destroy jupyter-ioloop-poller)
|
||||
(jupyter-ioloop-stop ,var))))))
|
||||
|
||||
(defmacro jupyter-test-rest-api-request (bodyform &rest check-forms)
|
||||
"Replace the body of `url-retrieve*' with CHECK-FORMS, evaluate BODYFORM.
|
||||
For `url-retrieve', the callback will be called with a nil status."
|
||||
|
@ -386,6 +412,29 @@ message contents."
|
|||
(jupyter-test-wait-until-idle-repl
|
||||
jupyter-current-client))
|
||||
|
||||
(defun jupyter-test-conn-info-plist ()
|
||||
"Return a connection info plist suitable for testing."
|
||||
(let* ((ports
|
||||
(cl-loop
|
||||
with ports = (jupyter-available-local-ports 5)
|
||||
for c in '(:shell :hb :iopub :stdin :control)
|
||||
collect c and collect (pop ports))))
|
||||
`(:shell_port
|
||||
,(plist-get ports :shell)
|
||||
:key "8671b7e4-5656e6c9d24edfce81916780"
|
||||
:hb_port
|
||||
,(plist-get ports :hb)
|
||||
:kernel_name "python"
|
||||
:control_port
|
||||
,(plist-get ports :control)
|
||||
:signature_scheme "hmac-sha256"
|
||||
:ip "127.0.0.1"
|
||||
:stdin_port
|
||||
,(plist-get ports :stdin)
|
||||
:transport "tcp"
|
||||
:iopub_port
|
||||
,(plist-get ports :iopub))))
|
||||
|
||||
(defun jupyter-test-text-has-property (prop val &optional positions)
|
||||
"Ensure PROP has VAL for text at POSITIONS.
|
||||
It is an error if any text not at POSITIONS has PROP. A nil value
|
||||
|
@ -592,6 +641,14 @@ see the documentation on the --NotebookApp.password argument."
|
|||
(process-buffer (car jupyter-test-notebook))
|
||||
(buffer-string)))))))
|
||||
|
||||
(defvar jupyter-test-zmq-sockets (make-hash-table :weakness 'key))
|
||||
|
||||
(advice-add 'zmq-socket
|
||||
:around (lambda (&rest args)
|
||||
(let ((sock (apply args)))
|
||||
(prog1 sock
|
||||
(puthash sock t jupyter-test-zmq-sockets)))))
|
||||
|
||||
;; Do lots of cleanup to avoid core dumps on Travis due to epoll reconnect
|
||||
;; attempts.
|
||||
(add-hook
|
||||
|
@ -601,6 +658,12 @@ see the documentation on the --NotebookApp.password argument."
|
|||
(cl-loop
|
||||
for client in (jupyter-all-objects 'jupyter--clients)
|
||||
do (ignore-errors (jupyter-shutdown-kernel client)))
|
||||
(ignore-errors (delete-process (car jupyter-test-notebook)))))
|
||||
(ignore-errors (delete-process (car jupyter-test-notebook)))
|
||||
(cl-loop
|
||||
for sock being the hash-keys of jupyter-test-zmq-sockets do
|
||||
(ignore-errors
|
||||
(zmq-set-option sock zmq-LINGER 0)
|
||||
(zmq-close sock)))
|
||||
(ignore-errors (zmq-context-terminate (zmq-current-context)))))
|
||||
|
||||
;;; test-helper.el ends here
|
||||
|
|
Loading…
Add table
Reference in a new issue