jupyter_client/
responses.rs

1/*! Available responses back from the kernel.
2*/
3use header::Header;
4use metadata::Metadata;
5use serde_derive::Deserialize;
6use serde_json::Value;
7use std::collections::HashMap;
8
9/// Link pointing to some help text.
10#[derive(Deserialize, Debug, PartialEq, Eq)]
11pub struct HelpLink {
12    /// The text to display.
13    pub text: String,
14    /// The url to point to.
15    pub url: String,
16}
17
18/** Overall response type
19
20There are two responses available:
21
22- responses that come from sending a shell message, and
23- responses that come from the IOPub socket.
24
25These two responses are then wrapped into a single `Response` type so that functions can return any
26response.
27*/
28#[derive(Debug)]
29pub enum Response {
30    /// Response from sending a shell message.
31    Shell(ShellResponse),
32    /// Response from the IOPub socket, sent from the kernel.
33    IoPub(IoPubResponse),
34}
35
36/// Responses from sending shell messages.
37#[derive(Debug)]
38pub enum ShellResponse {
39    /// Response from asking for information about the running kernel.
40    KernelInfo {
41        /// Header from the kernel.
42        header: Header,
43        /// Header sent to the kernel.
44        parent_header: Header,
45        /// Metadata about the response.
46        metadata: Metadata,
47        /// Main response content.
48        content: KernelInfoContent,
49    },
50    /// Response from sending an execute request.
51    Execute {
52        /// Header from the kernel.
53        header: Header,
54        /// Header sent to the kernel.
55        parent_header: Header,
56        /// Metadata about the response.
57        metadata: Metadata,
58        /// Main response content.
59        content: ExecuteReplyContent,
60    },
61    /// Response from inspecting a code block.
62    Inspect {
63        /// Header from the kernel.
64        header: Header,
65        /// Header sent to the kernel.
66        parent_header: Header,
67        /// Metadata about the response.
68        metadata: Metadata,
69        /// Main response content.
70        content: InspectContent,
71    },
72    /// Resposne from asking for code completion.
73    Complete {
74        /// Header from the kernel.
75        header: Header,
76        /// Header sent to the kernel.
77        parent_header: Header,
78        /// Metadata about the response.
79        metadata: Metadata,
80        /// Main response content.
81        content: CompleteContent,
82    },
83    /// Response from fetching kernel command history.
84    History {
85        /// Header from the kernel.
86        header: Header,
87        /// Header sent to the kernel.
88        parent_header: Header,
89        /// Metadata about the response.
90        metadata: Metadata,
91        /// Main response content.
92        content: HistoryContent,
93    },
94    /// Response from asking the kernel if the code is complete.
95    IsComplete {
96        /// Header from the kernel.
97        header: Header,
98        /// Header sent to the kernel.
99        parent_header: Header,
100        /// Metadata about the response.
101        metadata: Metadata,
102        /// Main response content.
103        content: IsCompleteStatus,
104    },
105    /// Response from asking to shut down the kernel.
106    Shutdown {
107        /// Header from the kernel.
108        header: Header,
109        /// Header sent to the kernel.
110        parent_header: Header,
111        /// Metadata about the response.
112        metadata: Metadata,
113        /// Main response content.
114        content: ShutdownContent,
115    },
116    /// Response from asking information about comms.
117    CommInfo {
118        /// Header from the kernel.
119        header: Header,
120        /// Header sent to the kernel.
121        parent_header: Header,
122        /// Metadata about the response.
123        metadata: Metadata,
124        /// Main response content.
125        content: CommInfoContent,
126    },
127}
128
129/// Responses from the IOPub channel.
130#[derive(Debug)]
131pub enum IoPubResponse {
132    /// Response from the kernel showing the current kernel status.
133    Status {
134        /// Header from the kernel.
135        header: Header,
136        /// Header sent to the kernel.
137        parent_header: Header,
138        /// Metadata about the response.
139        metadata: Metadata,
140        /// Main response content.
141        content: StatusContent,
142    },
143    /// Response when any code is run so all clients are aware of it.
144    ExecuteInput {
145        /// Header from the kernel.
146        header: Header,
147        /// Header sent to the kernel.
148        parent_header: Header,
149        /// Metadata about the response.
150        metadata: Metadata,
151        /// Main response content.
152        content: ExecuteInputContent,
153    },
154    /// Response when something is written to stdout/stderr.
155    Stream {
156        /// Header from the kernel.
157        header: Header,
158        /// Header sent to the kernel.
159        parent_header: Header,
160        /// Metadata about the response.
161        metadata: Metadata,
162        /// Main response content.
163        content: StreamContent,
164    },
165    /// Response when a response has mutliple formats.
166    ExecuteResult {
167        /// Header from the kernel.
168        header: Header,
169        /// Header sent to the kernel.
170        parent_header: Header,
171        /// Metadata about the response.
172        metadata: Metadata,
173        /// Main response content.
174        content: ExecuteResultContent,
175    },
176    /// Response when an error occurs.
177    Error {
178        /// Header from the kernel.
179        header: Header,
180        /// Header sent to the kernel.
181        parent_header: Header,
182        /// Metadata about the response.
183        metadata: Metadata,
184        /// Main response content.
185        content: ErrorContent,
186    },
187    /// Response when the kernel askes the client to clear it's output.
188    ClearOutput {
189        /// Header from the kernel.
190        header: Header,
191        /// Header sent to the kernel.
192        parent_header: Header,
193        /// Metadata about the response.
194        metadata: Metadata,
195        /// Main response content.
196        content: ClearOutputContent,
197    },
198}
199
200/// Content for a KernelInfo response.
201#[derive(Deserialize, Debug)]
202pub struct KernelInfoContent {
203    /// Status of the request.
204    pub status: Status,
205    /// Version of the messaging protocol.
206    pub protocol_version: String,
207    /// The kernel implementation name.
208    pub implementation: String,
209    /// The kernel implementation version.
210    pub implementation_version: String,
211    /// Information about the language of code for the kernel.
212    pub language_info: LanguageInfo,
213    /// A banner of information about the kernel.
214    pub banner: String,
215    /// List of help entries.
216    pub help_links: Vec<HelpLink>,
217}
218
219/// Information about the language of code for the kernel.
220#[derive(Deserialize, Debug)]
221pub struct LanguageInfo {
222    /// Name of the programming language the kernel implements.
223    pub name: String,
224    /// The language version number.
225    pub version: String,
226    /// Mimetype for script files in this language.
227    pub mimetype: String,
228    /// Extension including the dot e.g. '.py'
229    pub file_extension: String,
230    /// Pygments lexer for highlighting.
231    pub pygments_lexer: String,
232    /// Codemirror mode, for highlighting in the notebook.
233    pub codemirror_mode: Value,
234    /// If notebooks written with this kernel should be exported with something other than the
235    /// general 'script' exporter.
236    pub nbconvert_exporter: String,
237}
238
239/// Information from code execution.
240#[derive(Deserialize, Debug)]
241pub struct ExecuteReplyContent {
242    /// Status of the request.
243    pub status: Status,
244    /// Global execution count.
245    pub execution_count: i64,
246    // status == "ok" fields
247    /// List of payload dicts (deprecated).
248    pub payload: Option<Vec<HashMap<String, Value>>>,
249    /// Results for the user expressions.
250    pub user_expressions: Option<HashMap<String, Value>>,
251    // status == "error" fields
252    /// Exception name as a string.
253    pub ename: Option<String>,
254    /// Exception value, as a string.
255    pub evalue: Option<String>,
256    /// Traceback frames as strings.
257    pub traceback: Option<Vec<String>>,
258}
259
260/// Response from the IOPub status messages
261#[derive(Deserialize, Debug)]
262pub struct StatusContent {
263    /// The state of the kernel.
264    pub execution_state: ExecutionState,
265}
266
267/// Response when code is input to the kernel.
268#[derive(Deserialize, Debug)]
269pub struct ExecuteInputContent {
270    /// The code that was run.
271    pub code: String,
272    /// Counter for the execution number.
273    pub execution_count: i64,
274}
275
276/// Response from inspecting code
277#[derive(Deserialize, Debug)]
278pub struct InspectContent {
279    /// Status of the request.
280    pub status: Status,
281    /// Whether the object was found or not.
282    pub found: bool,
283    /// Empty if nothing is found.
284    pub data: HashMap<String, Value>,
285    /// Metadata.
286    pub metadata: HashMap<String, Value>,
287}
288
289/// Response when printing to stdout/stderr.
290#[derive(Deserialize, Debug)]
291pub struct StreamContent {
292    /// Type of the stream.
293    pub name: StreamType,
294    /// Text to be written to the stream.
295    pub text: String,
296}
297
298/// Content of an error response.
299#[derive(Deserialize, Debug)]
300pub struct ErrorContent {
301    /// Exception name as a string.
302    pub ename: String,
303    /// Exception value, as a string.
304    pub evalue: String,
305    /// Traceback frames as strings.
306    pub traceback: Vec<String>,
307}
308
309/// Content when asking for code completion.
310#[derive(Deserialize, Debug)]
311pub struct CompleteContent {
312    /// Status of the request.
313    pub status: Status,
314    /// List of all matches.
315    pub matches: Vec<String>,
316    /// The start index text that should be replaced by the match.
317    pub cursor_start: u64,
318    /// The end index text that should be replaced by the match.
319    pub cursor_end: u64,
320    /// Extra information.
321    pub metadata: HashMap<String, Value>,
322}
323
324/// Content when asking for history entries.
325#[derive(Deserialize, Debug)]
326pub struct HistoryContent {
327    /// Status of the request.
328    pub status: Status,
329    /// List of history items.
330    pub history: Vec<Value>,
331}
332
333/// Response when asking the kernel to shutdown.
334#[derive(Deserialize, Debug)]
335pub struct ShutdownContent {
336    /// Status of the request.
337    pub status: Status,
338    /// Whether restart was requested.
339    pub restart: bool,
340}
341
342/// Response when asking for comm info.
343#[derive(Deserialize, Debug)]
344pub struct CommInfoContent {
345    /// Status of the request.
346    pub status: Status,
347    /// Map of available comms.
348    pub comms: HashMap<String, HashMap<String, String>>,
349}
350
351/// Response when requesting to execute code.
352#[derive(Deserialize, Debug)]
353pub struct ExecuteResultContent {
354    /// Global execution count.
355    pub execution_count: i64,
356    /// The result of the execution.
357    pub data: HashMap<String, String>,
358    /// Metadata about the execution.
359    pub metadata: Value,
360}
361
362/// Response when the kernel asks the client to clear the output.
363#[derive(Deserialize, Debug)]
364pub struct ClearOutputContent {
365    /// Wait to clear the output until new output is available.
366    pub wait: bool,
367}
368
369/// State of the kernel.
370#[derive(Deserialize, Debug, PartialEq)]
371#[serde(rename_all = "lowercase")]
372pub enum ExecutionState {
373    /// Running code.
374    Busy,
375    /// Doing nothing.
376    Idle,
377    /// Booting.
378    Starting,
379}
380
381/// Status of if entered code is complete (i.e. does not need another " character).
382#[derive(Deserialize, Debug, PartialEq)]
383#[serde(rename_all = "lowercase")]
384pub enum IsCompleteStatus {
385    /// Entered code is complete.
386    Complete,
387    /// More code is required. The argument is the indent value for the prompt.
388    Incomplete(String),
389    /// Invalid completion.
390    Invalid,
391    /// Unknown completion.
392    Unknown,
393}
394
395/// Type of stream, either stdout or stderr.
396#[derive(Deserialize, Debug, PartialEq)]
397#[serde(rename_all = "lowercase")]
398#[allow(missing_docs)]
399pub enum StreamType {
400    Stdout,
401    Stderr,
402}
403
404/// Status of the request.
405#[derive(Deserialize, Debug, PartialEq)]
406#[serde(rename_all = "lowercase")]
407#[allow(missing_docs)]
408pub enum Status {
409    Ok,
410    Error,
411    Abort,
412}
413
414#[cfg(test)]
415mod tests {
416    use super::*;
417    use crate::test_helpers::*;
418    use crate::wire::WireMessage;
419
420    #[test]
421    fn test_kernel_info_message_parsing() {
422        let auth = FakeAuth::create();
423        let raw_response = vec![
424            "<IDS|MSG>".to_string().into_bytes(),
425            expected_signature().into_bytes(),
426            // Header
427            r#"{
428                "date": "",
429                "msg_id": "",
430                "username": "",
431                "session": "",
432                "msg_type": "kernel_info_reply",
433                "version": ""
434            }"#.to_string()
435            .into_bytes(),
436            // Parent header
437            r#"{
438                "date": "",
439                "msg_id": "",
440                "username": "",
441                "session": "",
442                "msg_type": "kernel_info_request",
443                "version": ""
444            }"#.to_string()
445            .into_bytes(),
446            // Metadata
447            r#"{}"#.to_string().into_bytes(),
448            // Content
449            r#"{
450                "banner": "banner",
451                "implementation": "implementation",
452                "implementation_version": "implementation_version",
453                "protocol_version": "protocol_version",
454                "status": "ok",
455                "language_info": {
456                    "name": "python",
457                    "version": "3.7.0",
458                    "mimetype": "text/x-python",
459                    "file_extension": ".py",
460                    "pygments_lexer": "ipython3",
461                    "codemirror_mode": {
462                        "name": "ipython",
463                        "version": 3
464                    },
465                    "nbconvert_exporter": "python"
466                },
467                "help_links": [{"text": "text", "url": "url"}]
468            }"#.to_string()
469            .into_bytes(),
470        ];
471        let msg = WireMessage::from_raw_response(raw_response, auth.clone()).unwrap();
472        let response = msg.into_response().unwrap();
473        match response {
474            Response::Shell(ShellResponse::KernelInfo {
475                header,
476                parent_header: _parent_header,
477                metadata: _metadata,
478                content,
479            }) => {
480                // Check the header
481                assert_eq!(header.msg_type, "kernel_info_reply");
482
483                // Check the content
484                assert_eq!(content.banner, "banner");
485                assert_eq!(content.implementation, "implementation");
486                assert_eq!(content.implementation_version, "implementation_version");
487                assert_eq!(content.protocol_version, "protocol_version");
488                assert_eq!(content.status, Status::Ok);
489                assert_eq!(
490                    content.help_links,
491                    vec![HelpLink {
492                        text: "text".to_string(),
493                        url: "url".to_string(),
494                    }]
495                );
496                assert_eq!(content.language_info.name, "python");
497            }
498            _ => unreachable!("Incorrect response type, should be KernelInfo"),
499        }
500    }
501
502    #[test]
503    fn test_execute_request_message_parsing() {
504        let auth = FakeAuth::create();
505        let raw_response = vec![
506            "<IDS|MSG>".to_string().into_bytes(),
507            expected_signature().into_bytes(),
508            // Header
509            r#"{
510                "date": "",
511                "msg_id": "",
512                "username": "",
513                "session": "",
514                "msg_type": "execute_reply",
515                "version": ""
516            }"#.to_string()
517            .into_bytes(),
518            // Parent header
519            r#"{
520                "date": "",
521                "msg_id": "",
522                "username": "",
523                "session": "",
524                "msg_type": "execute_request",
525                "version": ""
526            }"#.to_string()
527            .into_bytes(),
528            // Metadata
529            r#"{}"#.to_string().into_bytes(),
530            // Content
531            r#"{
532                "status": "ok",
533                "execution_count": 4
534            }"#.to_string()
535            .into_bytes(),
536        ];
537        let msg = WireMessage::from_raw_response(raw_response, auth.clone()).unwrap();
538        let response = msg.into_response().unwrap();
539        match response {
540            Response::Shell(ShellResponse::Execute {
541                header,
542                parent_header: _parent_header,
543                metadata: _metadata,
544                content,
545            }) => {
546                // Check the header
547                assert_eq!(header.msg_type, "execute_reply");
548
549                // Check the content
550                assert_eq!(content.status, Status::Ok);
551                assert_eq!(content.execution_count, 4);
552            }
553            _ => unreachable!("Incorrect response type, should be KernelInfo"),
554        }
555    }
556
557    #[test]
558    fn test_status_message_parsing() {
559        let auth = FakeAuth::create();
560        let raw_response = vec![
561            "<IDS|MSG>".to_string().into_bytes(),
562            expected_signature().into_bytes(),
563            // Header
564            r#"{
565                "date": "",
566                "msg_id": "",
567                "username": "",
568                "session": "",
569                "msg_type": "status",
570                "version": ""
571            }"#.to_string()
572            .into_bytes(),
573            // Parent header, not relevant
574            r#"{
575                "date": "",
576                "msg_id": "",
577                "username": "",
578                "session": "",
579                "msg_type": "execute_request",
580                "version": ""
581            }"#.to_string()
582            .into_bytes(),
583            // Metadata
584            r#"{}"#.to_string().into_bytes(),
585            // Content
586            r#"{
587                "status": "ok",
588                "execution_state": "busy"
589            }"#.to_string()
590            .into_bytes(),
591        ];
592        let msg = WireMessage::from_raw_response(raw_response, auth.clone()).unwrap();
593        let response = msg.into_response().unwrap();
594        match response {
595            Response::IoPub(IoPubResponse::Status {
596                header,
597                parent_header: _parent_header,
598                metadata: _metadata,
599                content,
600            }) => {
601                // Check the header
602                assert_eq!(header.msg_type, "status");
603
604                // Check the content
605                assert_eq!(content.execution_state, ExecutionState::Busy);
606            }
607            _ => unreachable!("Incorrect response type, should be Status"),
608        }
609    }
610
611    #[test]
612    fn test_execute_input_parsing() {
613        let auth = FakeAuth::create();
614        let raw_response = vec![
615            "<IDS|MSG>".to_string().into_bytes(),
616            expected_signature().into_bytes(),
617            // Header
618            r#"{
619                "date": "",
620                "msg_id": "",
621                "username": "",
622                "session": "",
623                "msg_type": "execute_input",
624                "version": ""
625            }"#.to_string()
626            .into_bytes(),
627            // Parent header, not relevant
628            r#"{
629                "date": "",
630                "msg_id": "",
631                "username": "",
632                "session": "",
633                "msg_type": "",
634                "version": ""
635            }"#.to_string()
636            .into_bytes(),
637            // Metadata
638            r#"{}"#.to_string().into_bytes(),
639            // Content
640            r#"{
641                "status": "ok",
642                "code": "a = 10",
643                "execution_count": 4
644            }"#.to_string()
645            .into_bytes(),
646        ];
647        let msg = WireMessage::from_raw_response(raw_response, auth.clone()).unwrap();
648        let response = msg.into_response().unwrap();
649        match response {
650            Response::IoPub(IoPubResponse::ExecuteInput {
651                header,
652                parent_header: _parent_header,
653                metadata: _metadata,
654                content,
655            }) => {
656                // Check the header
657                assert_eq!(header.msg_type, "execute_input");
658
659                // Check the content
660                assert_eq!(content.code, "a = 10");
661                assert_eq!(content.execution_count, 4);
662            }
663            _ => unreachable!("Incorrect response type, should be Status"),
664        }
665    }
666
667    #[test]
668    fn test_stream_parsing() {
669        let auth = FakeAuth::create();
670        let raw_response = vec![
671            "<IDS|MSG>".to_string().into_bytes(),
672            expected_signature().into_bytes(),
673            // Header
674            r#"{
675                "date": "",
676                "msg_id": "",
677                "username": "",
678                "session": "",
679                "msg_type": "stream",
680                "version": ""
681            }"#.to_string()
682            .into_bytes(),
683            // Parent header, not relevant
684            r#"{
685                "date": "",
686                "msg_id": "",
687                "username": "",
688                "session": "",
689                "msg_type": "",
690                "version": ""
691            }"#.to_string()
692            .into_bytes(),
693            // Metadata
694            r#"{}"#.to_string().into_bytes(),
695            // Content
696            r#"{
697                "status": "ok",
698                "name": "stdout",
699                "text": "10"
700            }"#.to_string()
701            .into_bytes(),
702        ];
703        let msg = WireMessage::from_raw_response(raw_response, auth.clone()).unwrap();
704        let response = msg.into_response().unwrap();
705        match response {
706            Response::IoPub(IoPubResponse::Stream {
707                header,
708                parent_header: _parent_header,
709                metadata: _metadata,
710                content,
711            }) => {
712                // Check the header
713                assert_eq!(header.msg_type, "stream");
714
715                // Check the content
716                assert_eq!(content.name, StreamType::Stdout);
717                assert_eq!(content.text, "10");
718            }
719            _ => unreachable!("Incorrect response type, should be Stream"),
720        }
721    }
722
723    #[test]
724    fn test_is_complete_message_parsing() {
725        let auth = FakeAuth::create();
726        let raw_response = vec![
727            "<IDS|MSG>".to_string().into_bytes(),
728            expected_signature().into_bytes(),
729            // Header
730            r#"{
731                "date": "",
732                "msg_id": "",
733                "username": "",
734                "session": "",
735                "msg_type": "is_complete_reply",
736                "version": ""
737            }"#.to_string()
738            .into_bytes(),
739            // Parent header
740            r#"{
741                "date": "",
742                "msg_id": "",
743                "username": "",
744                "session": "",
745                "msg_type": "is_complete_request",
746                "version": ""
747            }"#.to_string()
748            .into_bytes(),
749            // Metadata
750            r#"{}"#.to_string().into_bytes(),
751            // Content
752            r#"{
753                "status": "complete"
754            }"#.to_string()
755            .into_bytes(),
756        ];
757        let msg = WireMessage::from_raw_response(raw_response, auth.clone()).unwrap();
758        let response = msg.into_response().unwrap();
759        match response {
760            Response::Shell(ShellResponse::IsComplete {
761                header,
762                parent_header: _parent_header,
763                metadata: _metadata,
764                content,
765            }) => {
766                // Check the header
767                assert_eq!(header.msg_type, "is_complete_reply");
768
769                // Check the content
770                assert_eq!(content, IsCompleteStatus::Complete);
771            }
772            _ => unreachable!("Incorrect response type, should be IsComplete"),
773        }
774    }
775
776    #[test]
777    fn test_is_complete_message_parsing_with_incomplete_reply() {
778        let auth = FakeAuth::create();
779        let raw_response = vec![
780            "<IDS|MSG>".to_string().into_bytes(),
781            expected_signature().into_bytes(),
782            // Header
783            r#"{
784                "date": "",
785                "msg_id": "",
786                "username": "",
787                "session": "",
788                "msg_type": "is_complete_reply",
789                "version": ""
790            }"#.to_string()
791            .into_bytes(),
792            // Parent header
793            r#"{
794                "date": "",
795                "msg_id": "",
796                "username": "",
797                "session": "",
798                "msg_type": "is_complete_request",
799                "version": ""
800            }"#.to_string()
801            .into_bytes(),
802            // Metadata
803            r#"{}"#.to_string().into_bytes(),
804            // Content
805            r#"{
806                "status": "incomplete",
807                "indent": "  "
808            }"#.to_string()
809            .into_bytes(),
810        ];
811        let msg = WireMessage::from_raw_response(raw_response, auth.clone()).unwrap();
812        let response = msg.into_response().unwrap();
813        match response {
814            Response::Shell(ShellResponse::IsComplete {
815                header,
816                parent_header: _parent_header,
817                metadata: _metadata,
818                content,
819            }) => {
820                // Check the header
821                assert_eq!(header.msg_type, "is_complete_reply");
822
823                // Check the content
824                assert_eq!(content, IsCompleteStatus::Incomplete("  ".to_string()));
825            }
826            _ => unreachable!("Incorrect response type, should be IsComplete"),
827        }
828    }
829
830    #[test]
831    fn test_shutdown_message_parsing() {
832        let auth = FakeAuth::create();
833        let raw_response = vec![
834            "<IDS|MSG>".to_string().into_bytes(),
835            expected_signature().into_bytes(),
836            // Header
837            r#"{
838                "date": "",
839                "msg_id": "",
840                "username": "",
841                "session": "",
842                "msg_type": "shutdown_reply",
843                "version": ""
844            }"#.to_string()
845            .into_bytes(),
846            // Parent header
847            r#"{
848                "date": "",
849                "msg_id": "",
850                "username": "",
851                "session": "",
852                "msg_type": "kernel_info_request",
853                "version": ""
854            }"#.to_string()
855            .into_bytes(),
856            // Metadata
857            r#"{}"#.to_string().into_bytes(),
858            // Content
859            r#"{
860                "status": "ok",
861                "restart": false
862            }"#.to_string()
863            .into_bytes(),
864        ];
865        let msg = WireMessage::from_raw_response(raw_response, auth.clone()).unwrap();
866        let response = msg.into_response().unwrap();
867        match response {
868            Response::Shell(ShellResponse::Shutdown {
869                header,
870                parent_header: _parent_header,
871                metadata: _metadata,
872                content,
873            }) => {
874                // Check the header
875                assert_eq!(header.msg_type, "shutdown_reply");
876
877                // Check the content
878                assert_eq!(content.restart, false);
879            }
880            _ => unreachable!("Incorrect response type, should be KernelInfo"),
881        }
882    }
883
884    #[test]
885    fn test_comm_info_message_parsing() {
886        let auth = FakeAuth::create();
887        let raw_response = vec![
888            "<IDS|MSG>".to_string().into_bytes(),
889            expected_signature().into_bytes(),
890            // Header
891            r#"{
892                "date": "",
893                "msg_id": "",
894                "username": "",
895                "session": "",
896                "msg_type": "comm_info_reply",
897                "version": ""
898            }"#.to_string()
899            .into_bytes(),
900            // Parent header
901            r#"{
902                "date": "",
903                "msg_id": "",
904                "username": "",
905                "session": "",
906                "msg_type": "comm_info_request",
907                "version": ""
908            }"#.to_string()
909            .into_bytes(),
910            // Metadata
911            r#"{}"#.to_string().into_bytes(),
912            // Content
913            r#"{
914                "status": "ok",
915                "comms": {
916                    "u-u-i-d": {
917                        "target_name": "foobar"
918                    }
919                }
920            }"#.to_string()
921            .into_bytes(),
922        ];
923        let msg = WireMessage::from_raw_response(raw_response, auth.clone()).unwrap();
924        let response = msg.into_response().unwrap();
925        match response {
926            Response::Shell(ShellResponse::CommInfo {
927                header,
928                parent_header: _parent_header,
929                metadata: _metadata,
930                content,
931            }) => {
932                // Check the header
933                assert_eq!(header.msg_type, "comm_info_reply");
934
935                // Check the content
936                assert_eq!(content.comms["u-u-i-d"]["target_name"], "foobar");
937            }
938            _ => unreachable!("Incorrect response type, should be CommInfo"),
939        }
940    }
941
942    #[test]
943    fn test_execute_result_message_parsing() {
944        use serde_json::json;
945
946        let auth = FakeAuth::create();
947        let raw_response = vec![
948            "<IDS|MSG>".to_string().into_bytes(),
949            expected_signature().into_bytes(),
950            // Header
951            r#"{
952                "date": "",
953                "msg_id": "",
954                "username": "",
955                "session": "",
956                "msg_type": "execute_result",
957                "version": ""
958            }"#.to_string()
959            .into_bytes(),
960            // Parent header
961            r#"{
962                "date": "",
963                "msg_id": "",
964                "username": "",
965                "session": "",
966                "msg_type": "execute_request",
967                "version": ""
968            }"#.to_string()
969            .into_bytes(),
970            // Metadata
971            r#"{}"#.to_string().into_bytes(),
972            // Content
973            r#"{
974                "data": {
975                    "text/plain": "10"
976                },
977                "metadata": {},
978                "execution_count": 46
979            }"#.to_string()
980            .into_bytes(),
981        ];
982        let msg = WireMessage::from_raw_response(raw_response, auth.clone()).unwrap();
983        let response = msg.into_response().unwrap();
984        match response {
985            Response::IoPub(IoPubResponse::ExecuteResult {
986                header,
987                parent_header: _parent_header,
988                metadata: _metadata,
989                content,
990            }) => {
991                // Check the header
992                assert_eq!(header.msg_type, "execute_result");
993
994                // Check the content
995                assert_eq!(content.data["text/plain"], "10");
996                assert_eq!(content.metadata, json!({}));
997                assert_eq!(content.execution_count, 46);
998            }
999            _ => unreachable!("Incorrect response type, should be ExecuteResult"),
1000        }
1001    }
1002
1003    #[test]
1004    fn test_clear_output_message_parsing() {
1005        let auth = FakeAuth::create();
1006        let raw_response = vec![
1007            "<IDS|MSG>".to_string().into_bytes(),
1008            expected_signature().into_bytes(),
1009            // Header
1010            r#"{
1011                "date": "",
1012                "msg_id": "",
1013                "username": "",
1014                "session": "",
1015                "msg_type": "clear_output",
1016                "version": ""
1017            }"#.to_string()
1018            .into_bytes(),
1019            // Parent header
1020            r#"{
1021                "date": "",
1022                "msg_id": "",
1023                "username": "",
1024                "session": "",
1025                "msg_type": "execute_request",
1026                "version": ""
1027            }"#.to_string()
1028            .into_bytes(),
1029            // Metadata
1030            r#"{}"#.to_string().into_bytes(),
1031            // Content
1032            r#"{
1033                "wait": false
1034            }"#.to_string()
1035            .into_bytes(),
1036        ];
1037        let msg = WireMessage::from_raw_response(raw_response, auth.clone()).unwrap();
1038        let response = msg.into_response().unwrap();
1039        match response {
1040            Response::IoPub(IoPubResponse::ClearOutput {
1041                header,
1042                parent_header: _parent_header,
1043                metadata: _metadata,
1044                content,
1045            }) => {
1046                // Check the header
1047                assert_eq!(header.msg_type, "clear_output");
1048
1049                // Check the content
1050                assert_eq!(content.wait, false);
1051            }
1052            _ => unreachable!("Incorrect response type, should be ClearOutput"),
1053        }
1054    }
1055}