test_manager.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  1. # coding: utf-8
  2. """Tests for the notebook manager."""
  3. from __future__ import print_function
  4. import os
  5. import sys
  6. import time
  7. from contextlib import contextmanager
  8. from itertools import combinations
  9. from nose import SkipTest
  10. from tornado.web import HTTPError
  11. from unittest import TestCase
  12. from tempfile import NamedTemporaryFile
  13. from nbformat import v4 as nbformat
  14. from ipython_genutils.tempdir import TemporaryDirectory
  15. from traitlets import TraitError
  16. from ipython_genutils.testing import decorators as dec
  17. from ..filemanager import FileContentsManager
  18. def _make_dir(contents_manager, api_path):
  19. """
  20. Make a directory.
  21. """
  22. os_path = contents_manager._get_os_path(api_path)
  23. try:
  24. os.makedirs(os_path)
  25. except OSError:
  26. print("Directory already exists: %r" % os_path)
  27. class TestFileContentsManager(TestCase):
  28. @contextmanager
  29. def assertRaisesHTTPError(self, status, msg=None):
  30. msg = msg or "Should have raised HTTPError(%i)" % status
  31. try:
  32. yield
  33. except HTTPError as e:
  34. self.assertEqual(e.status_code, status)
  35. else:
  36. self.fail(msg)
  37. def symlink(self, contents_manager, src, dst):
  38. """Make a symlink to src from dst
  39. src and dst are api_paths
  40. """
  41. src_os_path = contents_manager._get_os_path(src)
  42. dst_os_path = contents_manager._get_os_path(dst)
  43. print(src_os_path, dst_os_path, os.path.isfile(src_os_path))
  44. os.symlink(src_os_path, dst_os_path)
  45. def test_root_dir(self):
  46. with TemporaryDirectory() as td:
  47. fm = FileContentsManager(root_dir=td)
  48. self.assertEqual(fm.root_dir, td)
  49. def test_missing_root_dir(self):
  50. with TemporaryDirectory() as td:
  51. root = os.path.join(td, 'notebook', 'dir', 'is', 'missing')
  52. self.assertRaises(TraitError, FileContentsManager, root_dir=root)
  53. def test_invalid_root_dir(self):
  54. with NamedTemporaryFile() as tf:
  55. self.assertRaises(TraitError, FileContentsManager, root_dir=tf.name)
  56. def test_get_os_path(self):
  57. # full filesystem path should be returned with correct operating system
  58. # separators.
  59. with TemporaryDirectory() as td:
  60. root = td
  61. fm = FileContentsManager(root_dir=root)
  62. path = fm._get_os_path('/path/to/notebook/test.ipynb')
  63. rel_path_list = '/path/to/notebook/test.ipynb'.split('/')
  64. fs_path = os.path.join(fm.root_dir, *rel_path_list)
  65. self.assertEqual(path, fs_path)
  66. fm = FileContentsManager(root_dir=root)
  67. path = fm._get_os_path('test.ipynb')
  68. fs_path = os.path.join(fm.root_dir, 'test.ipynb')
  69. self.assertEqual(path, fs_path)
  70. fm = FileContentsManager(root_dir=root)
  71. path = fm._get_os_path('////test.ipynb')
  72. fs_path = os.path.join(fm.root_dir, 'test.ipynb')
  73. self.assertEqual(path, fs_path)
  74. def test_checkpoint_subdir(self):
  75. subd = u'sub ∂ir'
  76. cp_name = 'test-cp.ipynb'
  77. with TemporaryDirectory() as td:
  78. root = td
  79. os.mkdir(os.path.join(td, subd))
  80. fm = FileContentsManager(root_dir=root)
  81. cpm = fm.checkpoints
  82. cp_dir = cpm.checkpoint_path(
  83. 'cp', 'test.ipynb'
  84. )
  85. cp_subdir = cpm.checkpoint_path(
  86. 'cp', '/%s/test.ipynb' % subd
  87. )
  88. self.assertNotEqual(cp_dir, cp_subdir)
  89. self.assertEqual(cp_dir, os.path.join(root, cpm.checkpoint_dir, cp_name))
  90. self.assertEqual(cp_subdir, os.path.join(root, subd, cpm.checkpoint_dir, cp_name))
  91. @dec.skipif(sys.platform == 'win32' and sys.version_info[0] < 3)
  92. def test_bad_symlink(self):
  93. with TemporaryDirectory() as td:
  94. cm = FileContentsManager(root_dir=td)
  95. path = 'test bad symlink'
  96. _make_dir(cm, path)
  97. file_model = cm.new_untitled(path=path, ext='.txt')
  98. # create a broken symlink
  99. self.symlink(cm, "target", '%s/%s' % (path, 'bad symlink'))
  100. model = cm.get(path)
  101. contents = {
  102. content['name']: content for content in model['content']
  103. }
  104. self.assertTrue('untitled.txt' in contents)
  105. self.assertEqual(contents['untitled.txt'], file_model)
  106. # broken symlinks should still be shown in the contents manager
  107. self.assertTrue('bad symlink' in contents)
  108. @dec.skipif(sys.platform == 'win32' and sys.version_info[0] < 3)
  109. def test_good_symlink(self):
  110. with TemporaryDirectory() as td:
  111. cm = FileContentsManager(root_dir=td)
  112. parent = 'test good symlink'
  113. name = 'good symlink'
  114. path = '{0}/{1}'.format(parent, name)
  115. _make_dir(cm, parent)
  116. file_model = cm.new(path=parent + '/zfoo.txt')
  117. # create a good symlink
  118. self.symlink(cm, file_model['path'], path)
  119. symlink_model = cm.get(path, content=False)
  120. dir_model = cm.get(parent)
  121. self.assertEqual(
  122. sorted(dir_model['content'], key=lambda x: x['name']),
  123. [symlink_model, file_model],
  124. )
  125. def test_403(self):
  126. if hasattr(os, 'getuid'):
  127. if os.getuid() == 0:
  128. raise SkipTest("Can't test permissions as root")
  129. if sys.platform.startswith('win'):
  130. raise SkipTest("Can't test permissions on Windows")
  131. with TemporaryDirectory() as td:
  132. cm = FileContentsManager(root_dir=td)
  133. model = cm.new_untitled(type='file')
  134. os_path = cm._get_os_path(model['path'])
  135. os.chmod(os_path, 0o400)
  136. try:
  137. with cm.open(os_path, 'w') as f:
  138. f.write(u"don't care")
  139. except HTTPError as e:
  140. self.assertEqual(e.status_code, 403)
  141. else:
  142. self.fail("Should have raised HTTPError(403)")
  143. def test_escape_root(self):
  144. with TemporaryDirectory() as td:
  145. cm = FileContentsManager(root_dir=td)
  146. # make foo, bar next to root
  147. with open(os.path.join(cm.root_dir, '..', 'foo'), 'w') as f:
  148. f.write('foo')
  149. with open(os.path.join(cm.root_dir, '..', 'bar'), 'w') as f:
  150. f.write('bar')
  151. with self.assertRaisesHTTPError(404):
  152. cm.get('..')
  153. with self.assertRaisesHTTPError(404):
  154. cm.get('foo/../../../bar')
  155. with self.assertRaisesHTTPError(404):
  156. cm.delete('../foo')
  157. with self.assertRaisesHTTPError(404):
  158. cm.rename('../foo', '../bar')
  159. with self.assertRaisesHTTPError(404):
  160. cm.save(model={
  161. 'type': 'file',
  162. 'content': u'',
  163. 'format': 'text',
  164. }, path='../foo')
  165. class TestContentsManager(TestCase):
  166. @contextmanager
  167. def assertRaisesHTTPError(self, status, msg=None):
  168. msg = msg or "Should have raised HTTPError(%i)" % status
  169. try:
  170. yield
  171. except HTTPError as e:
  172. self.assertEqual(e.status_code, status)
  173. else:
  174. self.fail(msg)
  175. def make_populated_dir(self, api_path):
  176. cm = self.contents_manager
  177. self.make_dir(api_path)
  178. cm.new(path="/".join([api_path, "nb.ipynb"]))
  179. cm.new(path="/".join([api_path, "file.txt"]))
  180. def check_populated_dir_files(self, api_path):
  181. dir_model = self.contents_manager.get(api_path)
  182. self.assertEqual(dir_model['path'], api_path)
  183. self.assertEqual(dir_model['type'], "directory")
  184. for entry in dir_model['content']:
  185. if entry['type'] == "directory":
  186. continue
  187. elif entry['type'] == "file":
  188. self.assertEqual(entry['name'], "file.txt")
  189. complete_path = "/".join([api_path, "file.txt"])
  190. self.assertEqual(entry["path"], complete_path)
  191. elif entry['type'] == "notebook":
  192. self.assertEqual(entry['name'], "nb.ipynb")
  193. complete_path = "/".join([api_path, "nb.ipynb"])
  194. self.assertEqual(entry["path"], complete_path)
  195. def setUp(self):
  196. self._temp_dir = TemporaryDirectory()
  197. self.td = self._temp_dir.name
  198. self.contents_manager = FileContentsManager(
  199. root_dir=self.td,
  200. )
  201. def tearDown(self):
  202. self._temp_dir.cleanup()
  203. def make_dir(self, api_path):
  204. """make a subdirectory at api_path
  205. override in subclasses if contents are not on the filesystem.
  206. """
  207. _make_dir(self.contents_manager, api_path)
  208. def add_code_cell(self, nb):
  209. output = nbformat.new_output("display_data", {'application/javascript': "alert('hi');"})
  210. cell = nbformat.new_code_cell("print('hi')", outputs=[output])
  211. nb.cells.append(cell)
  212. def new_notebook(self):
  213. cm = self.contents_manager
  214. model = cm.new_untitled(type='notebook')
  215. name = model['name']
  216. path = model['path']
  217. full_model = cm.get(path)
  218. nb = full_model['content']
  219. nb['metadata']['counter'] = int(1e6 * time.time())
  220. self.add_code_cell(nb)
  221. cm.save(full_model, path)
  222. return nb, name, path
  223. def test_new_untitled(self):
  224. cm = self.contents_manager
  225. # Test in root directory
  226. model = cm.new_untitled(type='notebook')
  227. assert isinstance(model, dict)
  228. self.assertIn('name', model)
  229. self.assertIn('path', model)
  230. self.assertIn('type', model)
  231. self.assertEqual(model['type'], 'notebook')
  232. self.assertEqual(model['name'], 'Untitled.ipynb')
  233. self.assertEqual(model['path'], 'Untitled.ipynb')
  234. # Test in sub-directory
  235. model = cm.new_untitled(type='directory')
  236. assert isinstance(model, dict)
  237. self.assertIn('name', model)
  238. self.assertIn('path', model)
  239. self.assertIn('type', model)
  240. self.assertEqual(model['type'], 'directory')
  241. self.assertEqual(model['name'], 'Untitled Folder')
  242. self.assertEqual(model['path'], 'Untitled Folder')
  243. sub_dir = model['path']
  244. model = cm.new_untitled(path=sub_dir)
  245. assert isinstance(model, dict)
  246. self.assertIn('name', model)
  247. self.assertIn('path', model)
  248. self.assertIn('type', model)
  249. self.assertEqual(model['type'], 'file')
  250. self.assertEqual(model['name'], 'untitled')
  251. self.assertEqual(model['path'], '%s/untitled' % sub_dir)
  252. # Test with a compound extension
  253. model = cm.new_untitled(path=sub_dir, ext='.foo.bar')
  254. self.assertEqual(model['name'], 'untitled.foo.bar')
  255. model = cm.new_untitled(path=sub_dir, ext='.foo.bar')
  256. self.assertEqual(model['name'], 'untitled1.foo.bar')
  257. def test_modified_date(self):
  258. cm = self.contents_manager
  259. # Create a new notebook.
  260. nb, name, path = self.new_notebook()
  261. model = cm.get(path)
  262. # Add a cell and save.
  263. self.add_code_cell(model['content'])
  264. cm.save(model, path)
  265. # Reload notebook and verify that last_modified incremented.
  266. saved = cm.get(path)
  267. self.assertGreaterEqual(saved['last_modified'], model['last_modified'])
  268. # Move the notebook and verify that last_modified stayed the same.
  269. # (The frontend fires a warning if last_modified increases on the
  270. # renamed file.)
  271. new_path = 'renamed.ipynb'
  272. cm.rename(path, new_path)
  273. renamed = cm.get(new_path)
  274. self.assertGreaterEqual(
  275. renamed['last_modified'],
  276. saved['last_modified'],
  277. )
  278. def test_get(self):
  279. cm = self.contents_manager
  280. # Create a notebook
  281. model = cm.new_untitled(type='notebook')
  282. name = model['name']
  283. path = model['path']
  284. # Check that we 'get' on the notebook we just created
  285. model2 = cm.get(path)
  286. assert isinstance(model2, dict)
  287. self.assertIn('name', model2)
  288. self.assertIn('path', model2)
  289. self.assertEqual(model['name'], name)
  290. self.assertEqual(model['path'], path)
  291. nb_as_file = cm.get(path, content=True, type='file')
  292. self.assertEqual(nb_as_file['path'], path)
  293. self.assertEqual(nb_as_file['type'], 'file')
  294. self.assertEqual(nb_as_file['format'], 'text')
  295. self.assertNotIsInstance(nb_as_file['content'], dict)
  296. nb_as_bin_file = cm.get(path, content=True, type='file', format='base64')
  297. self.assertEqual(nb_as_bin_file['format'], 'base64')
  298. # Test in sub-directory
  299. sub_dir = '/foo/'
  300. self.make_dir('foo')
  301. model = cm.new_untitled(path=sub_dir, ext='.ipynb')
  302. model2 = cm.get(sub_dir + name)
  303. assert isinstance(model2, dict)
  304. self.assertIn('name', model2)
  305. self.assertIn('path', model2)
  306. self.assertIn('content', model2)
  307. self.assertEqual(model2['name'], 'Untitled.ipynb')
  308. self.assertEqual(model2['path'], '{0}/{1}'.format(sub_dir.strip('/'), name))
  309. # Test with a regular file.
  310. file_model_path = cm.new_untitled(path=sub_dir, ext='.txt')['path']
  311. file_model = cm.get(file_model_path)
  312. self.assertDictContainsSubset(
  313. {
  314. 'content': u'',
  315. 'format': u'text',
  316. 'mimetype': u'text/plain',
  317. 'name': u'untitled.txt',
  318. 'path': u'foo/untitled.txt',
  319. 'type': u'file',
  320. 'writable': True,
  321. },
  322. file_model,
  323. )
  324. self.assertIn('created', file_model)
  325. self.assertIn('last_modified', file_model)
  326. # Test getting directory model
  327. # Create a sub-sub directory to test getting directory contents with a
  328. # subdir.
  329. self.make_dir('foo/bar')
  330. dirmodel = cm.get('foo')
  331. self.assertEqual(dirmodel['type'], 'directory')
  332. self.assertIsInstance(dirmodel['content'], list)
  333. self.assertEqual(len(dirmodel['content']), 3)
  334. self.assertEqual(dirmodel['path'], 'foo')
  335. self.assertEqual(dirmodel['name'], 'foo')
  336. # Directory contents should match the contents of each individual entry
  337. # when requested with content=False.
  338. model2_no_content = cm.get(sub_dir + name, content=False)
  339. file_model_no_content = cm.get(u'foo/untitled.txt', content=False)
  340. sub_sub_dir_no_content = cm.get('foo/bar', content=False)
  341. self.assertEqual(sub_sub_dir_no_content['path'], 'foo/bar')
  342. self.assertEqual(sub_sub_dir_no_content['name'], 'bar')
  343. for entry in dirmodel['content']:
  344. # Order isn't guaranteed by the spec, so this is a hacky way of
  345. # verifying that all entries are matched.
  346. if entry['path'] == sub_sub_dir_no_content['path']:
  347. self.assertEqual(entry, sub_sub_dir_no_content)
  348. elif entry['path'] == model2_no_content['path']:
  349. self.assertEqual(entry, model2_no_content)
  350. elif entry['path'] == file_model_no_content['path']:
  351. self.assertEqual(entry, file_model_no_content)
  352. else:
  353. self.fail("Unexpected directory entry: %s" % entry())
  354. with self.assertRaises(HTTPError):
  355. cm.get('foo', type='file')
  356. def test_update(self):
  357. cm = self.contents_manager
  358. # Create a notebook
  359. model = cm.new_untitled(type='notebook')
  360. name = model['name']
  361. path = model['path']
  362. # Change the name in the model for rename
  363. model['path'] = 'test.ipynb'
  364. model = cm.update(model, path)
  365. assert isinstance(model, dict)
  366. self.assertIn('name', model)
  367. self.assertIn('path', model)
  368. self.assertEqual(model['name'], 'test.ipynb')
  369. # Make sure the old name is gone
  370. self.assertRaises(HTTPError, cm.get, path)
  371. # Test in sub-directory
  372. # Create a directory and notebook in that directory
  373. sub_dir = '/foo/'
  374. self.make_dir('foo')
  375. model = cm.new_untitled(path=sub_dir, type='notebook')
  376. path = model['path']
  377. # Change the name in the model for rename
  378. d = path.rsplit('/', 1)[0]
  379. new_path = model['path'] = d + '/test_in_sub.ipynb'
  380. model = cm.update(model, path)
  381. assert isinstance(model, dict)
  382. self.assertIn('name', model)
  383. self.assertIn('path', model)
  384. self.assertEqual(model['name'], 'test_in_sub.ipynb')
  385. self.assertEqual(model['path'], new_path)
  386. # Make sure the old name is gone
  387. self.assertRaises(HTTPError, cm.get, path)
  388. def test_save(self):
  389. cm = self.contents_manager
  390. # Create a notebook
  391. model = cm.new_untitled(type='notebook')
  392. name = model['name']
  393. path = model['path']
  394. # Get the model with 'content'
  395. full_model = cm.get(path)
  396. # Save the notebook
  397. model = cm.save(full_model, path)
  398. assert isinstance(model, dict)
  399. self.assertIn('name', model)
  400. self.assertIn('path', model)
  401. self.assertEqual(model['name'], name)
  402. self.assertEqual(model['path'], path)
  403. # Test in sub-directory
  404. # Create a directory and notebook in that directory
  405. sub_dir = '/foo/'
  406. self.make_dir('foo')
  407. model = cm.new_untitled(path=sub_dir, type='notebook')
  408. name = model['name']
  409. path = model['path']
  410. model = cm.get(path)
  411. # Change the name in the model for rename
  412. model = cm.save(model, path)
  413. assert isinstance(model, dict)
  414. self.assertIn('name', model)
  415. self.assertIn('path', model)
  416. self.assertEqual(model['name'], 'Untitled.ipynb')
  417. self.assertEqual(model['path'], 'foo/Untitled.ipynb')
  418. def test_delete(self):
  419. cm = self.contents_manager
  420. # Create a notebook
  421. nb, name, path = self.new_notebook()
  422. # Delete the notebook
  423. cm.delete(path)
  424. # Check that deleting a non-existent path raises an error.
  425. self.assertRaises(HTTPError, cm.delete, path)
  426. # Check that a 'get' on the deleted notebook raises and error
  427. self.assertRaises(HTTPError, cm.get, path)
  428. def test_rename(self):
  429. cm = self.contents_manager
  430. # Create a new notebook
  431. nb, name, path = self.new_notebook()
  432. # Rename the notebook
  433. cm.rename(path, "changed_path")
  434. # Attempting to get the notebook under the old name raises an error
  435. self.assertRaises(HTTPError, cm.get, path)
  436. # Fetching the notebook under the new name is successful
  437. assert isinstance(cm.get("changed_path"), dict)
  438. # Ported tests on nested directory renaming from pgcontents
  439. all_dirs = ['foo', 'bar', 'foo/bar', 'foo/bar/foo', 'foo/bar/foo/bar']
  440. unchanged_dirs = all_dirs[:2]
  441. changed_dirs = all_dirs[2:]
  442. for _dir in all_dirs:
  443. self.make_populated_dir(_dir)
  444. self.check_populated_dir_files(_dir)
  445. # Renaming to an existing directory should fail
  446. for src, dest in combinations(all_dirs, 2):
  447. with self.assertRaisesHTTPError(409):
  448. cm.rename(src, dest)
  449. # Creating a notebook in a non_existant directory should fail
  450. with self.assertRaisesHTTPError(404):
  451. cm.new_untitled("foo/bar_diff", ext=".ipynb")
  452. cm.rename("foo/bar", "foo/bar_diff")
  453. # Assert that unchanged directories remain so
  454. for unchanged in unchanged_dirs:
  455. self.check_populated_dir_files(unchanged)
  456. # Assert changed directories can no longer be accessed under old names
  457. for changed_dirname in changed_dirs:
  458. with self.assertRaisesHTTPError(404):
  459. cm.get(changed_dirname)
  460. new_dirname = changed_dirname.replace("foo/bar", "foo/bar_diff", 1)
  461. self.check_populated_dir_files(new_dirname)
  462. # Created a notebook in the renamed directory should work
  463. cm.new_untitled("foo/bar_diff", ext=".ipynb")
  464. def test_delete_root(self):
  465. cm = self.contents_manager
  466. with self.assertRaises(HTTPError) as err:
  467. cm.delete('')
  468. self.assertEqual(err.exception.status_code, 400)
  469. def test_copy(self):
  470. cm = self.contents_manager
  471. parent = u'å b'
  472. name = u'nb √.ipynb'
  473. path = u'{0}/{1}'.format(parent, name)
  474. self.make_dir(parent)
  475. orig = cm.new(path=path)
  476. # copy with unspecified name
  477. copy = cm.copy(path)
  478. self.assertEqual(copy['name'], orig['name'].replace('.ipynb', '-Copy1.ipynb'))
  479. # copy with specified name
  480. copy2 = cm.copy(path, u'å b/copy 2.ipynb')
  481. self.assertEqual(copy2['name'], u'copy 2.ipynb')
  482. self.assertEqual(copy2['path'], u'å b/copy 2.ipynb')
  483. # copy with specified path
  484. copy2 = cm.copy(path, u'/')
  485. self.assertEqual(copy2['name'], name)
  486. self.assertEqual(copy2['path'], name)
  487. def test_trust_notebook(self):
  488. cm = self.contents_manager
  489. nb, name, path = self.new_notebook()
  490. untrusted = cm.get(path)['content']
  491. assert not cm.notary.check_cells(untrusted)
  492. # print(untrusted)
  493. cm.trust_notebook(path)
  494. trusted = cm.get(path)['content']
  495. # print(trusted)
  496. assert cm.notary.check_cells(trusted)
  497. def test_mark_trusted_cells(self):
  498. cm = self.contents_manager
  499. nb, name, path = self.new_notebook()
  500. cm.mark_trusted_cells(nb, path)
  501. for cell in nb.cells:
  502. if cell.cell_type == 'code':
  503. assert not cell.metadata.trusted
  504. cm.trust_notebook(path)
  505. nb = cm.get(path)['content']
  506. for cell in nb.cells:
  507. if cell.cell_type == 'code':
  508. assert cell.metadata.trusted
  509. def test_check_and_sign(self):
  510. cm = self.contents_manager
  511. nb, name, path = self.new_notebook()
  512. cm.mark_trusted_cells(nb, path)
  513. cm.check_and_sign(nb, path)
  514. assert not cm.notary.check_signature(nb)
  515. cm.trust_notebook(path)
  516. nb = cm.get(path)['content']
  517. cm.mark_trusted_cells(nb, path)
  518. cm.check_and_sign(nb, path)
  519. assert cm.notary.check_signature(nb)
  520. class TestContentsManagerNoAtomic(TestContentsManager):
  521. """
  522. Make same test in no atomic case than in atomic case, using inheritance
  523. """
  524. def setUp(self):
  525. self._temp_dir = TemporaryDirectory()
  526. self.td = self._temp_dir.name
  527. self.contents_manager = FileContentsManager(
  528. root_dir = self.td,
  529. )
  530. self.contents_manager.use_atomic_writing = False