clientsession.spec.ts 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  1. // Copyright (c) Jupyter Development Team.
  2. // Distributed under the terms of the Modified BSD License.
  3. import { expect } from 'chai';
  4. import { SessionManager } from '@jupyterlab/services';
  5. import { ClientSession, IClientSession } from '@jupyterlab/apputils';
  6. import { UUID } from '@phosphor/coreutils';
  7. import { acceptDialog, dismissDialog } from '@jupyterlab/testutils';
  8. describe('@jupyterlab/apputils', () => {
  9. describe('ClientSession', () => {
  10. const manager = new SessionManager();
  11. let session: ClientSession;
  12. before(() => manager.ready);
  13. beforeEach(() => {
  14. session = new ClientSession({
  15. manager,
  16. kernelPreference: { name: manager.specs.default }
  17. });
  18. });
  19. afterEach(async () => {
  20. await session.shutdown();
  21. session.dispose();
  22. });
  23. describe('#constructor()', () => {
  24. it('should create a client session', () => {
  25. expect(session).to.be.an.instanceof(ClientSession);
  26. });
  27. });
  28. describe('#terminated', () => {
  29. it('should be emitted when the session is terminated', async () => {
  30. await session.initialize();
  31. session.terminated.connect((sender, args) => {
  32. expect(sender).to.equal(session);
  33. expect(args).to.be.undefined;
  34. });
  35. await session.shutdown();
  36. });
  37. });
  38. describe('#kernelChanged', () => {
  39. it('should be emitted when the kernel changes', async () => {
  40. session.kernelChanged.connect((sender, { oldValue, newValue }) => {
  41. expect(sender).to.equal(session);
  42. expect(oldValue).to.be.null;
  43. expect(newValue).to.equal(session.kernel);
  44. });
  45. await session.initialize();
  46. });
  47. });
  48. describe('#statusChanged', () => {
  49. it('should be emitted when the status changes', async () => {
  50. session.statusChanged.connect((sender, args) => {
  51. expect(sender).to.equal(session);
  52. expect(typeof args).to.equal('string');
  53. });
  54. await session.initialize();
  55. });
  56. });
  57. describe('#iopubMessage', () => {
  58. it('should be emitted for iopub kernel messages', async () => {
  59. session.iopubMessage.connect((sender, args) => {
  60. expect(sender).to.equal(session);
  61. });
  62. await session.initialize();
  63. });
  64. });
  65. describe('#propertyChanged', () => {
  66. it('should be emitted when a session path changes', async () => {
  67. session.kernelPreference = { canStart: false };
  68. session.propertyChanged.connect((sender, args) => {
  69. expect(sender).to.equal(session);
  70. expect(args).to.equal('path');
  71. });
  72. await session.setPath('foo');
  73. });
  74. it('should be emitted when a session name changes', async () => {
  75. session.kernelPreference = { canStart: false };
  76. session.propertyChanged.connect((sender, args) => {
  77. expect(sender).to.equal(session);
  78. expect(args).to.equal('name');
  79. });
  80. await session.setName('foo');
  81. });
  82. it('should be emitted when a session type changes', async () => {
  83. session.kernelPreference = { canStart: false };
  84. session.propertyChanged.connect((sender, args) => {
  85. expect(sender).to.equal(session);
  86. expect(args).to.equal('type');
  87. });
  88. await session.setType('foo');
  89. });
  90. });
  91. describe('#kernel', () => {
  92. it('should be the current kernel of the the session', async () => {
  93. expect(session.kernel).to.be.null;
  94. await session.initialize();
  95. expect(session.kernel).to.be.ok;
  96. });
  97. });
  98. describe('#path', () => {
  99. it('should current path of the the session', async () => {
  100. session.kernelPreference = { canStart: false };
  101. expect(typeof session.path).to.equal('string');
  102. await session.setPath('foo');
  103. expect(session.path).to.equal('foo');
  104. });
  105. });
  106. describe('#name', () => {
  107. it('should the current name of the the session', async () => {
  108. session.kernelPreference = { canStart: false };
  109. expect(typeof session.name).to.equal('string');
  110. await session.setName('foo');
  111. expect(session.name).to.equal('foo');
  112. });
  113. });
  114. describe('#type', () => {
  115. it('should the current type of the the session', async () => {
  116. session.kernelPreference = { canStart: false };
  117. expect(typeof session.type).to.equal('string');
  118. await session.setType('foo');
  119. expect(session.type).to.equal('foo');
  120. });
  121. });
  122. describe('#kernelPreference', () => {
  123. it('should be the kernel preference of the session', () => {
  124. const preference: IClientSession.IKernelPreference = {
  125. name: 'foo',
  126. language: 'bar',
  127. id: '1234',
  128. shouldStart: true,
  129. canStart: true
  130. };
  131. session.kernelPreference = preference;
  132. expect(session.kernelPreference).to.equal(preference);
  133. });
  134. });
  135. describe('#manager', () => {
  136. it('should be the session manager used by the session', () => {
  137. expect(session.manager).to.equal(manager);
  138. });
  139. });
  140. describe('#status', () => {
  141. it('should be the current status of the session', () => {
  142. expect(typeof session.status).to.equal('string');
  143. });
  144. });
  145. describe('#isReady', () => {
  146. it('should be false until ready', async () => {
  147. expect(session.isReady).to.equal(false);
  148. await session.initialize();
  149. expect(session.isReady).to.equal(true);
  150. });
  151. });
  152. describe('#initialize()', () => {
  153. it('should start the default kernel', async () => {
  154. await session.initialize();
  155. expect(session.kernel.name).to.equal(manager.specs.default);
  156. });
  157. it('should connect to an existing session on the path', async () => {
  158. const other = await manager.startNew({ path: session.path });
  159. await session.initialize();
  160. expect(other.kernel.id).to.equal(session.kernel.id);
  161. other.dispose();
  162. });
  163. it('should connect to an existing kernel', async () => {
  164. // Dispose the session so it can be re-instantiated.
  165. session.dispose();
  166. const other = await manager.startNew({ path: UUID.uuid4() });
  167. const kernelPreference = { id: other.kernel.id };
  168. session = new ClientSession({ manager, kernelPreference });
  169. await session.initialize();
  170. expect(session.kernel.id).to.equal(other.kernel.id);
  171. other.dispose();
  172. });
  173. it('should present a dialog if there is no distinct kernel to start', async () => {
  174. // Remove the kernel preference before initializing.
  175. session.kernelPreference = {};
  176. const accept = acceptDialog();
  177. await session.initialize();
  178. await accept;
  179. expect(session.kernel.name).to.equal(manager.specs.default);
  180. });
  181. it('should be a no-op if if the shouldStart kernelPreference is false', async () => {
  182. session.kernelPreference = { shouldStart: false };
  183. await session.initialize();
  184. expect(session.kernel).to.not.be.ok;
  185. });
  186. it('should be a no-op if if the canStart kernelPreference is false', async () => {
  187. session.kernelPreference = { canStart: false };
  188. await session.initialize();
  189. expect(session.kernel).to.not.be.ok;
  190. });
  191. });
  192. describe('#kernelDisplayName', () => {
  193. it('should be the display name of the current kernel', async () => {
  194. expect(session.kernelDisplayName).to.equal('No Kernel!');
  195. await session.initialize();
  196. expect(session.kernelDisplayName).to.not.equal('No Kernel!');
  197. });
  198. });
  199. describe('#isDisposed', () => {
  200. it('should test whether a client session has been disposed', () => {
  201. expect(session.isDisposed).to.equal(false);
  202. session.dispose();
  203. expect(session.isDisposed).to.equal(true);
  204. });
  205. });
  206. describe('#dispose()', () => {
  207. it('should dispose the resources held by the client session', () => {
  208. session.dispose();
  209. expect(session.isDisposed).to.equal(true);
  210. session.dispose();
  211. expect(session.isDisposed).to.equal(true);
  212. });
  213. });
  214. describe('#changeKernel()', () => {
  215. it('should change the current kernel', async () => {
  216. await session.initialize();
  217. const name = session.kernel.name;
  218. const id = session.kernel.id;
  219. const kernel = await session.changeKernel({ name });
  220. expect(kernel.id).to.not.equal(id);
  221. expect(kernel.name).to.equal(name);
  222. });
  223. });
  224. describe('#selectKernel()', () => {
  225. it('should select a kernel for the session', async () => {
  226. await session.initialize();
  227. const { id, name } = session.kernel;
  228. const accept = acceptDialog();
  229. await session.selectKernel();
  230. await accept;
  231. expect(session.kernel.id).to.not.equal(id);
  232. expect(session.kernel.name).to.equal(name);
  233. });
  234. it('should keep the existing kernel if dismissed', async () => {
  235. await session.initialize();
  236. const { id, name } = session.kernel;
  237. const dismiss = dismissDialog();
  238. await session.selectKernel();
  239. await dismiss;
  240. expect(session.kernel.id).to.equal(id);
  241. expect(session.kernel.name).to.equal(name);
  242. });
  243. });
  244. describe('#shutdown', () => {
  245. it('should kill the kernel and shut down the session', async () => {
  246. await session.initialize();
  247. expect(session.kernel).to.not.equal(null);
  248. await session.shutdown();
  249. expect(session.kernel).to.be.null;
  250. });
  251. });
  252. describe('#restart()', () => {
  253. it('should restart if the user accepts the dialog', async () => {
  254. let called = false;
  255. await session.initialize();
  256. session.statusChanged.connect((sender, args) => {
  257. if (args === 'restarting') {
  258. called = true;
  259. }
  260. });
  261. const restart = session.restart();
  262. await acceptDialog();
  263. expect(await restart).to.equal(true);
  264. expect(called).to.equal(true);
  265. });
  266. it('should not restart if the user rejects the dialog', async () => {
  267. let called = false;
  268. await session.initialize();
  269. session.statusChanged.connect((sender, args) => {
  270. if (args === 'restarting') {
  271. called = true;
  272. }
  273. });
  274. const restart = session.restart();
  275. await dismissDialog();
  276. expect(await restart).to.equal(false);
  277. expect(called).to.equal(false);
  278. });
  279. it('should start the same kernel as the previously started kernel', async () => {
  280. await session.initialize();
  281. await session.shutdown();
  282. await session.restart();
  283. expect(session.kernel).to.be.ok;
  284. });
  285. });
  286. describe('#setPath()', () => {
  287. it('should change the session path', async () => {
  288. session.kernelPreference = { canStart: false };
  289. await session.setPath('foo');
  290. expect(session.path).to.equal('foo');
  291. });
  292. });
  293. describe('#setName', () => {
  294. it('should change the session name', async () => {
  295. session.kernelPreference = { canStart: false };
  296. await session.setName('foo');
  297. expect(session.name).to.equal('foo');
  298. });
  299. });
  300. describe('#setType()', () => {
  301. it('should set the session type', async () => {
  302. session.kernelPreference = { canStart: false };
  303. await session.setType('foo');
  304. expect(session.type).to.equal('foo');
  305. });
  306. });
  307. describe('.restartKernel()', () => {
  308. it('should restart if the user accepts the dialog', async () => {
  309. let called = false;
  310. session.statusChanged.connect((sender, args) => {
  311. if (args === 'restarting') {
  312. called = true;
  313. }
  314. });
  315. await session.initialize();
  316. const restart = ClientSession.restartKernel(session.kernel);
  317. await acceptDialog();
  318. await restart;
  319. expect(called).to.equal(true);
  320. });
  321. it('should not restart if the user rejects the dialog', async () => {
  322. let called = false;
  323. await session.initialize();
  324. session.statusChanged.connect((sender, args) => {
  325. if (args === 'restarting') {
  326. called = true;
  327. }
  328. });
  329. const restart = ClientSession.restartKernel(session.kernel);
  330. await dismissDialog();
  331. await restart;
  332. expect(called).to.equal(false);
  333. });
  334. });
  335. describe('.getDefaultKernel()', () => {
  336. beforeEach(() => {
  337. session.dispose();
  338. });
  339. it('should return null if no options are given', () => {
  340. expect(
  341. ClientSession.getDefaultKernel({
  342. specs: manager.specs,
  343. preference: {}
  344. })
  345. ).to.be.null;
  346. });
  347. it('should return a matching name', () => {
  348. const spec = manager.specs.kernelspecs[manager.specs.default];
  349. expect(
  350. ClientSession.getDefaultKernel({
  351. specs: manager.specs,
  352. preference: { name: spec.name }
  353. })
  354. ).to.equal(spec.name);
  355. });
  356. it('should return null if no match is found', () => {
  357. expect(
  358. ClientSession.getDefaultKernel({
  359. specs: manager.specs,
  360. preference: { name: 'foo' }
  361. })
  362. ).to.be.null;
  363. });
  364. it('should return a matching language', () => {
  365. const spec = manager.specs.kernelspecs[manager.specs.default];
  366. const kernelspecs: any = {};
  367. kernelspecs[spec.name] = spec;
  368. expect(
  369. ClientSession.getDefaultKernel({
  370. specs: {
  371. default: spec.name,
  372. kernelspecs
  373. },
  374. preference: { language: spec.language }
  375. })
  376. ).to.equal(spec.name);
  377. });
  378. it('should return null if a language matches twice', () => {
  379. const spec = manager.specs.kernelspecs[manager.specs.default];
  380. const kernelspecs: any = {};
  381. kernelspecs['foo'] = spec;
  382. kernelspecs['bar'] = spec;
  383. expect(
  384. ClientSession.getDefaultKernel({
  385. specs: {
  386. default: spec.name,
  387. kernelspecs
  388. },
  389. preference: { language: spec.language }
  390. })
  391. ).to.be.null;
  392. });
  393. });
  394. describe('.populateKernelSelect()', () => {
  395. beforeEach(() => {
  396. session.dispose();
  397. });
  398. it('should populate the select div', () => {
  399. const div = document.createElement('select');
  400. ClientSession.populateKernelSelect(div, {
  401. specs: manager.specs,
  402. preference: {}
  403. });
  404. expect(div.firstChild).to.be.ok;
  405. expect(div.value).to.not.equal('null');
  406. });
  407. it('should select the null option', () => {
  408. const div = document.createElement('select');
  409. ClientSession.populateKernelSelect(div, {
  410. specs: manager.specs,
  411. preference: { shouldStart: false }
  412. });
  413. expect(div.firstChild).to.be.ok;
  414. expect(div.value).to.equal('null');
  415. });
  416. it('should disable the node', () => {
  417. const div = document.createElement('select');
  418. ClientSession.populateKernelSelect(div, {
  419. specs: manager.specs,
  420. preference: { canStart: false }
  421. });
  422. expect(div.firstChild).to.be.ok;
  423. expect(div.value).to.equal('null');
  424. expect(div.disabled).to.equal(true);
  425. });
  426. });
  427. });
  428. });