##// END OF EJS Templates
TEST: More fine-grained test for directory contents....
Scott Sanderson -
Show More
@@ -1,378 +1,400 b''
1 1 # coding: utf-8
2 2 """Tests for the notebook manager."""
3 3 from __future__ import print_function
4 4
5 5 import os
6 6
7 7 from tornado.web import HTTPError
8 8 from unittest import TestCase
9 9 from tempfile import NamedTemporaryFile
10 10
11 11 from IPython.nbformat import v4 as nbformat
12 12
13 13 from IPython.utils.tempdir import TemporaryDirectory
14 14 from IPython.utils.traitlets import TraitError
15 15 from IPython.html.utils import url_path_join
16 16 from IPython.testing import decorators as dec
17 17
18 18 from ..filemanager import FileContentsManager
19 19
20 20
21 21 class TestFileContentsManager(TestCase):
22 22
23 23 def test_root_dir(self):
24 24 with TemporaryDirectory() as td:
25 25 fm = FileContentsManager(root_dir=td)
26 26 self.assertEqual(fm.root_dir, td)
27 27
28 28 def test_missing_root_dir(self):
29 29 with TemporaryDirectory() as td:
30 30 root = os.path.join(td, 'notebook', 'dir', 'is', 'missing')
31 31 self.assertRaises(TraitError, FileContentsManager, root_dir=root)
32 32
33 33 def test_invalid_root_dir(self):
34 34 with NamedTemporaryFile() as tf:
35 35 self.assertRaises(TraitError, FileContentsManager, root_dir=tf.name)
36 36
37 37 def test_get_os_path(self):
38 38 # full filesystem path should be returned with correct operating system
39 39 # separators.
40 40 with TemporaryDirectory() as td:
41 41 root = td
42 42 fm = FileContentsManager(root_dir=root)
43 43 path = fm._get_os_path('/path/to/notebook/test.ipynb')
44 44 rel_path_list = '/path/to/notebook/test.ipynb'.split('/')
45 45 fs_path = os.path.join(fm.root_dir, *rel_path_list)
46 46 self.assertEqual(path, fs_path)
47 47
48 48 fm = FileContentsManager(root_dir=root)
49 49 path = fm._get_os_path('test.ipynb')
50 50 fs_path = os.path.join(fm.root_dir, 'test.ipynb')
51 51 self.assertEqual(path, fs_path)
52 52
53 53 fm = FileContentsManager(root_dir=root)
54 54 path = fm._get_os_path('////test.ipynb')
55 55 fs_path = os.path.join(fm.root_dir, 'test.ipynb')
56 56 self.assertEqual(path, fs_path)
57 57
58 58 def test_checkpoint_subdir(self):
59 59 subd = u'sub βˆ‚ir'
60 60 cp_name = 'test-cp.ipynb'
61 61 with TemporaryDirectory() as td:
62 62 root = td
63 63 os.mkdir(os.path.join(td, subd))
64 64 fm = FileContentsManager(root_dir=root)
65 65 cp_dir = fm.get_checkpoint_path('cp', 'test.ipynb')
66 66 cp_subdir = fm.get_checkpoint_path('cp', '/%s/test.ipynb' % subd)
67 67 self.assertNotEqual(cp_dir, cp_subdir)
68 68 self.assertEqual(cp_dir, os.path.join(root, fm.checkpoint_dir, cp_name))
69 69 self.assertEqual(cp_subdir, os.path.join(root, subd, fm.checkpoint_dir, cp_name))
70 70
71 71
72 72 class TestContentsManager(TestCase):
73 73
74 74 def setUp(self):
75 75 self._temp_dir = TemporaryDirectory()
76 76 self.td = self._temp_dir.name
77 77 self.contents_manager = FileContentsManager(
78 78 root_dir=self.td,
79 79 )
80 80
81 81 def tearDown(self):
82 82 self._temp_dir.cleanup()
83 83
84 84 def make_dir(self, api_path):
85 85 """make subdirectory, rel_path is the relative path
86 86 to that directory from the location where the server started"""
87 87 os_path = self.contents_manager._get_os_path(api_path)
88 88 try:
89 89 os.makedirs(os_path)
90 90 except OSError:
91 91 print("Directory already exists: %r" % os_path)
92 92
93 93 def symlink(self, src, dst):
94 94 """Make a symlink to src from dst
95 95
96 96 src and dst are api_paths
97 97 """
98 98 src_os_path = self.contents_manager._get_os_path(src)
99 99 dst_os_path = self.contents_manager._get_os_path(dst)
100 100 print(src_os_path, dst_os_path, os.path.isfile(src_os_path))
101 101 os.symlink(src_os_path, dst_os_path)
102 102
103 103
104 104 def add_code_cell(self, nb):
105 105 output = nbformat.new_output("display_data", {'application/javascript': "alert('hi');"})
106 106 cell = nbformat.new_code_cell("print('hi')", outputs=[output])
107 107 nb.cells.append(cell)
108 108
109 109 def new_notebook(self):
110 110 cm = self.contents_manager
111 111 model = cm.new_untitled(type='notebook')
112 112 name = model['name']
113 113 path = model['path']
114 114
115 115 full_model = cm.get(path)
116 116 nb = full_model['content']
117 117 self.add_code_cell(nb)
118 118
119 119 cm.save(full_model, path)
120 120 return nb, name, path
121 121
122 122 def test_new_untitled(self):
123 123 cm = self.contents_manager
124 124 # Test in root directory
125 125 model = cm.new_untitled(type='notebook')
126 126 assert isinstance(model, dict)
127 127 self.assertIn('name', model)
128 128 self.assertIn('path', model)
129 129 self.assertIn('type', model)
130 130 self.assertEqual(model['type'], 'notebook')
131 131 self.assertEqual(model['name'], 'Untitled.ipynb')
132 132 self.assertEqual(model['path'], 'Untitled.ipynb')
133 133
134 134 # Test in sub-directory
135 135 model = cm.new_untitled(type='directory')
136 136 assert isinstance(model, dict)
137 137 self.assertIn('name', model)
138 138 self.assertIn('path', model)
139 139 self.assertIn('type', model)
140 140 self.assertEqual(model['type'], 'directory')
141 141 self.assertEqual(model['name'], 'Untitled Folder')
142 142 self.assertEqual(model['path'], 'Untitled Folder')
143 143 sub_dir = model['path']
144 144
145 145 model = cm.new_untitled(path=sub_dir)
146 146 assert isinstance(model, dict)
147 147 self.assertIn('name', model)
148 148 self.assertIn('path', model)
149 149 self.assertIn('type', model)
150 150 self.assertEqual(model['type'], 'file')
151 151 self.assertEqual(model['name'], 'untitled')
152 152 self.assertEqual(model['path'], '%s/untitled' % sub_dir)
153 153
154 154 def test_get(self):
155 155 cm = self.contents_manager
156 156 # Create a notebook
157 157 model = cm.new_untitled(type='notebook')
158 158 name = model['name']
159 159 path = model['path']
160 160
161 161 # Check that we 'get' on the notebook we just created
162 162 model2 = cm.get(path)
163 163 assert isinstance(model2, dict)
164 164 self.assertIn('name', model2)
165 165 self.assertIn('path', model2)
166 166 self.assertEqual(model['name'], name)
167 167 self.assertEqual(model['path'], path)
168 168
169 169 nb_as_file = cm.get(path, content=True, type='file')
170 170 self.assertEqual(nb_as_file['path'], path)
171 171 self.assertEqual(nb_as_file['type'], 'file')
172 172 self.assertEqual(nb_as_file['format'], 'text')
173 173 self.assertNotIsInstance(nb_as_file['content'], dict)
174 174
175 175 nb_as_bin_file = cm.get(path, content=True, type='file', format='base64')
176 176 self.assertEqual(nb_as_bin_file['format'], 'base64')
177 177
178 178 # Test in sub-directory
179 179 sub_dir = '/foo/'
180 180 self.make_dir('foo')
181 181 model = cm.new_untitled(path=sub_dir, ext='.ipynb')
182 182 model2 = cm.get(sub_dir + name)
183 183 assert isinstance(model2, dict)
184 184 self.assertIn('name', model2)
185 185 self.assertIn('path', model2)
186 186 self.assertIn('content', model2)
187 187 self.assertEqual(model2['name'], 'Untitled.ipynb')
188 188 self.assertEqual(model2['path'], '{0}/{1}'.format(sub_dir.strip('/'), name))
189 189
190 190 # Test getting directory model
191
192 # Create a sub-sub directory to test getting directory contents with a
193 # subdir.
194 sub_sub_dir_path = 'foo/bar'
195 self.make_dir(sub_sub_dir_path)
196
191 197 dirmodel = cm.get('foo')
192 198 self.assertEqual(dirmodel['type'], 'directory')
199 self.assertIsInstance(dirmodel['content'], list)
200 self.assertEqual(len(dirmodel['content']), 2)
201
202 # Directory contents should match the contents of each individual entry
203 # when requested with content=False.
204 model2_no_content = cm.get(sub_dir + name, content=False)
205 sub_sub_dir_no_content = cm.get(sub_sub_dir_path, content=False)
206 for entry in dirmodel['content']:
207 # Order isn't guaranteed by the spec, so this is a hacky way of
208 # verifying that all entries are matched.
209 if entry['path'] == sub_sub_dir_no_content['path']:
210 self.assertEqual(entry, sub_sub_dir_no_content)
211 elif entry['path'] == model2_no_content['path']:
212 self.assertEqual(entry, model2_no_content)
213 else:
214 self.fail("Unexpected directory entry: %s" % entry())
193 215
194 216 with self.assertRaises(HTTPError):
195 217 cm.get('foo', type='file')
196 218
197 219
198 220 @dec.skip_win32
199 221 def test_bad_symlink(self):
200 222 cm = self.contents_manager
201 223 path = 'test bad symlink'
202 224 self.make_dir(path)
203 225
204 226 file_model = cm.new_untitled(path=path, ext='.txt')
205 227
206 228 # create a broken symlink
207 229 self.symlink("target", '%s/%s' % (path, 'bad symlink'))
208 230 model = cm.get(path)
209 231 self.assertEqual(model['content'], [file_model])
210 232
211 233 @dec.skip_win32
212 234 def test_good_symlink(self):
213 235 cm = self.contents_manager
214 236 parent = 'test good symlink'
215 237 name = 'good symlink'
216 238 path = '{0}/{1}'.format(parent, name)
217 239 self.make_dir(parent)
218 240
219 241 file_model = cm.new(path=parent + '/zfoo.txt')
220 242
221 243 # create a good symlink
222 244 self.symlink(file_model['path'], path)
223 245 symlink_model = cm.get(path, content=False)
224 246 dir_model = cm.get(parent)
225 247 self.assertEqual(
226 248 sorted(dir_model['content'], key=lambda x: x['name']),
227 249 [symlink_model, file_model],
228 250 )
229 251
230 252 def test_update(self):
231 253 cm = self.contents_manager
232 254 # Create a notebook
233 255 model = cm.new_untitled(type='notebook')
234 256 name = model['name']
235 257 path = model['path']
236 258
237 259 # Change the name in the model for rename
238 260 model['path'] = 'test.ipynb'
239 261 model = cm.update(model, path)
240 262 assert isinstance(model, dict)
241 263 self.assertIn('name', model)
242 264 self.assertIn('path', model)
243 265 self.assertEqual(model['name'], 'test.ipynb')
244 266
245 267 # Make sure the old name is gone
246 268 self.assertRaises(HTTPError, cm.get, path)
247 269
248 270 # Test in sub-directory
249 271 # Create a directory and notebook in that directory
250 272 sub_dir = '/foo/'
251 273 self.make_dir('foo')
252 274 model = cm.new_untitled(path=sub_dir, type='notebook')
253 275 path = model['path']
254 276
255 277 # Change the name in the model for rename
256 278 d = path.rsplit('/', 1)[0]
257 279 new_path = model['path'] = d + '/test_in_sub.ipynb'
258 280 model = cm.update(model, path)
259 281 assert isinstance(model, dict)
260 282 self.assertIn('name', model)
261 283 self.assertIn('path', model)
262 284 self.assertEqual(model['name'], 'test_in_sub.ipynb')
263 285 self.assertEqual(model['path'], new_path)
264 286
265 287 # Make sure the old name is gone
266 288 self.assertRaises(HTTPError, cm.get, path)
267 289
268 290 def test_save(self):
269 291 cm = self.contents_manager
270 292 # Create a notebook
271 293 model = cm.new_untitled(type='notebook')
272 294 name = model['name']
273 295 path = model['path']
274 296
275 297 # Get the model with 'content'
276 298 full_model = cm.get(path)
277 299
278 300 # Save the notebook
279 301 model = cm.save(full_model, path)
280 302 assert isinstance(model, dict)
281 303 self.assertIn('name', model)
282 304 self.assertIn('path', model)
283 305 self.assertEqual(model['name'], name)
284 306 self.assertEqual(model['path'], path)
285 307
286 308 # Test in sub-directory
287 309 # Create a directory and notebook in that directory
288 310 sub_dir = '/foo/'
289 311 self.make_dir('foo')
290 312 model = cm.new_untitled(path=sub_dir, type='notebook')
291 313 name = model['name']
292 314 path = model['path']
293 315 model = cm.get(path)
294 316
295 317 # Change the name in the model for rename
296 318 model = cm.save(model, path)
297 319 assert isinstance(model, dict)
298 320 self.assertIn('name', model)
299 321 self.assertIn('path', model)
300 322 self.assertEqual(model['name'], 'Untitled.ipynb')
301 323 self.assertEqual(model['path'], 'foo/Untitled.ipynb')
302 324
303 325 def test_delete(self):
304 326 cm = self.contents_manager
305 327 # Create a notebook
306 328 nb, name, path = self.new_notebook()
307 329
308 330 # Delete the notebook
309 331 cm.delete(path)
310 332
311 333 # Check that deleting a non-existent path raises an error.
312 334 self.assertRaises(HTTPError, cm.delete, path)
313 335
314 336 # Check that a 'get' on the deleted notebook raises and error
315 337 self.assertRaises(HTTPError, cm.get, path)
316 338
317 339 def test_copy(self):
318 340 cm = self.contents_manager
319 341 parent = u'Γ₯ b'
320 342 name = u'nb √.ipynb'
321 343 path = u'{0}/{1}'.format(parent, name)
322 344 self.make_dir(parent)
323 345
324 346 orig = cm.new(path=path)
325 347 # copy with unspecified name
326 348 copy = cm.copy(path)
327 349 self.assertEqual(copy['name'], orig['name'].replace('.ipynb', '-Copy1.ipynb'))
328 350
329 351 # copy with specified name
330 352 copy2 = cm.copy(path, u'Γ₯ b/copy 2.ipynb')
331 353 self.assertEqual(copy2['name'], u'copy 2.ipynb')
332 354 self.assertEqual(copy2['path'], u'Γ₯ b/copy 2.ipynb')
333 355 # copy with specified path
334 356 copy2 = cm.copy(path, u'/')
335 357 self.assertEqual(copy2['name'], name)
336 358 self.assertEqual(copy2['path'], name)
337 359
338 360 def test_trust_notebook(self):
339 361 cm = self.contents_manager
340 362 nb, name, path = self.new_notebook()
341 363
342 364 untrusted = cm.get(path)['content']
343 365 assert not cm.notary.check_cells(untrusted)
344 366
345 367 # print(untrusted)
346 368 cm.trust_notebook(path)
347 369 trusted = cm.get(path)['content']
348 370 # print(trusted)
349 371 assert cm.notary.check_cells(trusted)
350 372
351 373 def test_mark_trusted_cells(self):
352 374 cm = self.contents_manager
353 375 nb, name, path = self.new_notebook()
354 376
355 377 cm.mark_trusted_cells(nb, path)
356 378 for cell in nb.cells:
357 379 if cell.cell_type == 'code':
358 380 assert not cell.metadata.trusted
359 381
360 382 cm.trust_notebook(path)
361 383 nb = cm.get(path)['content']
362 384 for cell in nb.cells:
363 385 if cell.cell_type == 'code':
364 386 assert cell.metadata.trusted
365 387
366 388 def test_check_and_sign(self):
367 389 cm = self.contents_manager
368 390 nb, name, path = self.new_notebook()
369 391
370 392 cm.mark_trusted_cells(nb, path)
371 393 cm.check_and_sign(nb, path)
372 394 assert not cm.notary.check_signature(nb)
373 395
374 396 cm.trust_notebook(path)
375 397 nb = cm.get(path)['content']
376 398 cm.mark_trusted_cells(nb, path)
377 399 cm.check_and_sign(nb, path)
378 400 assert cm.notary.check_signature(nb)
General Comments 0
You need to be logged in to leave comments. Login now