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