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