ikernel.spec.ts 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543
  1. // Copyright (c) Jupyter Development Team.
  2. // Distributed under the terms of the Modified BSD License.
  3. import { PageConfig } from '@jupyterlab/coreutils';
  4. import {
  5. expectFailure,
  6. flakyIt as it,
  7. JupyterServer,
  8. testEmission
  9. } from '@jupyterlab/testutils';
  10. import { PromiseDelegate, UUID } from '@lumino/coreutils';
  11. import {
  12. Kernel,
  13. KernelManager,
  14. KernelMessage,
  15. KernelSpec,
  16. KernelSpecAPI
  17. } from '../../src';
  18. import { FakeKernelManager, handleRequest, KernelTester } from '../utils';
  19. const server = new JupyterServer();
  20. beforeAll(async () => {
  21. await server.start();
  22. });
  23. afterAll(async () => {
  24. await server.shutdown();
  25. });
  26. describe('Kernel.IKernel', () => {
  27. let defaultKernel: Kernel.IKernelConnection;
  28. let specs: KernelSpec.ISpecModels;
  29. let kernelManager: KernelManager;
  30. beforeAll(async () => {
  31. jest.setTimeout(20000);
  32. kernelManager = new FakeKernelManager();
  33. specs = await KernelSpecAPI.getSpecs();
  34. });
  35. beforeEach(async () => {
  36. defaultKernel = await kernelManager.startNew();
  37. await defaultKernel.info;
  38. });
  39. afterEach(async () => {
  40. await defaultKernel.shutdown();
  41. defaultKernel.dispose();
  42. });
  43. afterAll(async () => {
  44. await kernelManager.shutdownAll();
  45. });
  46. describe('#disposed', () => {
  47. it('should be emitted when the kernel is disposed', async () => {
  48. await defaultKernel.info;
  49. let called = false;
  50. defaultKernel.disposed.connect((sender, args) => {
  51. expect(sender).toBe(defaultKernel);
  52. expect(args).toBeUndefined();
  53. called = true;
  54. });
  55. defaultKernel.dispose();
  56. expect(called).toBe(true);
  57. });
  58. it('should be emitted when the kernel is shut down', async () => {
  59. await defaultKernel.info;
  60. let called = false;
  61. defaultKernel.disposed.connect((sender, args) => {
  62. expect(sender).toBe(defaultKernel);
  63. expect(args).toBeUndefined();
  64. called = true;
  65. });
  66. await defaultKernel.shutdown();
  67. expect(called).toBe(true);
  68. });
  69. });
  70. describe('#statusChanged', () => {
  71. it('should be a signal following the Kernel status', async () => {
  72. let called = false;
  73. defaultKernel.statusChanged.connect(() => {
  74. if (defaultKernel.status === 'busy') {
  75. called = true;
  76. }
  77. });
  78. await defaultKernel.requestExecute({ code: 'a=1' }, true).done;
  79. expect(called).toBe(true);
  80. });
  81. });
  82. describe('#pendingInput', () => {
  83. it('should be a signal following input request', async () => {
  84. let called = false;
  85. defaultKernel.pendingInput.connect((sender, args) => {
  86. if (!called) {
  87. called = true;
  88. defaultKernel.sendInputReply({ status: 'ok', value: 'foo' });
  89. }
  90. });
  91. const code = `input("Input something")`;
  92. await defaultKernel.requestExecute(
  93. {
  94. code: code,
  95. allow_stdin: true
  96. },
  97. true
  98. ).done;
  99. expect(called).toBe(true);
  100. });
  101. });
  102. describe('#iopubMessage', () => {
  103. it('should be emitted for an iopub message', async () => {
  104. let called = false;
  105. defaultKernel.iopubMessage.connect((k, msg) => {
  106. called = true;
  107. });
  108. await defaultKernel.requestExecute({ code: 'a=1' }, true).done;
  109. expect(called).toBe(true);
  110. });
  111. it('should be emitted regardless of the sender', async () => {
  112. const tester = new KernelTester();
  113. const kernel = await tester.start();
  114. const msgId = UUID.uuid4();
  115. const emission = testEmission(kernel.iopubMessage, {
  116. find: (k, msg) => msg.header.msg_id === msgId
  117. });
  118. const msg = KernelMessage.createMessage({
  119. msgType: 'status',
  120. channel: 'iopub',
  121. session: tester.serverSessionId,
  122. msgId,
  123. content: {
  124. execution_state: 'idle'
  125. }
  126. });
  127. tester.send(msg);
  128. await emission;
  129. await tester.shutdown();
  130. tester.dispose();
  131. });
  132. });
  133. describe('#unhandledMessage', () => {
  134. let tester: KernelTester;
  135. beforeEach(() => {
  136. tester = new KernelTester();
  137. });
  138. afterEach(async () => {
  139. await tester.shutdown();
  140. tester.dispose();
  141. });
  142. it('should be emitted for an unhandled message', async () => {
  143. const kernel = await tester.start();
  144. const msgId = UUID.uuid4();
  145. const emission = testEmission(kernel.unhandledMessage, {
  146. find: (k, msg) => msg.header.msg_id === msgId
  147. });
  148. const msg = KernelMessage.createMessage({
  149. msgType: 'kernel_info_request',
  150. channel: 'shell',
  151. session: tester.serverSessionId,
  152. msgId,
  153. content: {}
  154. });
  155. msg.parent_header = { session: kernel.clientId };
  156. tester.send(msg);
  157. await emission;
  158. });
  159. it('should not be emitted for an iopub signal', async () => {
  160. const kernel = await tester.start();
  161. // We'll send two messages, first an iopub message, then a shell message.
  162. // The unhandledMessage signal should only emit once for the shell message.
  163. const msgId = UUID.uuid4();
  164. const emission = testEmission(kernel.unhandledMessage, {
  165. test: (k, msg) => {
  166. expect(msg.header.msg_id).toBe(msgId);
  167. }
  168. });
  169. // Send an iopub message.
  170. tester.sendStatus(UUID.uuid4(), 'idle');
  171. // Send a shell message.
  172. const msg = KernelMessage.createMessage({
  173. msgType: 'kernel_info_request',
  174. channel: 'shell',
  175. session: tester.serverSessionId,
  176. msgId,
  177. content: {}
  178. });
  179. msg.parent_header = { session: kernel.clientId };
  180. tester.send(msg);
  181. await emission;
  182. });
  183. it('should not be emitted for a different client session', async () => {
  184. const kernel = await tester.start();
  185. // We'll send two messages, first a message with a different session, then
  186. // one with the current client session. The unhandledMessage signal should
  187. // only emit once for the current session message.
  188. const msgId = 'message from right session';
  189. const emission = testEmission(kernel.unhandledMessage, {
  190. test: (k, msg) => {
  191. expect((msg.parent_header as KernelMessage.IHeader).session).toBe(
  192. kernel.clientId
  193. );
  194. expect(msg.header.msg_id).toBe(msgId);
  195. }
  196. });
  197. // Send a shell message with the wrong client (parent) session.
  198. const msg1 = KernelMessage.createMessage({
  199. msgType: 'kernel_info_request',
  200. channel: 'shell',
  201. session: tester.serverSessionId,
  202. msgId: 'message from wrong session',
  203. content: {}
  204. });
  205. msg1.parent_header = { session: 'wrong session' };
  206. tester.send(msg1);
  207. // Send a shell message with the right client (parent) session.
  208. const msg2 = KernelMessage.createMessage({
  209. msgType: 'kernel_info_request',
  210. channel: 'shell',
  211. session: tester.serverSessionId,
  212. msgId: msgId,
  213. content: {}
  214. });
  215. msg2.parent_header = { session: kernel.clientId };
  216. tester.send(msg2);
  217. await emission;
  218. });
  219. });
  220. describe('#anyMessage', () => {
  221. let tester: KernelTester;
  222. beforeEach(() => {
  223. tester = new KernelTester();
  224. });
  225. afterEach(async () => {
  226. await tester.shutdown();
  227. tester.dispose();
  228. });
  229. it('should be emitted for an unhandled message', async () => {
  230. const kernel = await tester.start();
  231. const msgId = UUID.uuid4();
  232. const emission = testEmission(kernel.anyMessage, {
  233. test: (k, args) => {
  234. expect(args.msg.header.msg_id).toBe(msgId);
  235. expect(args.msg.header.msg_type).toBe('kernel_info_request');
  236. expect(args.direction).toBe('recv');
  237. }
  238. });
  239. const msg = KernelMessage.createMessage({
  240. msgType: 'kernel_info_request',
  241. channel: 'shell',
  242. session: tester.serverSessionId,
  243. msgId,
  244. content: {}
  245. });
  246. msg.parent_header = { session: kernel.clientId };
  247. tester.send(msg);
  248. await emission;
  249. });
  250. it('should be emitted for an iopub message', async () => {
  251. const kernel = await tester.start();
  252. const msgId = 'idle status';
  253. const emission = testEmission(kernel.anyMessage, {
  254. test: (k, args) => {
  255. expect((args.msg.header as any).msg_id).toBe(msgId);
  256. expect(args.direction).toBe('recv');
  257. }
  258. });
  259. tester.sendStatus(msgId, 'idle');
  260. await emission;
  261. });
  262. it('should be emitted for an stdin message', async () => {
  263. const kernel = await tester.start();
  264. const emission = testEmission(kernel.anyMessage, {
  265. test: (k, { msg, direction }) => {
  266. if (!KernelMessage.isInputReplyMsg(msg)) {
  267. throw new Error('Unexpected message');
  268. }
  269. if (msg.content.status !== 'ok') {
  270. throw new Error('Message has been changed');
  271. }
  272. expect(msg.content.value).toBe('foo');
  273. expect(direction).toBe('send');
  274. }
  275. });
  276. kernel.sendInputReply({ status: 'ok', value: 'foo' });
  277. await emission;
  278. });
  279. });
  280. describe('#id', () => {
  281. it('should be a string', () => {
  282. expect(typeof defaultKernel.id).toBe('string');
  283. });
  284. });
  285. describe('#name', () => {
  286. it('should be a string', () => {
  287. expect(typeof defaultKernel.name).toBe('string');
  288. });
  289. });
  290. describe('#username', () => {
  291. it('should be a string', () => {
  292. expect(typeof defaultKernel.username).toBe('string');
  293. });
  294. });
  295. describe('#serverSettings', () => {
  296. it('should be the server settings', () => {
  297. expect(defaultKernel.serverSettings.baseUrl).toBe(
  298. PageConfig.getBaseUrl()
  299. );
  300. });
  301. });
  302. describe('#clientId', () => {
  303. it('should be a string', () => {
  304. expect(typeof defaultKernel.clientId).toBe('string');
  305. });
  306. });
  307. describe('#status', () => {
  308. beforeEach(async () => {
  309. await defaultKernel.info;
  310. });
  311. it('should get an idle status', async () => {
  312. const emission = testEmission(defaultKernel.statusChanged, {
  313. find: () => defaultKernel.status === 'idle'
  314. });
  315. await defaultKernel.requestExecute({ code: 'a=1' }).done;
  316. await emission;
  317. });
  318. it('should get a restarting status', async () => {
  319. const kernel = await kernelManager.startNew();
  320. await kernel.info;
  321. const emission = testEmission(kernel.statusChanged, {
  322. find: () => kernel.status === 'restarting'
  323. });
  324. await kernel.requestKernelInfo();
  325. await kernel.restart();
  326. await emission;
  327. await kernel.requestKernelInfo();
  328. await kernel.shutdown();
  329. });
  330. it('should get a busy status', async () => {
  331. const emission = testEmission(defaultKernel.statusChanged, {
  332. find: () => defaultKernel.status === 'busy'
  333. });
  334. await defaultKernel.requestExecute({ code: 'a=1' }, true).done;
  335. await emission;
  336. });
  337. it('should get an unknown status while disconnected', async () => {
  338. const tester = new KernelTester();
  339. const kernel = await tester.start();
  340. const emission = testEmission(kernel.statusChanged, {
  341. find: () => kernel.status === 'unknown'
  342. });
  343. await tester.close();
  344. await emission;
  345. tester.dispose();
  346. });
  347. it('should get a dead status', async () => {
  348. const tester = new KernelTester();
  349. const kernel = await tester.start();
  350. await kernel.info;
  351. const dead = testEmission(kernel.statusChanged, {
  352. find: () => kernel.status === 'dead'
  353. });
  354. tester.sendStatus(UUID.uuid4(), 'dead');
  355. await dead;
  356. tester.dispose();
  357. });
  358. });
  359. describe('#info', () => {
  360. it('should get the kernel info', async () => {
  361. const name = (await defaultKernel.info).language_info.name;
  362. const defaultSpecs = specs.kernelspecs[specs.default]!;
  363. expect(name).toBe(defaultSpecs.language);
  364. });
  365. });
  366. describe('#spec', () => {
  367. it('should resolve with the spec', async () => {
  368. const spec = await defaultKernel.spec;
  369. expect(spec!.name).toBe(specs.default);
  370. });
  371. });
  372. describe('#isDisposed', () => {
  373. it('should be true after we dispose of the kernel', async () => {
  374. const kernel = defaultKernel.clone();
  375. expect(kernel.isDisposed).toBe(false);
  376. kernel.dispose();
  377. expect(kernel.isDisposed).toBe(true);
  378. });
  379. it('should be safe to call multiple times', async () => {
  380. const kernel = defaultKernel.clone();
  381. expect(kernel.isDisposed).toBe(false);
  382. expect(kernel.isDisposed).toBe(false);
  383. kernel.dispose();
  384. expect(kernel.isDisposed).toBe(true);
  385. expect(kernel.isDisposed).toBe(true);
  386. });
  387. });
  388. describe('#dispose()', () => {
  389. it('should dispose of the resources held by the kernel', async () => {
  390. const kernel = defaultKernel.clone();
  391. const future = kernel.requestExecute({ code: 'foo' });
  392. expect(future.isDisposed).toBe(false);
  393. kernel.dispose();
  394. expect(future.isDisposed).toBe(true);
  395. });
  396. it('should be safe to call twice', async () => {
  397. const kernel = defaultKernel.clone();
  398. const future = kernel.requestExecute({ code: 'foo' });
  399. expect(future.isDisposed).toBe(false);
  400. kernel.dispose();
  401. expect(future.isDisposed).toBe(true);
  402. expect(kernel.isDisposed).toBe(true);
  403. kernel.dispose();
  404. expect(future.isDisposed).toBe(true);
  405. expect(kernel.isDisposed).toBe(true);
  406. });
  407. });
  408. describe('#sendShellMessage()', () => {
  409. let tester: KernelTester;
  410. let kernel: Kernel.IKernelConnection;
  411. beforeEach(async () => {
  412. tester = new KernelTester();
  413. kernel = await tester.start();
  414. });
  415. afterEach(async () => {
  416. await tester.shutdown();
  417. tester.dispose();
  418. });
  419. it('should send a message to the kernel', async () => {
  420. const done = new PromiseDelegate<void>();
  421. const msgId = UUID.uuid4();
  422. tester.onMessage(msg => {
  423. try {
  424. expect(msg.header.msg_id).toBe(msgId);
  425. } catch (e) {
  426. done.reject(e);
  427. throw e;
  428. }
  429. done.resolve();
  430. });
  431. const msg = KernelMessage.createMessage({
  432. msgType: 'comm_info_request',
  433. channel: 'shell',
  434. username: kernel.username,
  435. session: kernel.clientId,
  436. msgId,
  437. content: {}
  438. });
  439. kernel.sendShellMessage(msg, true);
  440. await done.promise;
  441. });
  442. it('should send a binary message', async () => {
  443. const done = new PromiseDelegate<void>();
  444. const msgId = UUID.uuid4();
  445. tester.onMessage(msg => {
  446. try {
  447. const decoder = new TextDecoder('utf8');
  448. const item = msg.buffers![0] as DataView;
  449. expect(decoder.decode(item)).toBe('hello');
  450. } catch (e) {
  451. done.reject(e);
  452. throw e;
  453. }
  454. done.resolve();
  455. });
  456. const encoder = new TextEncoder();
  457. const data = encoder.encode('hello');
  458. const msg = KernelMessage.createMessage({
  459. msgType: 'comm_info_request',
  460. channel: 'shell',
  461. username: kernel.username,
  462. session: kernel.clientId,
  463. msgId,
  464. content: {},
  465. buffers: [data, data.buffer]
  466. });
  467. kernel.sendShellMessage(msg, true);
  468. await done.promise;
  469. });
  470. it('should fail if the kernel is dead', async () => {
  471. // Create a promise that resolves when the kernel's status changes to dead
  472. const dead = testEmission(kernel.statusChanged, {
  473. find: () => kernel.status === 'dead'
  474. });
  475. tester.sendStatus(UUID.uuid4(), 'dead');
  476. await dead;
  477. expect(kernel.status).toBe('dead');
  478. const msg = KernelMessage.createMessage({
  479. msgType: 'kernel_info_request',
  480. channel: 'shell',
  481. username: kernel.username,
  482. session: kernel.clientId,
  483. content: {}
  484. });
  485. expect(() => {
  486. kernel.sendShellMessage(msg, true);
  487. }).toThrowError(/Kernel is dead/);
  488. });
  489. it('should handle out of order messages', async () => {
  490. // This test that a future.done promise resolves when a status idle and
  491. // reply come through, even if the status comes first.
  492. const msg = KernelMessage.createMessage({
  493. msgType: 'kernel_info_request',
  494. channel: 'shell',
  495. username: kernel.username,
  496. session: kernel.clientId,
  497. content: {}
  498. });
  499. const future = kernel.sendShellMessage(msg, true);
  500. tester.onMessage(msg => {
  501. // trigger onDone
  502. tester.send(
  503. KernelMessage.createMessage({
  504. msgType: 'status',
  505. channel: 'iopub',
  506. username: kernel.username,
  507. session: kernel.clientId,
  508. content: { execution_state: 'idle' },
  509. parentHeader: msg.header
  510. })
  511. );
  512. future.onIOPub = () => {
  513. tester.send(
  514. KernelMessage.createMessage({
  515. msgType: 'comm_open',
  516. channel: 'shell',
  517. username: kernel.username,
  518. session: kernel.clientId,
  519. content: {
  520. comm_id: 'abcd',
  521. target_name: 'target',
  522. data: {}
  523. },
  524. parentHeader: msg.header
  525. })
  526. );
  527. };
  528. });
  529. await future.done;
  530. });
  531. });
  532. describe('#interrupt()', () => {
  533. it('should interrupt and resolve with a valid server response', async () => {
  534. const kernel = await kernelManager.startNew();
  535. await kernel.interrupt();
  536. await kernel.shutdown();
  537. });
  538. it('should throw an error for an invalid response', async () => {
  539. handleRequest(defaultKernel, 200, {
  540. id: defaultKernel.id,
  541. name: defaultKernel.name
  542. });
  543. const interrupt = defaultKernel.interrupt();
  544. await expectFailure(interrupt, 'Invalid response: 200 OK');
  545. });
  546. it('should throw an error for an error response', async () => {
  547. handleRequest(defaultKernel, 500, {});
  548. const interrupt = defaultKernel.interrupt();
  549. await expectFailure(interrupt, '');
  550. });
  551. it('should fail if the kernel is dead', async () => {
  552. const tester = new KernelTester();
  553. const kernel = await tester.start();
  554. // Create a promise that resolves when the kernel's status changes to dead
  555. const dead = testEmission(kernel.statusChanged, {
  556. find: () => kernel.status === 'dead'
  557. });
  558. tester.sendStatus(UUID.uuid4(), 'dead');
  559. await dead;
  560. await expectFailure(kernel.interrupt(), 'Kernel is dead');
  561. tester.dispose();
  562. });
  563. });
  564. describe('#restart()', () => {
  565. beforeEach(async () => {
  566. await defaultKernel.requestKernelInfo();
  567. });
  568. it('should restart and resolve with a valid server response', async () => {
  569. const kernel = await kernelManager.startNew();
  570. await kernel.info;
  571. await kernel.requestKernelInfo();
  572. await kernel.restart();
  573. await kernel.requestKernelInfo();
  574. await kernel.shutdown();
  575. });
  576. it('should fail if the kernel does not restart', async () => {
  577. handleRequest(defaultKernel, 500, {});
  578. const restart = defaultKernel.restart();
  579. await expectFailure(restart, '');
  580. });
  581. it('should throw an error for an invalid response', async () => {
  582. const { id, name } = defaultKernel;
  583. handleRequest(defaultKernel, 205, { id, name });
  584. await expectFailure(
  585. defaultKernel.restart(),
  586. 'Invalid response: 205 Reset Content'
  587. );
  588. });
  589. it('should throw an error for an error response', async () => {
  590. handleRequest(defaultKernel, 500, {});
  591. const restart = defaultKernel.restart();
  592. await expectFailure(restart);
  593. });
  594. it('should throw an error for an invalid id', async () => {
  595. handleRequest(defaultKernel, 200, {});
  596. const restart = defaultKernel.restart();
  597. await expectFailure(restart);
  598. });
  599. it('should dispose of existing comm and future objects', async () => {
  600. const kernel = await kernelManager.startNew();
  601. await kernel.info;
  602. await kernel.requestKernelInfo();
  603. const comm = kernel.createComm('test');
  604. const future = kernel.requestExecute({ code: 'foo' });
  605. await kernel.restart();
  606. await kernel.requestKernelInfo();
  607. expect(future.isDisposed).toBe(true);
  608. expect(comm.isDisposed).toBe(true);
  609. await kernel.shutdown();
  610. });
  611. });
  612. describe('#reconnect()', () => {
  613. it('should create a new websocket and resolve the returned promise', async () => {
  614. const oldWS = (defaultKernel as any)._ws;
  615. await defaultKernel.reconnect();
  616. expect((defaultKernel as any)._ws).not.toBe(oldWS);
  617. });
  618. it('should emit `"connecting"`, then `"connected"` status', async () => {
  619. const emission = testEmission(defaultKernel.connectionStatusChanged, {
  620. find: () => defaultKernel.connectionStatus === 'connecting',
  621. test: async () => {
  622. await testEmission(defaultKernel.connectionStatusChanged, {
  623. find: () => defaultKernel.connectionStatus === 'connected'
  624. });
  625. }
  626. });
  627. await defaultKernel.reconnect();
  628. await emission;
  629. });
  630. it('return promise should reject if the kernel is disposed or disconnected', async () => {
  631. const connection = defaultKernel.reconnect();
  632. defaultKernel.dispose();
  633. try {
  634. await connection;
  635. // If the connection did not reject, so test fails.
  636. throw new Error('Reconnection promise did not reject');
  637. } catch (e) {
  638. /* Connection promise reject - test passes */
  639. }
  640. });
  641. });
  642. describe('#shutdown()', () => {
  643. it('should shut down and resolve with a valid server response', async () => {
  644. const kernel = await kernelManager.startNew();
  645. await kernel.shutdown();
  646. });
  647. it('should throw an error for an invalid response', async () => {
  648. handleRequest(defaultKernel, 200, {
  649. id: UUID.uuid4(),
  650. name: 'foo'
  651. });
  652. const shutdown = defaultKernel.shutdown();
  653. await expectFailure(shutdown, 'Invalid response: 200 OK');
  654. });
  655. it('should handle a 404 error', async () => {
  656. const kernel = await kernelManager.startNew();
  657. handleRequest(kernel, 404, {});
  658. await kernel.shutdown();
  659. });
  660. it('should throw an error for an error response', async () => {
  661. handleRequest(defaultKernel, 500, {});
  662. const shutdown = defaultKernel.shutdown();
  663. await expectFailure(shutdown, '');
  664. });
  665. it('should still pass if the kernel is dead', async () => {
  666. const tester = new KernelTester();
  667. const kernel = await tester.start();
  668. // Create a promise that resolves when the kernel's status changes to dead
  669. const dead = testEmission(kernel.statusChanged, {
  670. find: () => kernel.status === 'dead'
  671. });
  672. tester.sendStatus(UUID.uuid4(), 'dead');
  673. await dead;
  674. await kernel.shutdown();
  675. tester.dispose();
  676. });
  677. });
  678. describe('#requestKernelInfo()', () => {
  679. it('should resolve the promise', async () => {
  680. const msg = (await defaultKernel.requestKernelInfo())!;
  681. if (msg.content.status !== 'ok') {
  682. throw new Error('Message error');
  683. }
  684. const name = msg.content.language_info.name;
  685. expect(name).toBeTruthy();
  686. });
  687. });
  688. describe('#requestComplete()', () => {
  689. it('should resolve the promise', async () => {
  690. const options: KernelMessage.ICompleteRequestMsg['content'] = {
  691. code: 'hello',
  692. cursor_pos: 4
  693. };
  694. await defaultKernel.requestComplete(options);
  695. });
  696. it('should reject the promise if the kernel is dead', async () => {
  697. const options: KernelMessage.ICompleteRequestMsg['content'] = {
  698. code: 'hello',
  699. cursor_pos: 4
  700. };
  701. const tester = new KernelTester();
  702. const kernel = await tester.start();
  703. // Create a promise that resolves when the kernel's status changes to dead
  704. const dead = testEmission(kernel.statusChanged, {
  705. find: () => kernel.status === 'dead'
  706. });
  707. tester.sendStatus(UUID.uuid4(), 'dead');
  708. await dead;
  709. await expectFailure(kernel.requestComplete(options), 'Kernel is dead');
  710. tester.dispose();
  711. });
  712. });
  713. describe('#requestInspect()', () => {
  714. it('should resolve the promise', async () => {
  715. const options: KernelMessage.IInspectRequestMsg['content'] = {
  716. code: 'hello',
  717. cursor_pos: 4,
  718. detail_level: 0
  719. };
  720. await defaultKernel.requestInspect(options);
  721. });
  722. });
  723. describe('#requestIsComplete()', () => {
  724. it('should resolve the promise', async () => {
  725. const options: KernelMessage.IIsCompleteRequestMsg['content'] = {
  726. code: 'hello'
  727. };
  728. await defaultKernel.requestIsComplete(options);
  729. });
  730. });
  731. describe('#requestHistory()', () => {
  732. it('range messages should resolve the promise', async () => {
  733. const options: KernelMessage.IHistoryRequestMsg['content'] = {
  734. output: true,
  735. raw: true,
  736. hist_access_type: 'range',
  737. session: 0,
  738. start: 1,
  739. stop: 2
  740. };
  741. await defaultKernel.requestHistory(options);
  742. });
  743. it('tail messages should resolve the promise', async () => {
  744. const options: KernelMessage.IHistoryRequestMsg['content'] = {
  745. output: true,
  746. raw: true,
  747. hist_access_type: 'tail',
  748. n: 1
  749. };
  750. await defaultKernel.requestHistory(options);
  751. });
  752. it('search messages should resolve the promise', async () => {
  753. const options: KernelMessage.IHistoryRequestMsg['content'] = {
  754. output: true,
  755. raw: true,
  756. hist_access_type: 'search',
  757. n: 1,
  758. pattern: '*',
  759. unique: true
  760. };
  761. await defaultKernel.requestHistory(options);
  762. });
  763. });
  764. describe('#sendInputReply()', () => {
  765. it('should send an input_reply message', async () => {
  766. const tester = new KernelTester();
  767. const kernel = await tester.start();
  768. const done = new PromiseDelegate<void>();
  769. tester.onMessage(msg => {
  770. expect(msg.header.msg_type).toBe('input_reply');
  771. done.resolve(undefined);
  772. });
  773. kernel.sendInputReply({ status: 'ok', value: 'test' });
  774. await done.promise;
  775. await tester.shutdown();
  776. tester.dispose();
  777. });
  778. it('should fail if the kernel is dead', async () => {
  779. const tester = new KernelTester();
  780. const kernel = await tester.start();
  781. // Create a promise that resolves when the kernel's status changes to dead
  782. const dead = testEmission(kernel.statusChanged, {
  783. find: () => kernel.status === 'dead'
  784. });
  785. tester.sendStatus(UUID.uuid4(), 'dead');
  786. await dead;
  787. expect(() => {
  788. kernel.sendInputReply({ status: 'ok', value: 'test' });
  789. }).toThrowError(/Kernel is dead/);
  790. tester.dispose();
  791. });
  792. });
  793. describe('#requestExecute()', () => {
  794. it('should send and handle incoming messages', async () => {
  795. const content: KernelMessage.IExecuteRequestMsg['content'] = {
  796. code: 'test',
  797. silent: false,
  798. store_history: true,
  799. user_expressions: {},
  800. allow_stdin: false,
  801. stop_on_error: false
  802. };
  803. const options = {
  804. username: defaultKernel.username,
  805. session: defaultKernel.clientId
  806. };
  807. let future: Kernel.IShellFuture;
  808. const tester = new KernelTester();
  809. tester.onMessage(msg => {
  810. expect(msg.channel).toBe('shell');
  811. // send a reply
  812. tester.send(
  813. KernelMessage.createMessage<KernelMessage.IExecuteReplyMsg>({
  814. ...options,
  815. msgType: 'execute_reply',
  816. channel: 'shell',
  817. content: {
  818. execution_count: 1,
  819. status: 'ok',
  820. user_expressions: {}
  821. },
  822. parentHeader: msg.header as KernelMessage.IExecuteRequestMsg['header']
  823. })
  824. );
  825. future.onReply = () => {
  826. // trigger onStdin
  827. tester.send(
  828. KernelMessage.createMessage({
  829. ...options,
  830. channel: 'stdin',
  831. msgType: 'input_request',
  832. content: {
  833. prompt: 'prompt',
  834. password: false
  835. },
  836. parentHeader: msg.header
  837. })
  838. );
  839. };
  840. future.onStdin = () => {
  841. // trigger onIOPub with a 'stream' message
  842. tester.send(
  843. KernelMessage.createMessage<KernelMessage.IStreamMsg>({
  844. ...options,
  845. channel: 'iopub',
  846. msgType: 'stream',
  847. content: { name: 'stdout', text: '' },
  848. parentHeader: msg.header
  849. })
  850. );
  851. };
  852. future.onIOPub = ioMsg => {
  853. if (ioMsg.header.msg_type === 'stream') {
  854. // trigger onDone
  855. tester.send(
  856. KernelMessage.createMessage<KernelMessage.IStatusMsg>({
  857. ...options,
  858. channel: 'iopub',
  859. msgType: 'status',
  860. content: {
  861. execution_state: 'idle'
  862. },
  863. parentHeader: msg.header
  864. })
  865. );
  866. }
  867. };
  868. });
  869. const kernel = await tester.start();
  870. future = kernel.requestExecute(content);
  871. await future.done;
  872. expect(future.isDisposed).toBe(true);
  873. await tester.shutdown();
  874. tester.dispose();
  875. });
  876. it('should not dispose of KernelFuture when disposeOnDone=false', async () => {
  877. const options: KernelMessage.IExecuteRequestMsg['content'] = {
  878. code: 'test',
  879. silent: false,
  880. store_history: true,
  881. user_expressions: {},
  882. allow_stdin: false,
  883. stop_on_error: false
  884. };
  885. const future = defaultKernel.requestExecute(options, false);
  886. await future.done;
  887. expect(future.isDisposed).toBe(false);
  888. future.dispose();
  889. expect(future.isDisposed).toBe(true);
  890. });
  891. });
  892. describe('#checkExecuteMetadata()', () => {
  893. it('should accept cell metadata as part of request', async () => {
  894. const options: KernelMessage.IExecuteRequestMsg['content'] = {
  895. code: 'test',
  896. silent: false,
  897. store_history: true,
  898. user_expressions: {},
  899. allow_stdin: false,
  900. stop_on_error: false
  901. };
  902. const metadata = { cellId: 'test' };
  903. const future = defaultKernel.requestExecute(options, false, metadata);
  904. await future.done;
  905. expect(future.msg.metadata).toEqual(metadata);
  906. });
  907. });
  908. describe('#registerMessageHook()', () => {
  909. it('should have the most recently registered hook run first', async () => {
  910. const options: KernelMessage.IExecuteRequestMsg['content'] = {
  911. code: 'test',
  912. silent: false,
  913. store_history: true,
  914. user_expressions: {},
  915. allow_stdin: false,
  916. stop_on_error: false
  917. };
  918. const calls: string[] = [];
  919. let future: Kernel.IShellFuture;
  920. let kernel: Kernel.IKernelConnection;
  921. const tester = new KernelTester();
  922. tester.onMessage(message => {
  923. // send a reply
  924. const parentHeader = message.header;
  925. const session = 'session';
  926. tester.send(
  927. KernelMessage.createMessage({
  928. parentHeader,
  929. session,
  930. channel: 'shell',
  931. msgType: 'comm_open',
  932. content: { comm_id: 'B', data: {}, target_name: 'C' }
  933. })
  934. );
  935. future.onReply = () => {
  936. // trigger onIOPub with a 'stream' message
  937. tester.send(
  938. KernelMessage.createMessage({
  939. parentHeader,
  940. session,
  941. channel: 'iopub',
  942. msgType: 'stream',
  943. content: { name: 'stdout', text: 'foo' }
  944. })
  945. );
  946. // trigger onDone
  947. tester.send(
  948. KernelMessage.createMessage({
  949. parentHeader,
  950. session,
  951. channel: 'iopub',
  952. msgType: 'status',
  953. content: { execution_state: 'idle' }
  954. })
  955. );
  956. };
  957. kernel.registerMessageHook(parentHeader.msg_id, async msg => {
  958. // Make this hook call asynchronous
  959. // tslint:disable-next-line:await-promise
  960. await calls.push('last');
  961. return true;
  962. });
  963. kernel.registerMessageHook(parentHeader.msg_id, msg => {
  964. calls.push('first');
  965. // not returning should also continue handling
  966. return void 0 as any;
  967. });
  968. future.onIOPub = () => {
  969. calls.push('iopub');
  970. };
  971. });
  972. kernel = await tester.start();
  973. future = kernel.requestExecute(options, false);
  974. await future.done;
  975. // the last hook was called for the stream and the status message.
  976. expect(calls).toEqual([
  977. 'first',
  978. 'last',
  979. 'iopub',
  980. 'first',
  981. 'last',
  982. 'iopub'
  983. ]);
  984. await tester.shutdown();
  985. tester.dispose();
  986. });
  987. it('should abort processing if a hook returns false, but the done logic should still work', async () => {
  988. const options: KernelMessage.IExecuteRequestMsg['content'] = {
  989. code: 'test',
  990. silent: false,
  991. store_history: true,
  992. user_expressions: {},
  993. allow_stdin: false,
  994. stop_on_error: false
  995. };
  996. const calls: string[] = [];
  997. const tester = new KernelTester();
  998. let future: Kernel.IShellFuture;
  999. let kernel: Kernel.IKernelConnection;
  1000. tester.onMessage(message => {
  1001. // send a reply
  1002. const parentHeader = message.header;
  1003. const session = 'session';
  1004. tester.send(
  1005. KernelMessage.createMessage({
  1006. parentHeader,
  1007. session,
  1008. channel: 'shell',
  1009. msgType: 'comm_open',
  1010. content: { comm_id: 'B', data: {}, target_name: 'C' }
  1011. })
  1012. );
  1013. future.onReply = () => {
  1014. // trigger onIOPub with a 'stream' message
  1015. tester.send(
  1016. KernelMessage.createMessage({
  1017. parentHeader,
  1018. session,
  1019. channel: 'iopub',
  1020. msgType: 'stream',
  1021. content: { name: 'stdout', text: 'foo' }
  1022. })
  1023. );
  1024. // trigger onDone
  1025. tester.send(
  1026. KernelMessage.createMessage({
  1027. parentHeader,
  1028. session,
  1029. channel: 'iopub',
  1030. msgType: 'status',
  1031. content: { execution_state: 'idle' }
  1032. })
  1033. );
  1034. };
  1035. kernel.registerMessageHook(parentHeader.msg_id, msg => {
  1036. calls.push('last');
  1037. return true;
  1038. });
  1039. kernel.registerMessageHook(parentHeader.msg_id, msg => {
  1040. calls.push('first');
  1041. return false;
  1042. });
  1043. future.onIOPub = async () => {
  1044. // tslint:disable-next-line:await-promise
  1045. await calls.push('iopub');
  1046. };
  1047. });
  1048. kernel = await tester.start();
  1049. future = kernel.requestExecute(options, false);
  1050. await future.done;
  1051. // the last hook was called for the stream and the status message.
  1052. expect(calls).toEqual(['first', 'first']);
  1053. await tester.shutdown();
  1054. tester.dispose();
  1055. });
  1056. it('should process additions on the next run', async () => {
  1057. const options: KernelMessage.IExecuteRequestMsg['content'] = {
  1058. code: 'test',
  1059. silent: false,
  1060. store_history: true,
  1061. user_expressions: {},
  1062. allow_stdin: false,
  1063. stop_on_error: false
  1064. };
  1065. const calls: string[] = [];
  1066. const tester = new KernelTester();
  1067. let future: Kernel.IShellFuture;
  1068. let kernel: Kernel.IKernelConnection;
  1069. tester.onMessage(message => {
  1070. // send a reply
  1071. const parentHeader = message.header;
  1072. const session = 'session';
  1073. tester.send(
  1074. KernelMessage.createMessage({
  1075. parentHeader,
  1076. session,
  1077. channel: 'shell',
  1078. msgType: 'comm_open',
  1079. content: { comm_id: 'B', data: {}, target_name: 'C' }
  1080. })
  1081. );
  1082. future.onReply = () => {
  1083. // trigger onIOPub with a 'stream' message
  1084. tester.send(
  1085. KernelMessage.createMessage({
  1086. parentHeader,
  1087. session,
  1088. channel: 'iopub',
  1089. msgType: 'stream',
  1090. content: { name: 'stdout', text: 'foo' }
  1091. })
  1092. );
  1093. // trigger onDone
  1094. tester.send(
  1095. KernelMessage.createMessage({
  1096. parentHeader,
  1097. session,
  1098. channel: 'iopub',
  1099. msgType: 'status',
  1100. content: { execution_state: 'idle' }
  1101. })
  1102. );
  1103. };
  1104. kernel.registerMessageHook(parentHeader.msg_id, msg => {
  1105. calls.push('last');
  1106. kernel.registerMessageHook(parentHeader.msg_id, msg => {
  1107. calls.push('first');
  1108. return true;
  1109. });
  1110. return true;
  1111. });
  1112. future.onIOPub = () => {
  1113. calls.push('iopub');
  1114. };
  1115. });
  1116. kernel = await tester.start();
  1117. future = kernel.requestExecute(options, false);
  1118. await future.done;
  1119. expect(calls).toEqual(['last', 'iopub', 'first', 'last', 'iopub']);
  1120. await tester.shutdown();
  1121. tester.dispose();
  1122. });
  1123. it('should deactivate a hook immediately on removal', async () => {
  1124. const options: KernelMessage.IExecuteRequestMsg['content'] = {
  1125. code: 'test',
  1126. silent: false,
  1127. store_history: true,
  1128. user_expressions: {},
  1129. allow_stdin: false,
  1130. stop_on_error: false
  1131. };
  1132. const calls: string[] = [];
  1133. const tester = new KernelTester();
  1134. let future: Kernel.IShellFuture;
  1135. let kernel: Kernel.IKernelConnection;
  1136. tester.onMessage(message => {
  1137. // send a reply
  1138. const parentHeader = message.header;
  1139. const session = 'session';
  1140. tester.send(
  1141. KernelMessage.createMessage({
  1142. parentHeader,
  1143. session,
  1144. channel: 'shell',
  1145. msgType: 'comm_open',
  1146. content: { comm_id: 'B', data: {}, target_name: 'C' }
  1147. })
  1148. );
  1149. future.onReply = () => {
  1150. // trigger onIOPub with a 'stream' message
  1151. tester.send(
  1152. KernelMessage.createMessage({
  1153. parentHeader,
  1154. session,
  1155. channel: 'iopub',
  1156. msgType: 'stream',
  1157. content: { name: 'stdout', text: 'foo' }
  1158. })
  1159. );
  1160. // trigger onDone
  1161. tester.send(
  1162. KernelMessage.createMessage({
  1163. parentHeader,
  1164. session,
  1165. channel: 'iopub',
  1166. msgType: 'status',
  1167. content: { execution_state: 'idle' }
  1168. })
  1169. );
  1170. };
  1171. const toDelete = (msg: KernelMessage.IIOPubMessage) => {
  1172. calls.push('delete');
  1173. return true;
  1174. };
  1175. kernel.registerMessageHook(parentHeader.msg_id, toDelete);
  1176. kernel.registerMessageHook(parentHeader.msg_id, msg => {
  1177. if (calls.length > 0) {
  1178. // delete the hook the second time around
  1179. kernel.removeMessageHook(parentHeader.msg_id, toDelete);
  1180. }
  1181. calls.push('first');
  1182. return true;
  1183. });
  1184. future.onIOPub = () => {
  1185. calls.push('iopub');
  1186. };
  1187. });
  1188. kernel = await tester.start();
  1189. future = kernel.requestExecute(options, false);
  1190. await future.done;
  1191. expect(calls).toEqual(['first', 'delete', 'iopub', 'first', 'iopub']);
  1192. await tester.shutdown();
  1193. tester.dispose();
  1194. });
  1195. });
  1196. describe('handles messages asynchronously', () => {
  1197. // TODO: Also check that messages are canceled appropriately. In particular, when
  1198. // a kernel is restarted, then a message is sent for a comm open from the
  1199. // old session, the comm open should be canceled.
  1200. it('should run handlers in order', async () => {
  1201. const options: KernelMessage.IExecuteRequestMsg['content'] = {
  1202. code: 'test',
  1203. silent: false,
  1204. store_history: true,
  1205. user_expressions: {},
  1206. allow_stdin: true,
  1207. stop_on_error: false
  1208. };
  1209. const tester = new KernelTester();
  1210. const kernel = await tester.start();
  1211. const future = kernel.requestExecute(options, false);
  1212. // The list of emissions from the anyMessage signal.
  1213. const msgSignal: string[][] = [];
  1214. const msgSignalExpected: string[][] = [];
  1215. // The list of message processing calls
  1216. const calls: string[][] = [];
  1217. const callsExpected: string[][] = [];
  1218. function pushIopub(msgId: string) {
  1219. callsExpected.push([msgId, 'future hook a']);
  1220. callsExpected.push([msgId, 'future hook b']);
  1221. callsExpected.push([msgId, 'kernel hook a']);
  1222. callsExpected.push([msgId, 'kernel hook b']);
  1223. callsExpected.push([msgId, 'iopub']);
  1224. msgSignalExpected.push([msgId, 'iopub']);
  1225. }
  1226. function pushCommOpen(msgId: string) {
  1227. pushIopub(msgId);
  1228. callsExpected.push([msgId, 'comm open']);
  1229. }
  1230. function pushCommMsg(msgId: string) {
  1231. pushIopub(msgId);
  1232. callsExpected.push([msgId, 'comm msg']);
  1233. }
  1234. function pushCommClose(msgId: string) {
  1235. pushIopub(msgId);
  1236. callsExpected.push([msgId, 'comm close']);
  1237. }
  1238. function pushStdin(msgId: string) {
  1239. callsExpected.push([msgId, 'stdin']);
  1240. msgSignalExpected.push([msgId, 'stdin']);
  1241. }
  1242. function pushReply(msgId: string) {
  1243. callsExpected.push([msgId, 'reply']);
  1244. msgSignalExpected.push([msgId, 'shell']);
  1245. }
  1246. const anyMessageDone = new PromiseDelegate();
  1247. const handlingBlock = new PromiseDelegate();
  1248. tester.onMessage(message => {
  1249. tester.onMessage(() => {
  1250. return;
  1251. });
  1252. tester.parentHeader = message.header;
  1253. pushIopub(tester.sendStatus('busy', 'busy'));
  1254. pushIopub(tester.sendStream('stdout', { name: 'stdout', text: 'foo' }));
  1255. pushCommOpen(
  1256. tester.sendCommOpen('comm open', {
  1257. target_name: 'commtarget',
  1258. comm_id: 'commid',
  1259. data: {}
  1260. })
  1261. );
  1262. pushIopub(
  1263. tester.sendDisplayData('display 1', { data: {}, metadata: {} })
  1264. );
  1265. pushCommMsg(
  1266. tester.sendCommMsg('comm 1', { comm_id: 'commid', data: {} })
  1267. );
  1268. pushCommMsg(
  1269. tester.sendCommMsg('comm 2', { comm_id: 'commid', data: {} })
  1270. );
  1271. pushCommClose(
  1272. tester.sendCommClose('comm close', { comm_id: 'commid', data: {} })
  1273. );
  1274. pushStdin(
  1275. tester.sendInputRequest('stdin', { prompt: '', password: false })
  1276. );
  1277. pushIopub(
  1278. tester.sendDisplayData('display 2', {
  1279. data: {},
  1280. metadata: {},
  1281. transient: { display_id: 'displayid' }
  1282. })
  1283. );
  1284. pushIopub(
  1285. tester.sendUpdateDisplayData('update display', {
  1286. data: {},
  1287. metadata: {},
  1288. transient: { display_id: 'displayid' }
  1289. })
  1290. );
  1291. pushIopub(
  1292. tester.sendExecuteResult('execute result', {
  1293. execution_count: 1,
  1294. data: {},
  1295. metadata: {}
  1296. })
  1297. );
  1298. pushIopub(tester.sendStatus('idle', 'idle'));
  1299. pushReply(
  1300. tester.sendExecuteReply('execute reply', {
  1301. status: 'ok',
  1302. execution_count: 1,
  1303. user_expressions: {}
  1304. })
  1305. );
  1306. tester.parentHeader = undefined;
  1307. });
  1308. kernel.anyMessage.connect((k, args) => {
  1309. msgSignal.push([args.msg.header.msg_id, args.msg.channel]);
  1310. if (args.msg.header.msg_id === 'execute reply') {
  1311. anyMessageDone.resolve(undefined);
  1312. }
  1313. });
  1314. kernel.registerMessageHook(future.msg.header.msg_id, async msg => {
  1315. // Make this hook call asynchronous
  1316. // tslint:disable-next-line:await-promise
  1317. await calls.push([msg.header.msg_id, 'kernel hook b']);
  1318. return true;
  1319. });
  1320. kernel.registerMessageHook(future.msg.header.msg_id, async msg => {
  1321. calls.push([msg.header.msg_id, 'kernel hook a']);
  1322. return true;
  1323. });
  1324. kernel.registerCommTarget('commtarget', async (comm, msg) => {
  1325. // tslint:disable-next-line:await-promise
  1326. await calls.push([msg.header.msg_id, 'comm open']);
  1327. comm.onMsg = async msg => {
  1328. // tslint:disable-next-line:await-promise
  1329. await calls.push([msg.header.msg_id, 'comm msg']);
  1330. };
  1331. comm.onClose = async msg => {
  1332. // tslint:disable-next-line:await-promise
  1333. await calls.push([msg.header.msg_id, 'comm close']);
  1334. };
  1335. });
  1336. future.registerMessageHook(async msg => {
  1337. // tslint:disable-next-line:await-promise
  1338. await calls.push([msg.header.msg_id, 'future hook b']);
  1339. return true;
  1340. });
  1341. future.registerMessageHook(async msg => {
  1342. // Delay processing until after we've checked the anyMessage results.
  1343. await handlingBlock.promise;
  1344. // tslint:disable-next-line:await-promise
  1345. await calls.push([msg.header.msg_id, 'future hook a']);
  1346. return true;
  1347. });
  1348. future.onIOPub = async msg => {
  1349. // tslint:disable-next-line:await-promise
  1350. await calls.push([msg.header.msg_id, 'iopub']);
  1351. };
  1352. future.onStdin = async msg => {
  1353. // tslint:disable-next-line:await-promise
  1354. await calls.push([msg.header.msg_id, 'stdin']);
  1355. };
  1356. future.onReply = async msg => {
  1357. // tslint:disable-next-line:await-promise
  1358. await calls.push([msg.header.msg_id, 'reply']);
  1359. };
  1360. // Give the kernel time to receive and queue up the messages.
  1361. await anyMessageDone.promise;
  1362. // At this point, the synchronous anyMessage signal should have been
  1363. // emitted for every message, but no actual message handling should have
  1364. // happened.
  1365. expect(msgSignal).toEqual(msgSignalExpected);
  1366. expect(calls).toEqual([]);
  1367. // Release the lock on message processing.
  1368. handlingBlock.resolve(undefined);
  1369. await future.done;
  1370. expect(calls).toEqual(callsExpected);
  1371. await tester.shutdown();
  1372. tester.dispose();
  1373. });
  1374. });
  1375. });