kernels.scm 6.23 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
;;; Guix-kernel -- Guix kernel for Jupyter
;;; Copyright (C) 2019 Inria
;;;
;;; This program is free software: you can redistribute it and/or modify
;;; it under the terms of the GNU General Public License as published by
;;; the Free Software Foundation, either version 3 of the License, or
;;; (at your option) any later version.
;;;
;;; This program is distributed in the hope that it will be useful,
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;; GNU General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with this program.  If not, see <https://www.gnu.org/licenses/>.

(define-module (tests kernels)
  #:use-module (jupyter kernels)
  #:use-module (jupyter messages)
  #:use-module (simple-zmq)
  #:use-module (json)
  #:use-module (rnrs bytevectors)
23
  #:use-module (srfi srfi-1)
24
25
26
  #:use-module (srfi srfi-26)
  #:use-module (srfi srfi-64)
  #:use-module (ice-9 match))
27
28
29
30

(define %context
  (zmq-create-context))

31
32
33
(define %python3-specs
  (false-if-exception (find-kernel-specs "python3")))

34
35
36
37
38
39
40
(define %kernel-key "secretkey")

(define %kernel #f)

(test-begin "kernels")

;; These tests require the "python3" kernel provided by ipykernel.
41
(unless %python3-specs (test-skip 1))
42
43

(test-assert "run-kernel python3"
44
  (let ((kernel (run-kernel %context %python3-specs %kernel-key)))
45
46
    (set! %kernel kernel)
    (and (kernel? (pk 'kernel kernel))
47
48
49
50
51
         (begin
           (kill (kernel-pid kernel) 0)

           ;; FIXME: For some reason, we don't always get a "starting" status
           ;; message.  Thus, don't fail if we don't receive it.
52
           (let ((greetings (read-message %kernel 5000)))
53
54
             (or (not greetings)
                 (list (message-type greetings)
55
56
57
                       (kernel-status-execution-state
                        (json->kernel-status
                         (message-content greetings))))))))))
58
59
60
61
62
63
64

(unless %kernel (test-skip 1))
(test-equal "kernel_info_request"
  "python"
  (let ((request (message (header "kernel_info_request" "luser" "12345")
                          "{}")))
    (send-message %kernel request)
65
66
67
68
69
70
71
    (let* ((replies (unfold (cut > <> 2)
                            (lambda (_)
                              (read-message %kernel 10000))
                            1+ 0)))
      (define (type-predicate type)
        (lambda (message)
          (string=? (message-type message) type)))
72

73
      (and (every message? (pk 'replies replies))
74

75
76
77
           (match (filter (type-predicate "status") replies)
             ((busy idle)
              ;; We got two message: busy *then* idle.
78
79
80
81
82
83
              (and (eq? 'busy
                        (kernel-status-execution-state
                         (json->kernel-status (message-content busy))))
                   (eq? 'idle
                        (kernel-status-execution-state
                         (json->kernel-status (message-content idle))))
84
85
86
87
                   (equal? (message-parent-header busy)
                           (message-header request))
                   (equal? (message-parent-header idle)
                           (message-header request)))))
88

89
90
91
92
           (let ((reply (find (type-predicate "kernel_info_reply")
                              replies)))
             (and (equal? (message-parent-header reply)
                          (message-header request))
93
94
95
96
                  (let ((reply (json->kernel-info-reply
                                (message-content reply))))
                    (language-info-name
                     (kernel-info-reply-language-info reply)))))))))
97
98

(unless %kernel (test-skip 1))
99
100
(test-equal "execute_request"
  42
101
102
  (let ((request (message (header "execute_request" "luser" "12345")
                          (scm->json-string
103
104
                           (execute-request->json
                            (execute-request (code "40 + 2\n")))))))
105
    (send-message %kernel request)
106
107
108
109
110
111

    ;; As noted at
    ;; <https://jupyter-client.readthedocs.io/en/latest/messaging.html#request-reply>,
    ;; in the request-reply pattern, we first receive on the iopub socket a
    ;; "status" message, then our input is broadcast on iopub, and then we
    ;; get the result.
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
    ;;
    ;; However, ordering is not guaranteed: since we poll on all these
    ;; sockets, we might get the iopub message before the shell message.
    ;; Thus, this test does not make any assumptions on ordering.
    (let* ((replies (unfold (cut > <> 4)
                            (lambda (_)
                              (read-message %kernel 10000))
                            1+ 0)))
      (define (type-predicate type)
        (lambda (message)
          (string=? (message-type message) type)))

      (and (every message? (pk 'replies replies))

           (match (filter (type-predicate "status") replies)
             ((busy idle)
              ;; We got two message: busy *then* idle.
129
130
131
132
133
134
              (and (eq? 'busy
                        (kernel-status-execution-state
                         (json->kernel-status (message-content busy))))
                   (eq? 'idle
                        (kernel-status-execution-state
                         (json->kernel-status (message-content idle))))
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
                   (equal? (message-parent-header busy)
                           (message-header request))
                   (equal? (message-parent-header idle)
                           (message-header request)))))

           (let ((input (find (type-predicate "execute_input") replies)))
             (equal? (message-parent-header input) (message-header request)))

           (let ((reply (find (type-predicate "execute_reply") replies)))
             (equal? (message-parent-header reply) (message-header request)))

           (let ((result (find (type-predicate "execute_result") replies)))
             (and (equal? (message-parent-header result)
                          (message-header request))
                  (let* ((content (json-string->scm (message-content result)))
                         (data    (assoc-ref content "data"))
                         (text    (assoc-ref data "text/plain")))
                    (string->number text))))))))
153
154
155
156
157
158

(when %kernel
  (close-kernel %kernel)
  (kill (kernel-pid %kernel) 15))

(test-end "kernels")