3 import arvados_fuse as fuse
16 import multiprocessing
17 import run_test_server
21 from mount_test_base import MountTestBase
23 logger = logging.getLogger('arvados.arv-mount')
26 class FuseMountTest(MountTestBase):
28 super(FuseMountTest, self).setUp()
30 cw = arvados.CollectionWriter()
32 cw.start_new_file('thing1.txt')
34 cw.start_new_file('thing2.txt')
37 cw.start_new_stream('dir1')
38 cw.start_new_file('thing3.txt')
40 cw.start_new_file('thing4.txt')
43 cw.start_new_stream('dir2')
44 cw.start_new_file('thing5.txt')
46 cw.start_new_file('thing6.txt')
49 cw.start_new_stream('dir2/dir3')
50 cw.start_new_file('thing7.txt')
53 cw.start_new_file('thing8.txt')
56 cw.start_new_stream('edgecases')
57 for f in ":/.../-/*/\x01\\/ ".split("/"):
61 for f in ":/.../-/*/\x01\\/ ".split("/"):
62 cw.start_new_stream('edgecases/dirs/' + f)
63 cw.start_new_file('x/x')
66 self.testcollection = cw.finish()
67 self.api.collections().create(body={"manifest_text":cw.manifest_text()}).execute()
70 self.make_mount(fuse.CollectionDirectory, collection_record=self.testcollection)
72 self.assertDirContents(None, ['thing1.txt', 'thing2.txt',
73 'edgecases', 'dir1', 'dir2'])
74 self.assertDirContents('dir1', ['thing3.txt', 'thing4.txt'])
75 self.assertDirContents('dir2', ['thing5.txt', 'thing6.txt', 'dir3'])
76 self.assertDirContents('dir2/dir3', ['thing7.txt', 'thing8.txt'])
77 self.assertDirContents('edgecases',
78 "dirs/:/.../-/*/\x01\\/ ".split("/"))
79 self.assertDirContents('edgecases/dirs',
80 ":/.../-/*/\x01\\/ ".split("/"))
82 files = {'thing1.txt': 'data 1',
83 'thing2.txt': 'data 2',
84 'dir1/thing3.txt': 'data 3',
85 'dir1/thing4.txt': 'data 4',
86 'dir2/thing5.txt': 'data 5',
87 'dir2/thing6.txt': 'data 6',
88 'dir2/dir3/thing7.txt': 'data 7',
89 'dir2/dir3/thing8.txt': 'data 8'}
91 for k, v in files.items():
92 with open(os.path.join(self.mounttmp, k)) as f:
93 self.assertEqual(v, f.read())
96 class FuseNoAPITest(MountTestBase):
98 super(FuseNoAPITest, self).setUp()
99 keep = arvados.keep.KeepClient(local_store=self.keeptmp)
100 self.file_data = "API-free text\n"
101 self.file_loc = keep.put(self.file_data)
102 self.coll_loc = keep.put(". {} 0:{}:api-free.txt\n".format(
103 self.file_loc, len(self.file_data)))
106 self.make_mount(fuse.MagicDirectory)
107 self.assertDirContents(self.coll_loc, ['api-free.txt'])
108 with open(os.path.join(
109 self.mounttmp, self.coll_loc, 'api-free.txt')) as keep_file:
110 actual = keep_file.read(-1)
111 self.assertEqual(self.file_data, actual)
114 class FuseMagicTest(MountTestBase):
115 def setUp(self, api=None):
116 super(FuseMagicTest, self).setUp(api=api)
118 cw = arvados.CollectionWriter()
120 cw.start_new_file('thing1.txt')
123 self.testcollection = cw.finish()
124 self.test_manifest = cw.manifest_text()
125 self.api.collections().create(body={"manifest_text":self.test_manifest}).execute()
128 self.make_mount(fuse.MagicDirectory)
130 mount_ls = llfuse.listdir(self.mounttmp)
131 self.assertIn('README', mount_ls)
132 self.assertFalse(any(arvados.util.keep_locator_pattern.match(fn) or
133 arvados.util.uuid_pattern.match(fn)
135 "new FUSE MagicDirectory lists Collection")
136 self.assertDirContents(self.testcollection, ['thing1.txt'])
137 self.assertDirContents(os.path.join('by_id', self.testcollection),
139 mount_ls = llfuse.listdir(self.mounttmp)
140 self.assertIn('README', mount_ls)
141 self.assertIn(self.testcollection, mount_ls)
142 self.assertIn(self.testcollection,
143 llfuse.listdir(os.path.join(self.mounttmp, 'by_id')))
146 files[os.path.join(self.mounttmp, self.testcollection, 'thing1.txt')] = 'data 1'
148 for k, v in files.items():
149 with open(os.path.join(self.mounttmp, k)) as f:
150 self.assertEqual(v, f.read())
153 class FuseTagsTest(MountTestBase):
155 self.make_mount(fuse.TagsDirectory)
157 d1 = llfuse.listdir(self.mounttmp)
159 self.assertEqual(['foo_tag'], d1)
161 d2 = llfuse.listdir(os.path.join(self.mounttmp, 'foo_tag'))
163 self.assertEqual(['zzzzz-4zz18-fy296fx3hot09f7'], d2)
165 d3 = llfuse.listdir(os.path.join(self.mounttmp, 'foo_tag', 'zzzzz-4zz18-fy296fx3hot09f7'))
167 self.assertEqual(['foo'], d3)
170 class FuseTagsUpdateTest(MountTestBase):
171 def tag_collection(self, coll_uuid, tag_name):
172 return self.api.links().create(
173 body={'link': {'head_uuid': coll_uuid,
179 self.make_mount(fuse.TagsDirectory, poll_time=1)
181 self.assertIn('foo_tag', llfuse.listdir(self.mounttmp))
183 bar_uuid = run_test_server.fixture('collections')['bar_file']['uuid']
184 self.tag_collection(bar_uuid, 'fuse_test_tag')
186 self.assertIn('fuse_test_tag', llfuse.listdir(self.mounttmp))
187 self.assertDirContents('fuse_test_tag', [bar_uuid])
189 baz_uuid = run_test_server.fixture('collections')['baz_file']['uuid']
190 l = self.tag_collection(baz_uuid, 'fuse_test_tag')
192 self.assertDirContents('fuse_test_tag', [bar_uuid, baz_uuid])
194 self.api.links().delete(uuid=l['uuid']).execute()
196 self.assertDirContents('fuse_test_tag', [bar_uuid])
199 class FuseSharedTest(MountTestBase):
201 self.make_mount(fuse.SharedDirectory,
202 exclude=self.api.users().current().execute()['uuid'])
204 # shared_dirs is a list of the directories exposed
205 # by fuse.SharedDirectory (i.e. any object visible
206 # to the current user)
207 shared_dirs = llfuse.listdir(self.mounttmp)
209 self.assertIn('FUSE User', shared_dirs)
211 # fuse_user_objs is a list of the objects owned by the FUSE
212 # test user (which present as files in the 'FUSE User'
214 fuse_user_objs = llfuse.listdir(os.path.join(self.mounttmp, 'FUSE User'))
215 fuse_user_objs.sort()
216 self.assertEqual(['FUSE Test Project', # project owned by user
217 'collection #1 owned by FUSE', # collection owned by user
218 'collection #2 owned by FUSE', # collection owned by user
219 'pipeline instance owned by FUSE.pipelineInstance', # pipeline instance owned by user
222 # test_proj_files is a list of the files in the FUSE Test Project.
223 test_proj_files = llfuse.listdir(os.path.join(self.mounttmp, 'FUSE User', 'FUSE Test Project'))
224 test_proj_files.sort()
225 self.assertEqual(['collection in FUSE project',
226 'pipeline instance in FUSE project.pipelineInstance',
227 'pipeline template in FUSE project.pipelineTemplate'
230 # Double check that we can open and read objects in this folder as a file,
231 # and that its contents are what we expect.
232 pipeline_template_path = os.path.join(
236 'pipeline template in FUSE project.pipelineTemplate')
237 with open(pipeline_template_path) as f:
239 self.assertEqual("pipeline template in FUSE project", j['name'])
241 # check mtime on template
242 st = os.stat(pipeline_template_path)
243 self.assertEqual(st.st_mtime, 1397493304)
245 # check mtime on collection
246 st = os.stat(os.path.join(
249 'collection #1 owned by FUSE'))
250 self.assertEqual(st.st_mtime, 1391448174)
253 class FuseHomeTest(MountTestBase):
255 self.make_mount(fuse.ProjectDirectory,
256 project_object=self.api.users().current().execute())
258 d1 = llfuse.listdir(self.mounttmp)
259 self.assertIn('Unrestricted public data', d1)
261 d2 = llfuse.listdir(os.path.join(self.mounttmp, 'Unrestricted public data'))
262 public_project = run_test_server.fixture('groups')[
263 'anonymously_accessible_project']
266 for name, item in run_test_server.fixture('collections').iteritems():
267 if 'name' not in item:
269 elif item['owner_uuid'] == public_project['uuid']:
270 self.assertIn(item['name'], d2)
273 # Artificial assumption here: there is no public
274 # collection fixture with the same name as a
275 # non-public collection.
276 self.assertNotIn(item['name'], d2)
278 self.assertNotEqual(0, found_in)
279 self.assertNotEqual(0, found_not_in)
281 d3 = llfuse.listdir(os.path.join(self.mounttmp, 'Unrestricted public data', 'GNU General Public License, version 3'))
282 self.assertEqual(["GNU_General_Public_License,_version_3.pdf"], d3)
285 def fuseModifyFileTestHelperReadStartContents(mounttmp):
286 class Test(unittest.TestCase):
288 d1 = llfuse.listdir(mounttmp)
289 self.assertEqual(["file1.txt"], d1)
290 with open(os.path.join(mounttmp, "file1.txt")) as f:
291 self.assertEqual("blub", f.read())
294 def fuseModifyFileTestHelperReadEndContents(mounttmp):
295 class Test(unittest.TestCase):
297 d1 = llfuse.listdir(mounttmp)
298 self.assertEqual(["file1.txt"], d1)
299 with open(os.path.join(mounttmp, "file1.txt")) as f:
300 self.assertEqual("plnp", f.read())
303 class FuseModifyFileTest(MountTestBase):
305 collection = arvados.collection.Collection(api_client=self.api)
306 with collection.open("file1.txt", "w") as f:
309 collection.save_new()
311 m = self.make_mount(fuse.CollectionDirectory)
313 m.new_collection(collection.api_response(), collection)
315 self.pool.apply(fuseModifyFileTestHelperReadStartContents, (self.mounttmp,))
317 with collection.open("file1.txt", "w") as f:
320 self.pool.apply(fuseModifyFileTestHelperReadEndContents, (self.mounttmp,))
323 class FuseAddFileToCollectionTest(MountTestBase):
325 collection = arvados.collection.Collection(api_client=self.api)
326 with collection.open("file1.txt", "w") as f:
329 collection.save_new()
331 m = self.make_mount(fuse.CollectionDirectory)
333 m.new_collection(collection.api_response(), collection)
335 d1 = llfuse.listdir(self.mounttmp)
336 self.assertEqual(["file1.txt"], d1)
338 with collection.open("file2.txt", "w") as f:
341 d1 = llfuse.listdir(self.mounttmp)
342 self.assertEqual(["file1.txt", "file2.txt"], sorted(d1))
345 class FuseRemoveFileFromCollectionTest(MountTestBase):
347 collection = arvados.collection.Collection(api_client=self.api)
348 with collection.open("file1.txt", "w") as f:
351 with collection.open("file2.txt", "w") as f:
354 collection.save_new()
356 m = self.make_mount(fuse.CollectionDirectory)
358 m.new_collection(collection.api_response(), collection)
360 d1 = llfuse.listdir(self.mounttmp)
361 self.assertEqual(["file1.txt", "file2.txt"], sorted(d1))
363 collection.remove("file2.txt")
365 d1 = llfuse.listdir(self.mounttmp)
366 self.assertEqual(["file1.txt"], d1)
369 def fuseCreateFileTestHelper(mounttmp):
370 class Test(unittest.TestCase):
372 with open(os.path.join(mounttmp, "file1.txt"), "w") as f:
376 class FuseCreateFileTest(MountTestBase):
378 collection = arvados.collection.Collection(api_client=self.api)
379 collection.save_new()
381 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
382 self.assertEqual(collection2["manifest_text"], "")
384 collection.save_new()
386 m = self.make_mount(fuse.CollectionDirectory)
388 m.new_collection(collection.api_response(), collection)
389 self.assertTrue(m.writable())
391 self.assertNotIn("file1.txt", collection)
393 self.pool.apply(fuseCreateFileTestHelper, (self.mounttmp,))
395 self.assertIn("file1.txt", collection)
397 d1 = llfuse.listdir(self.mounttmp)
398 self.assertEqual(["file1.txt"], d1)
400 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
401 self.assertRegexpMatches(collection2["manifest_text"],
402 r'\. d41d8cd98f00b204e9800998ecf8427e\+0\+A\S+ 0:0:file1\.txt$')
405 def fuseWriteFileTestHelperWriteFile(mounttmp):
406 class Test(unittest.TestCase):
408 with open(os.path.join(mounttmp, "file1.txt"), "w") as f:
409 f.write("Hello world!")
412 def fuseWriteFileTestHelperReadFile(mounttmp):
413 class Test(unittest.TestCase):
415 with open(os.path.join(mounttmp, "file1.txt"), "r") as f:
416 self.assertEqual(f.read(), "Hello world!")
419 class FuseWriteFileTest(MountTestBase):
421 collection = arvados.collection.Collection(api_client=self.api)
422 collection.save_new()
424 m = self.make_mount(fuse.CollectionDirectory)
426 m.new_collection(collection.api_response(), collection)
427 self.assertTrue(m.writable())
429 self.assertNotIn("file1.txt", collection)
431 self.assertEqual(0, self.operations.write_counter.get())
432 self.pool.apply(fuseWriteFileTestHelperWriteFile, (self.mounttmp,))
433 self.assertEqual(12, self.operations.write_counter.get())
435 with collection.open("file1.txt") as f:
436 self.assertEqual(f.read(), "Hello world!")
438 self.assertEqual(0, self.operations.read_counter.get())
439 self.pool.apply(fuseWriteFileTestHelperReadFile, (self.mounttmp,))
440 self.assertEqual(12, self.operations.read_counter.get())
442 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
443 self.assertRegexpMatches(collection2["manifest_text"],
444 r'\. 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
447 def fuseUpdateFileTestHelper(mounttmp):
448 class Test(unittest.TestCase):
450 with open(os.path.join(mounttmp, "file1.txt"), "w") as f:
451 f.write("Hello world!")
453 with open(os.path.join(mounttmp, "file1.txt"), "r+") as f:
455 self.assertEqual(fr, "Hello world!")
457 f.write("Hola mundo!")
460 self.assertEqual(fr, "Hola mundo!!")
462 with open(os.path.join(mounttmp, "file1.txt"), "r") as f:
463 self.assertEqual(f.read(), "Hola mundo!!")
467 class FuseUpdateFileTest(MountTestBase):
469 collection = arvados.collection.Collection(api_client=self.api)
470 collection.save_new()
472 m = self.make_mount(fuse.CollectionDirectory)
474 m.new_collection(collection.api_response(), collection)
475 self.assertTrue(m.writable())
477 # See note in MountTestBase.setUp
478 self.pool.apply(fuseUpdateFileTestHelper, (self.mounttmp,))
480 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
481 self.assertRegexpMatches(collection2["manifest_text"],
482 r'\. daaef200ebb921e011e3ae922dd3266b\+11\+A\S+ 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:11:file1\.txt 22:1:file1\.txt$')
485 def fuseMkdirTestHelper(mounttmp):
486 class Test(unittest.TestCase):
488 with self.assertRaises(IOError):
489 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
490 f.write("Hello world!")
492 os.mkdir(os.path.join(mounttmp, "testdir"))
494 with self.assertRaises(OSError):
495 os.mkdir(os.path.join(mounttmp, "testdir"))
497 d1 = llfuse.listdir(mounttmp)
498 self.assertEqual(["testdir"], d1)
500 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
501 f.write("Hello world!")
503 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
504 self.assertEqual(["file1.txt"], d1)
508 class FuseMkdirTest(MountTestBase):
510 collection = arvados.collection.Collection(api_client=self.api)
511 collection.save_new()
513 m = self.make_mount(fuse.CollectionDirectory)
515 m.new_collection(collection.api_response(), collection)
516 self.assertTrue(m.writable())
518 self.pool.apply(fuseMkdirTestHelper, (self.mounttmp,))
520 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
521 self.assertRegexpMatches(collection2["manifest_text"],
522 r'\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
525 def fuseRmTestHelperWriteFile(mounttmp):
526 class Test(unittest.TestCase):
528 os.mkdir(os.path.join(mounttmp, "testdir"))
530 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
531 f.write("Hello world!")
535 def fuseRmTestHelperDeleteFile(mounttmp):
536 class Test(unittest.TestCase):
538 # Can't delete because it's not empty
539 with self.assertRaises(OSError):
540 os.rmdir(os.path.join(mounttmp, "testdir"))
542 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
543 self.assertEqual(["file1.txt"], d1)
546 os.remove(os.path.join(mounttmp, "testdir", "file1.txt"))
548 # Make sure it's empty
549 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
550 self.assertEqual([], d1)
552 # Try to delete it again
553 with self.assertRaises(OSError):
554 os.remove(os.path.join(mounttmp, "testdir", "file1.txt"))
558 def fuseRmTestHelperRmdir(mounttmp):
559 class Test(unittest.TestCase):
561 # Should be able to delete now that it is empty
562 os.rmdir(os.path.join(mounttmp, "testdir"))
564 # Make sure it's empty
565 d1 = llfuse.listdir(os.path.join(mounttmp))
566 self.assertEqual([], d1)
568 # Try to delete it again
569 with self.assertRaises(OSError):
570 os.rmdir(os.path.join(mounttmp, "testdir"))
574 class FuseRmTest(MountTestBase):
576 collection = arvados.collection.Collection(api_client=self.api)
577 collection.save_new()
579 m = self.make_mount(fuse.CollectionDirectory)
581 m.new_collection(collection.api_response(), collection)
582 self.assertTrue(m.writable())
584 self.pool.apply(fuseRmTestHelperWriteFile, (self.mounttmp,))
587 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
588 self.assertRegexpMatches(collection2["manifest_text"],
589 r'\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
590 self.pool.apply(fuseRmTestHelperDeleteFile, (self.mounttmp,))
592 # Can't have empty directories :-( so manifest will be empty.
593 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
594 self.assertEqual(collection2["manifest_text"], "")
596 self.pool.apply(fuseRmTestHelperRmdir, (self.mounttmp,))
598 # manifest should be empty now.
599 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
600 self.assertEqual(collection2["manifest_text"], "")
603 def fuseMvFileTestHelperWriteFile(mounttmp):
604 class Test(unittest.TestCase):
606 os.mkdir(os.path.join(mounttmp, "testdir"))
608 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
609 f.write("Hello world!")
613 def fuseMvFileTestHelperMoveFile(mounttmp):
614 class Test(unittest.TestCase):
616 d1 = llfuse.listdir(os.path.join(mounttmp))
617 self.assertEqual(["testdir"], d1)
618 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
619 self.assertEqual(["file1.txt"], d1)
621 os.rename(os.path.join(mounttmp, "testdir", "file1.txt"), os.path.join(mounttmp, "file1.txt"))
623 d1 = llfuse.listdir(os.path.join(mounttmp))
624 self.assertEqual(["file1.txt", "testdir"], sorted(d1))
625 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
626 self.assertEqual([], d1)
630 class FuseMvFileTest(MountTestBase):
632 collection = arvados.collection.Collection(api_client=self.api)
633 collection.save_new()
635 m = self.make_mount(fuse.CollectionDirectory)
637 m.new_collection(collection.api_response(), collection)
638 self.assertTrue(m.writable())
640 self.pool.apply(fuseMvFileTestHelperWriteFile, (self.mounttmp,))
643 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
644 self.assertRegexpMatches(collection2["manifest_text"],
645 r'\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
647 self.pool.apply(fuseMvFileTestHelperMoveFile, (self.mounttmp,))
649 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
650 self.assertRegexpMatches(collection2["manifest_text"],
651 r'\. 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
654 def fuseRenameTestHelper(mounttmp):
655 class Test(unittest.TestCase):
657 os.mkdir(os.path.join(mounttmp, "testdir"))
659 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
660 f.write("Hello world!")
664 class FuseRenameTest(MountTestBase):
666 collection = arvados.collection.Collection(api_client=self.api)
667 collection.save_new()
669 m = self.make_mount(fuse.CollectionDirectory)
671 m.new_collection(collection.api_response(), collection)
672 self.assertTrue(m.writable())
674 self.pool.apply(fuseRenameTestHelper, (self.mounttmp,))
677 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
678 self.assertRegexpMatches(collection2["manifest_text"],
679 r'\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
681 d1 = llfuse.listdir(os.path.join(self.mounttmp))
682 self.assertEqual(["testdir"], d1)
683 d1 = llfuse.listdir(os.path.join(self.mounttmp, "testdir"))
684 self.assertEqual(["file1.txt"], d1)
686 os.rename(os.path.join(self.mounttmp, "testdir"), os.path.join(self.mounttmp, "testdir2"))
688 d1 = llfuse.listdir(os.path.join(self.mounttmp))
689 self.assertEqual(["testdir2"], sorted(d1))
690 d1 = llfuse.listdir(os.path.join(self.mounttmp, "testdir2"))
691 self.assertEqual(["file1.txt"], d1)
693 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
694 self.assertRegexpMatches(collection2["manifest_text"],
695 r'\./testdir2 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
698 class FuseUpdateFromEventTest(MountTestBase):
700 collection = arvados.collection.Collection(api_client=self.api)
701 collection.save_new()
703 m = self.make_mount(fuse.CollectionDirectory)
705 m.new_collection(collection.api_response(), collection)
707 self.operations.listen_for_events()
709 d1 = llfuse.listdir(os.path.join(self.mounttmp))
710 self.assertEqual([], sorted(d1))
712 with arvados.collection.Collection(collection.manifest_locator(), api_client=self.api) as collection2:
713 with collection2.open("file1.txt", "w") as f:
716 # should show up in <10s via event bus notify
717 expect = ["file1.txt"]
719 d1 = sorted(llfuse.listdir(os.path.join(self.mounttmp)))
724 self.assertEqual(expect, d1)
727 def fuseFileConflictTestHelper(mounttmp):
728 class Test(unittest.TestCase):
730 with open(os.path.join(mounttmp, "file1.txt"), "w") as f:
733 d1 = sorted(llfuse.listdir(os.path.join(mounttmp)))
734 self.assertEqual(len(d1), 2)
736 with open(os.path.join(mounttmp, "file1.txt"), "r") as f:
737 self.assertEqual(f.read(), "bar")
739 self.assertRegexpMatches(d1[1],
740 r'file1\.txt~\d\d\d\d\d\d\d\d-\d\d\d\d\d\d~conflict~')
742 with open(os.path.join(mounttmp, d1[1]), "r") as f:
743 self.assertEqual(f.read(), "foo")
747 class FuseFileConflictTest(MountTestBase):
749 collection = arvados.collection.Collection(api_client=self.api)
750 collection.save_new()
752 m = self.make_mount(fuse.CollectionDirectory)
754 m.new_collection(collection.api_response(), collection)
756 d1 = llfuse.listdir(os.path.join(self.mounttmp))
757 self.assertEqual([], sorted(d1))
759 with arvados.collection.Collection(collection.manifest_locator(), api_client=self.api) as collection2:
760 with collection2.open("file1.txt", "w") as f:
763 # See note in MountTestBase.setUp
764 self.pool.apply(fuseFileConflictTestHelper, (self.mounttmp,))
767 def fuseUnlinkOpenFileTest(mounttmp):
768 class Test(unittest.TestCase):
770 with open(os.path.join(mounttmp, "file1.txt"), "w+") as f:
773 d1 = llfuse.listdir(os.path.join(mounttmp))
774 self.assertEqual(["file1.txt"], sorted(d1))
776 os.remove(os.path.join(mounttmp, "file1.txt"))
778 d1 = llfuse.listdir(os.path.join(mounttmp))
779 self.assertEqual([], sorted(d1))
782 self.assertEqual(f.read(), "foo")
786 self.assertEqual(f.read(), "foobar")
790 class FuseUnlinkOpenFileTest(MountTestBase):
792 collection = arvados.collection.Collection(api_client=self.api)
793 collection.save_new()
795 m = self.make_mount(fuse.CollectionDirectory)
797 m.new_collection(collection.api_response(), collection)
799 # See note in MountTestBase.setUp
800 self.pool.apply(fuseUnlinkOpenFileTest, (self.mounttmp,))
802 self.assertEqual(collection.manifest_text(), "")
805 def fuseMvFileBetweenCollectionsTest1(mounttmp, uuid1, uuid2):
806 class Test(unittest.TestCase):
808 with open(os.path.join(mounttmp, uuid1, "file1.txt"), "w") as f:
809 f.write("Hello world!")
811 d1 = os.listdir(os.path.join(mounttmp, uuid1))
812 self.assertEqual(["file1.txt"], sorted(d1))
813 d1 = os.listdir(os.path.join(mounttmp, uuid2))
814 self.assertEqual([], sorted(d1))
818 def fuseMvFileBetweenCollectionsTest2(mounttmp, uuid1, uuid2):
819 class Test(unittest.TestCase):
821 os.rename(os.path.join(mounttmp, uuid1, "file1.txt"), os.path.join(mounttmp, uuid2, "file2.txt"))
823 d1 = os.listdir(os.path.join(mounttmp, uuid1))
824 self.assertEqual([], sorted(d1))
825 d1 = os.listdir(os.path.join(mounttmp, uuid2))
826 self.assertEqual(["file2.txt"], sorted(d1))
830 class FuseMvFileBetweenCollectionsTest(MountTestBase):
832 collection1 = arvados.collection.Collection(api_client=self.api)
833 collection1.save_new()
835 collection2 = arvados.collection.Collection(api_client=self.api)
836 collection2.save_new()
838 m = self.make_mount(fuse.MagicDirectory)
840 # See note in MountTestBase.setUp
841 self.pool.apply(fuseMvFileBetweenCollectionsTest1, (self.mounttmp,
842 collection1.manifest_locator(),
843 collection2.manifest_locator()))
848 self.assertRegexpMatches(collection1.manifest_text(), r"\. 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$")
849 self.assertEqual(collection2.manifest_text(), "")
851 self.pool.apply(fuseMvFileBetweenCollectionsTest2, (self.mounttmp,
852 collection1.manifest_locator(),
853 collection2.manifest_locator()))
858 self.assertEqual(collection1.manifest_text(), "")
859 self.assertRegexpMatches(collection2.manifest_text(), r"\. 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file2\.txt$")
861 collection1.stop_threads()
862 collection2.stop_threads()
865 def fuseMvDirBetweenCollectionsTest1(mounttmp, uuid1, uuid2):
866 class Test(unittest.TestCase):
868 os.mkdir(os.path.join(mounttmp, uuid1, "testdir"))
869 with open(os.path.join(mounttmp, uuid1, "testdir", "file1.txt"), "w") as f:
870 f.write("Hello world!")
872 d1 = os.listdir(os.path.join(mounttmp, uuid1))
873 self.assertEqual(["testdir"], sorted(d1))
874 d1 = os.listdir(os.path.join(mounttmp, uuid1, "testdir"))
875 self.assertEqual(["file1.txt"], sorted(d1))
877 d1 = os.listdir(os.path.join(mounttmp, uuid2))
878 self.assertEqual([], sorted(d1))
883 def fuseMvDirBetweenCollectionsTest2(mounttmp, uuid1, uuid2):
884 class Test(unittest.TestCase):
886 os.rename(os.path.join(mounttmp, uuid1, "testdir"), os.path.join(mounttmp, uuid2, "testdir2"))
888 d1 = os.listdir(os.path.join(mounttmp, uuid1))
889 self.assertEqual([], sorted(d1))
891 d1 = os.listdir(os.path.join(mounttmp, uuid2))
892 self.assertEqual(["testdir2"], sorted(d1))
893 d1 = os.listdir(os.path.join(mounttmp, uuid2, "testdir2"))
894 self.assertEqual(["file1.txt"], sorted(d1))
896 with open(os.path.join(mounttmp, uuid2, "testdir2", "file1.txt"), "r") as f:
897 self.assertEqual(f.read(), "Hello world!")
901 class FuseMvDirBetweenCollectionsTest(MountTestBase):
903 collection1 = arvados.collection.Collection(api_client=self.api)
904 collection1.save_new()
906 collection2 = arvados.collection.Collection(api_client=self.api)
907 collection2.save_new()
909 m = self.make_mount(fuse.MagicDirectory)
911 # See note in MountTestBase.setUp
912 self.pool.apply(fuseMvDirBetweenCollectionsTest1, (self.mounttmp,
913 collection1.manifest_locator(),
914 collection2.manifest_locator()))
919 self.assertRegexpMatches(collection1.manifest_text(), r"\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$")
920 self.assertEqual(collection2.manifest_text(), "")
922 self.pool.apply(fuseMvDirBetweenCollectionsTest2, (self.mounttmp,
923 collection1.manifest_locator(),
924 collection2.manifest_locator()))
929 self.assertEqual(collection1.manifest_text(), "")
930 self.assertRegexpMatches(collection2.manifest_text(), r"\./testdir2 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$")
932 collection1.stop_threads()
933 collection2.stop_threads()
935 def fuseProjectMkdirTestHelper1(mounttmp):
936 class Test(unittest.TestCase):
938 os.mkdir(os.path.join(mounttmp, "testcollection"))
939 with self.assertRaises(OSError):
940 os.mkdir(os.path.join(mounttmp, "testcollection"))
943 def fuseProjectMkdirTestHelper2(mounttmp):
944 class Test(unittest.TestCase):
946 with open(os.path.join(mounttmp, "testcollection", "file1.txt"), "w") as f:
947 f.write("Hello world!")
948 with self.assertRaises(OSError):
949 os.rmdir(os.path.join(mounttmp, "testcollection"))
950 os.remove(os.path.join(mounttmp, "testcollection", "file1.txt"))
951 with self.assertRaises(OSError):
952 os.remove(os.path.join(mounttmp, "testcollection"))
953 os.rmdir(os.path.join(mounttmp, "testcollection"))
956 class FuseProjectMkdirRmdirTest(MountTestBase):
958 self.make_mount(fuse.ProjectDirectory,
959 project_object=self.api.users().current().execute())
961 d1 = llfuse.listdir(self.mounttmp)
962 self.assertNotIn('testcollection', d1)
964 self.pool.apply(fuseProjectMkdirTestHelper1, (self.mounttmp,))
966 d1 = llfuse.listdir(self.mounttmp)
967 self.assertIn('testcollection', d1)
969 self.pool.apply(fuseProjectMkdirTestHelper2, (self.mounttmp,))
971 d1 = llfuse.listdir(self.mounttmp)
972 self.assertNotIn('testcollection', d1)
975 def fuseProjectMvTestHelper1(mounttmp):
976 class Test(unittest.TestCase):
978 d1 = llfuse.listdir(mounttmp)
979 self.assertNotIn('testcollection', d1)
981 os.mkdir(os.path.join(mounttmp, "testcollection"))
983 d1 = llfuse.listdir(mounttmp)
984 self.assertIn('testcollection', d1)
986 with self.assertRaises(OSError):
987 os.rename(os.path.join(mounttmp, "testcollection"), os.path.join(mounttmp, 'Unrestricted public data'))
989 os.rename(os.path.join(mounttmp, "testcollection"), os.path.join(mounttmp, 'Unrestricted public data', 'testcollection'))
991 d1 = llfuse.listdir(mounttmp)
992 self.assertNotIn('testcollection', d1)
994 d1 = llfuse.listdir(os.path.join(mounttmp, 'Unrestricted public data'))
995 self.assertIn('testcollection', d1)
999 class FuseProjectMvTest(MountTestBase):
1001 self.make_mount(fuse.ProjectDirectory,
1002 project_object=self.api.users().current().execute())
1004 self.pool.apply(fuseProjectMvTestHelper1, (self.mounttmp,))
1007 def fuseFsyncTestHelper(mounttmp, k):
1008 class Test(unittest.TestCase):
1010 fd = os.open(os.path.join(mounttmp, k), os.O_RDONLY)
1016 class FuseFsyncTest(FuseMagicTest):
1018 self.make_mount(fuse.MagicDirectory)
1019 self.pool.apply(fuseFsyncTestHelper, (self.mounttmp, self.testcollection))
1022 class MagicDirApiError(FuseMagicTest):
1024 api = mock.MagicMock()
1025 super(MagicDirApiError, self).setUp(api=api)
1026 api.collections().get().execute.side_effect = iter([Exception('API fail'), {"manifest_text": self.test_manifest}])
1027 api.keep.get.side_effect = Exception('Keep fail')
1030 self.make_mount(fuse.MagicDirectory)
1032 self.operations.inodes.inode_cache.cap = 1
1033 self.operations.inodes.inode_cache.min_entries = 2
1035 with self.assertRaises(OSError):
1036 llfuse.listdir(os.path.join(self.mounttmp, self.testcollection))
1038 llfuse.listdir(os.path.join(self.mounttmp, self.testcollection))
1041 class FuseUnitTest(unittest.TestCase):
1042 def test_sanitize_filename(self):
1061 for f in acceptable:
1062 self.assertEqual(f, fuse.sanitize_filename(f))
1063 for f in unacceptable:
1064 self.assertNotEqual(f, fuse.sanitize_filename(f))
1065 # The sanitized filename should be the same length, though.
1066 self.assertEqual(len(f), len(fuse.sanitize_filename(f)))
1068 self.assertEqual("_", fuse.sanitize_filename(""))
1069 self.assertEqual("_", fuse.sanitize_filename("."))
1070 self.assertEqual("__", fuse.sanitize_filename(".."))
1073 class FuseMagicTestPDHOnly(MountTestBase):
1074 def setUp(self, api=None):
1075 super(FuseMagicTestPDHOnly, self).setUp(api=api)
1077 cw = arvados.CollectionWriter()
1079 cw.start_new_file('thing1.txt')
1082 self.testcollection = cw.finish()
1083 self.test_manifest = cw.manifest_text()
1084 created = self.api.collections().create(body={"manifest_text":self.test_manifest}).execute()
1085 self.testcollectionuuid = str(created['uuid'])
1087 def verify_pdh_only(self, pdh_only=False, skip_pdh_only=False):
1088 if skip_pdh_only is True:
1089 self.make_mount(fuse.MagicDirectory) # in this case, the default by_id applies
1091 self.make_mount(fuse.MagicDirectory, pdh_only=pdh_only)
1093 mount_ls = llfuse.listdir(self.mounttmp)
1094 self.assertIn('README', mount_ls)
1095 self.assertFalse(any(arvados.util.keep_locator_pattern.match(fn) or
1096 arvados.util.uuid_pattern.match(fn)
1097 for fn in mount_ls),
1098 "new FUSE MagicDirectory lists Collection")
1100 # look up using pdh should succeed in all cases
1101 self.assertDirContents(self.testcollection, ['thing1.txt'])
1102 self.assertDirContents(os.path.join('by_id', self.testcollection),
1104 mount_ls = llfuse.listdir(self.mounttmp)
1105 self.assertIn('README', mount_ls)
1106 self.assertIn(self.testcollection, mount_ls)
1107 self.assertIn(self.testcollection,
1108 llfuse.listdir(os.path.join(self.mounttmp, 'by_id')))
1111 files[os.path.join(self.mounttmp, self.testcollection, 'thing1.txt')] = 'data 1'
1113 for k, v in files.items():
1114 with open(os.path.join(self.mounttmp, k)) as f:
1115 self.assertEqual(v, f.read())
1117 # look up using uuid should fail when pdh_only is set
1118 if pdh_only is True:
1119 with self.assertRaises(OSError):
1120 self.assertDirContents(os.path.join('by_id', self.testcollectionuuid),
1123 self.assertDirContents(os.path.join('by_id', self.testcollectionuuid),
1126 def test_with_pdh_only_true(self):
1127 self.verify_pdh_only(pdh_only=True)
1129 def test_with_pdh_only_false(self):
1130 self.verify_pdh_only(pdh_only=False)
1132 def test_with_default_by_id(self):
1133 self.verify_pdh_only(skip_pdh_only=True)
1135 def _test_refresh_old_manifest(zzz):
1136 fnm = 'zzzzz-8i9sb-0vsrcqi7whchuil.log.txt'
1137 os.listdir(os.path.join(zzz))
1139 with open(os.path.join(zzz, fnm)) as f:
1142 class TokenExpiryTest(MountTestBase):
1144 super(TokenExpiryTest, self).setUp(local_store=False)
1146 @mock.patch('arvados.keep.KeepClient.get')
1147 def runTest(self, mocked_get):
1148 self.api._rootDesc = {"blobSignatureTtl": 2}
1149 mnt = self.make_mount(fuse.CollectionDirectory, collection_record='zzzzz-4zz18-op4e2lbej01tcvu')
1150 mocked_get.return_value = 'fake data'
1152 old_exp = int(time.time()) + 86400*14
1153 self.pool.apply(_test_refresh_old_manifest, (self.mounttmp,))
1154 want_exp = int(time.time()) + 86400*14
1156 got_loc = mocked_get.call_args[0][0]
1158 re.search(r'\+A[0-9a-f]+@([0-9a-f]+)', got_loc).group(1),
1160 self.assertGreaterEqual(
1161 got_exp, want_exp-2,
1162 msg='now+2w = {:x}, but fuse fetched locator {} (old_exp {:x})'.format(
1163 want_exp, got_loc, old_exp))
1164 self.assertLessEqual(
1166 msg='server is not using the expected 2w TTL; test is ineffective')