1 # Copyright (C) The Arvados Authors. All rights reserved.
3 # SPDX-License-Identifier: AGPL-3.0
15 import arvados_fuse as fuse
16 import run_test_server
18 from mount_test_base import MountTestBase
20 logger = logging.getLogger('arvados.arv-mount')
23 class AssertWithTimeout(object):
24 """Allow some time for an assertion to pass."""
26 def __init__(self, timeout=0):
27 self.timeout = timeout
30 self.deadline = time.time() + self.timeout
39 def attempt(self, fn, *args, **kwargs):
42 except AssertionError:
43 if time.time() > self.deadline:
50 class FuseMountTest(MountTestBase):
52 super(FuseMountTest, self).setUp()
54 cw = arvados.CollectionWriter()
56 cw.start_new_file('thing1.txt')
58 cw.start_new_file('thing2.txt')
61 cw.start_new_stream('dir1')
62 cw.start_new_file('thing3.txt')
64 cw.start_new_file('thing4.txt')
67 cw.start_new_stream('dir2')
68 cw.start_new_file('thing5.txt')
70 cw.start_new_file('thing6.txt')
73 cw.start_new_stream('dir2/dir3')
74 cw.start_new_file('thing7.txt')
77 cw.start_new_file('thing8.txt')
80 cw.start_new_stream('edgecases')
81 for f in ":/.../-/*/\x01\\/ ".split("/"):
85 for f in ":/.../-/*/\x01\\/ ".split("/"):
86 cw.start_new_stream('edgecases/dirs/' + f)
87 cw.start_new_file('x/x')
90 self.testcollection = cw.finish()
91 self.api.collections().create(body={"manifest_text":cw.manifest_text()}).execute()
94 self.make_mount(fuse.CollectionDirectory, collection_record=self.testcollection)
96 self.assertDirContents(None, ['thing1.txt', 'thing2.txt',
97 'edgecases', 'dir1', 'dir2'])
98 self.assertDirContents('dir1', ['thing3.txt', 'thing4.txt'])
99 self.assertDirContents('dir2', ['thing5.txt', 'thing6.txt', 'dir3'])
100 self.assertDirContents('dir2/dir3', ['thing7.txt', 'thing8.txt'])
101 self.assertDirContents('edgecases',
102 "dirs/:/.../-/*/\x01\\/ ".split("/"))
103 self.assertDirContents('edgecases/dirs',
104 ":/.../-/*/\x01\\/ ".split("/"))
106 files = {'thing1.txt': 'data 1',
107 'thing2.txt': 'data 2',
108 'dir1/thing3.txt': 'data 3',
109 'dir1/thing4.txt': 'data 4',
110 'dir2/thing5.txt': 'data 5',
111 'dir2/thing6.txt': 'data 6',
112 'dir2/dir3/thing7.txt': 'data 7',
113 'dir2/dir3/thing8.txt': 'data 8'}
115 for k, v in files.items():
116 with open(os.path.join(self.mounttmp, k)) as f:
117 self.assertEqual(v, f.read())
120 class FuseMagicTest(MountTestBase):
121 def setUp(self, api=None):
122 super(FuseMagicTest, self).setUp(api=api)
124 cw = arvados.CollectionWriter()
126 cw.start_new_file('thing1.txt')
129 self.testcollection = cw.finish()
130 self.test_manifest = cw.manifest_text()
131 coll = self.api.collections().create(body={"manifest_text":self.test_manifest}).execute()
132 self.test_manifest_pdh = coll['portable_data_hash']
135 self.make_mount(fuse.MagicDirectory)
137 mount_ls = llfuse.listdir(self.mounttmp)
138 self.assertIn('README', mount_ls)
139 self.assertFalse(any(arvados.util.keep_locator_pattern.match(fn) or
140 arvados.util.uuid_pattern.match(fn)
142 "new FUSE MagicDirectory lists Collection")
143 self.assertDirContents(self.testcollection, ['thing1.txt'])
144 self.assertDirContents(os.path.join('by_id', self.testcollection),
146 mount_ls = llfuse.listdir(self.mounttmp)
147 self.assertIn('README', mount_ls)
148 self.assertIn(self.testcollection, mount_ls)
149 self.assertIn(self.testcollection,
150 llfuse.listdir(os.path.join(self.mounttmp, 'by_id')))
153 files[os.path.join(self.mounttmp, self.testcollection, 'thing1.txt')] = 'data 1'
155 for k, v in files.items():
156 with open(os.path.join(self.mounttmp, k)) as f:
157 self.assertEqual(v, f.read())
160 class FuseTagsTest(MountTestBase):
162 self.make_mount(fuse.TagsDirectory)
164 d1 = llfuse.listdir(self.mounttmp)
166 self.assertEqual(['foo_tag'], d1)
168 d2 = llfuse.listdir(os.path.join(self.mounttmp, 'foo_tag'))
170 self.assertEqual(['zzzzz-4zz18-fy296fx3hot09f7'], d2)
172 d3 = llfuse.listdir(os.path.join(self.mounttmp, 'foo_tag', 'zzzzz-4zz18-fy296fx3hot09f7'))
174 self.assertEqual(['foo'], d3)
177 class FuseTagsUpdateTest(MountTestBase):
178 def tag_collection(self, coll_uuid, tag_name):
179 return self.api.links().create(
180 body={'link': {'head_uuid': coll_uuid,
186 self.make_mount(fuse.TagsDirectory, poll_time=1)
188 self.assertIn('foo_tag', llfuse.listdir(self.mounttmp))
190 bar_uuid = run_test_server.fixture('collections')['bar_file']['uuid']
191 self.tag_collection(bar_uuid, 'fuse_test_tag')
192 for attempt in AssertWithTimeout(10):
193 attempt(self.assertIn, 'fuse_test_tag', llfuse.listdir(self.mounttmp))
194 self.assertDirContents('fuse_test_tag', [bar_uuid])
196 baz_uuid = run_test_server.fixture('collections')['baz_file']['uuid']
197 l = self.tag_collection(baz_uuid, 'fuse_test_tag')
198 for attempt in AssertWithTimeout(10):
199 attempt(self.assertDirContents, 'fuse_test_tag', [bar_uuid, baz_uuid])
201 self.api.links().delete(uuid=l['uuid']).execute()
202 for attempt in AssertWithTimeout(10):
203 attempt(self.assertDirContents, 'fuse_test_tag', [bar_uuid])
206 def fuseSharedTestHelper(mounttmp):
207 class Test(unittest.TestCase):
209 # Double check that we can open and read objects in this folder as a file,
210 # and that its contents are what we expect.
211 baz_path = os.path.join(
215 'collection in FUSE project',
217 with open(baz_path) as f:
218 self.assertEqual("baz", f.read())
220 # check mtime on collection
221 st = os.stat(baz_path)
223 mtime = st.st_mtime_ns / 1000000000
224 except AttributeError:
226 self.assertEqual(mtime, 1391448174)
228 # shared_dirs is a list of the directories exposed
229 # by fuse.SharedDirectory (i.e. any object visible
230 # to the current user)
231 shared_dirs = llfuse.listdir(mounttmp)
233 self.assertIn('FUSE User', shared_dirs)
235 # fuse_user_objs is a list of the objects owned by the FUSE
236 # test user (which present as files in the 'FUSE User'
238 fuse_user_objs = llfuse.listdir(os.path.join(mounttmp, 'FUSE User'))
239 fuse_user_objs.sort()
240 self.assertEqual(['FUSE Test Project', # project owned by user
241 'collection #1 owned by FUSE', # collection owned by user
242 'collection #2 owned by FUSE' # collection owned by user
245 # test_proj_files is a list of the files in the FUSE Test Project.
246 test_proj_files = llfuse.listdir(os.path.join(mounttmp, 'FUSE User', 'FUSE Test Project'))
247 test_proj_files.sort()
248 self.assertEqual(['collection in FUSE project'
254 class FuseSharedTest(MountTestBase):
256 self.make_mount(fuse.SharedDirectory,
257 exclude=self.api.users().current().execute()['uuid'])
258 keep = arvados.keep.KeepClient()
261 self.pool.apply(fuseSharedTestHelper, (self.mounttmp,))
264 class FuseHomeTest(MountTestBase):
266 self.make_mount(fuse.ProjectDirectory,
267 project_object=self.api.users().current().execute())
269 d1 = llfuse.listdir(self.mounttmp)
270 self.assertIn('Unrestricted public data', d1)
272 d2 = llfuse.listdir(os.path.join(self.mounttmp, 'Unrestricted public data'))
273 public_project = run_test_server.fixture('groups')[
274 'anonymously_accessible_project']
277 for name, item in run_test_server.fixture('collections').iteritems():
278 if 'name' not in item:
280 elif item['owner_uuid'] == public_project['uuid']:
281 self.assertIn(item['name'], d2)
284 # Artificial assumption here: there is no public
285 # collection fixture with the same name as a
286 # non-public collection.
287 self.assertNotIn(item['name'], d2)
289 self.assertNotEqual(0, found_in)
290 self.assertNotEqual(0, found_not_in)
292 d3 = llfuse.listdir(os.path.join(self.mounttmp, 'Unrestricted public data', 'GNU General Public License, version 3'))
293 self.assertEqual(["GNU_General_Public_License,_version_3.pdf"], d3)
296 def fuseModifyFileTestHelperReadStartContents(mounttmp):
297 class Test(unittest.TestCase):
299 d1 = llfuse.listdir(mounttmp)
300 self.assertEqual(["file1.txt"], d1)
301 with open(os.path.join(mounttmp, "file1.txt")) as f:
302 self.assertEqual("blub", f.read())
305 def fuseModifyFileTestHelperReadEndContents(mounttmp):
306 class Test(unittest.TestCase):
308 d1 = llfuse.listdir(mounttmp)
309 self.assertEqual(["file1.txt"], d1)
310 with open(os.path.join(mounttmp, "file1.txt")) as f:
311 self.assertEqual("plnp", f.read())
314 class FuseModifyFileTest(MountTestBase):
316 collection = arvados.collection.Collection(api_client=self.api)
317 with collection.open("file1.txt", "w") as f:
320 collection.save_new()
322 m = self.make_mount(fuse.CollectionDirectory)
324 m.new_collection(collection.api_response(), collection)
326 self.pool.apply(fuseModifyFileTestHelperReadStartContents, (self.mounttmp,))
328 with collection.open("file1.txt", "w") as f:
331 self.pool.apply(fuseModifyFileTestHelperReadEndContents, (self.mounttmp,))
334 class FuseAddFileToCollectionTest(MountTestBase):
336 collection = arvados.collection.Collection(api_client=self.api)
337 with collection.open("file1.txt", "w") as f:
340 collection.save_new()
342 m = self.make_mount(fuse.CollectionDirectory)
344 m.new_collection(collection.api_response(), collection)
346 d1 = llfuse.listdir(self.mounttmp)
347 self.assertEqual(["file1.txt"], d1)
349 with collection.open("file2.txt", "w") as f:
352 d1 = llfuse.listdir(self.mounttmp)
353 self.assertEqual(["file1.txt", "file2.txt"], sorted(d1))
356 class FuseRemoveFileFromCollectionTest(MountTestBase):
358 collection = arvados.collection.Collection(api_client=self.api)
359 with collection.open("file1.txt", "w") as f:
362 with collection.open("file2.txt", "w") as f:
365 collection.save_new()
367 m = self.make_mount(fuse.CollectionDirectory)
369 m.new_collection(collection.api_response(), collection)
371 d1 = llfuse.listdir(self.mounttmp)
372 self.assertEqual(["file1.txt", "file2.txt"], sorted(d1))
374 collection.remove("file2.txt")
376 d1 = llfuse.listdir(self.mounttmp)
377 self.assertEqual(["file1.txt"], d1)
380 def fuseCreateFileTestHelper(mounttmp):
381 class Test(unittest.TestCase):
383 with open(os.path.join(mounttmp, "file1.txt"), "w") as f:
387 class FuseCreateFileTest(MountTestBase):
389 collection = arvados.collection.Collection(api_client=self.api)
390 collection.save_new()
392 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
393 self.assertEqual(collection2["manifest_text"], "")
395 collection.save_new()
397 m = self.make_mount(fuse.CollectionDirectory)
399 m.new_collection(collection.api_response(), collection)
400 self.assertTrue(m.writable())
402 self.assertNotIn("file1.txt", collection)
404 self.pool.apply(fuseCreateFileTestHelper, (self.mounttmp,))
406 self.assertIn("file1.txt", collection)
408 d1 = llfuse.listdir(self.mounttmp)
409 self.assertEqual(["file1.txt"], d1)
411 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
412 self.assertRegexpMatches(collection2["manifest_text"],
413 r'\. d41d8cd98f00b204e9800998ecf8427e\+0\+A\S+ 0:0:file1\.txt$')
416 def fuseWriteFileTestHelperWriteFile(mounttmp):
417 class Test(unittest.TestCase):
419 with open(os.path.join(mounttmp, "file1.txt"), "w") as f:
420 f.write("Hello world!")
423 def fuseWriteFileTestHelperReadFile(mounttmp):
424 class Test(unittest.TestCase):
426 with open(os.path.join(mounttmp, "file1.txt"), "r") as f:
427 self.assertEqual(f.read(), "Hello world!")
430 class FuseWriteFileTest(MountTestBase):
432 collection = arvados.collection.Collection(api_client=self.api)
433 collection.save_new()
435 m = self.make_mount(fuse.CollectionDirectory)
437 m.new_collection(collection.api_response(), collection)
438 self.assertTrue(m.writable())
440 self.assertNotIn("file1.txt", collection)
442 self.assertEqual(0, self.operations.write_counter.get())
443 self.pool.apply(fuseWriteFileTestHelperWriteFile, (self.mounttmp,))
444 self.assertEqual(12, self.operations.write_counter.get())
446 with collection.open("file1.txt") as f:
447 self.assertEqual(f.read(), "Hello world!")
449 self.assertEqual(0, self.operations.read_counter.get())
450 self.pool.apply(fuseWriteFileTestHelperReadFile, (self.mounttmp,))
451 self.assertEqual(12, self.operations.read_counter.get())
453 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
454 self.assertRegexpMatches(collection2["manifest_text"],
455 r'\. 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
458 def fuseUpdateFileTestHelper(mounttmp):
459 class Test(unittest.TestCase):
461 with open(os.path.join(mounttmp, "file1.txt"), "w") as f:
462 f.write("Hello world!")
464 with open(os.path.join(mounttmp, "file1.txt"), "r+") as f:
466 self.assertEqual(fr, "Hello world!")
468 f.write("Hola mundo!")
471 self.assertEqual(fr, "Hola mundo!!")
473 with open(os.path.join(mounttmp, "file1.txt"), "r") as f:
474 self.assertEqual(f.read(), "Hola mundo!!")
478 class FuseUpdateFileTest(MountTestBase):
480 collection = arvados.collection.Collection(api_client=self.api)
481 collection.save_new()
483 m = self.make_mount(fuse.CollectionDirectory)
485 m.new_collection(collection.api_response(), collection)
486 self.assertTrue(m.writable())
488 # See note in MountTestBase.setUp
489 self.pool.apply(fuseUpdateFileTestHelper, (self.mounttmp,))
491 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
492 self.assertRegexpMatches(collection2["manifest_text"],
493 r'\. daaef200ebb921e011e3ae922dd3266b\+11\+A\S+ 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:11:file1\.txt 22:1:file1\.txt$')
496 def fuseMkdirTestHelper(mounttmp):
497 class Test(unittest.TestCase):
499 with self.assertRaises(IOError):
500 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
501 f.write("Hello world!")
503 os.mkdir(os.path.join(mounttmp, "testdir"))
505 with self.assertRaises(OSError):
506 os.mkdir(os.path.join(mounttmp, "testdir"))
508 d1 = llfuse.listdir(mounttmp)
509 self.assertEqual(["testdir"], d1)
511 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
512 f.write("Hello world!")
514 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
515 self.assertEqual(["file1.txt"], d1)
519 class FuseMkdirTest(MountTestBase):
521 collection = arvados.collection.Collection(api_client=self.api)
522 collection.save_new()
524 m = self.make_mount(fuse.CollectionDirectory)
526 m.new_collection(collection.api_response(), collection)
527 self.assertTrue(m.writable())
529 self.pool.apply(fuseMkdirTestHelper, (self.mounttmp,))
531 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
532 self.assertRegexpMatches(collection2["manifest_text"],
533 r'\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
536 def fuseRmTestHelperWriteFile(mounttmp):
537 class Test(unittest.TestCase):
539 os.mkdir(os.path.join(mounttmp, "testdir"))
541 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
542 f.write("Hello world!")
546 def fuseRmTestHelperDeleteFile(mounttmp):
547 class Test(unittest.TestCase):
549 # Can't delete because it's not empty
550 with self.assertRaises(OSError):
551 os.rmdir(os.path.join(mounttmp, "testdir"))
553 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
554 self.assertEqual(["file1.txt"], d1)
557 os.remove(os.path.join(mounttmp, "testdir", "file1.txt"))
559 # Make sure it's empty
560 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
561 self.assertEqual([], d1)
563 # Try to delete it again
564 with self.assertRaises(OSError):
565 os.remove(os.path.join(mounttmp, "testdir", "file1.txt"))
569 def fuseRmTestHelperRmdir(mounttmp):
570 class Test(unittest.TestCase):
572 # Should be able to delete now that it is empty
573 os.rmdir(os.path.join(mounttmp, "testdir"))
575 # Make sure it's empty
576 d1 = llfuse.listdir(os.path.join(mounttmp))
577 self.assertEqual([], d1)
579 # Try to delete it again
580 with self.assertRaises(OSError):
581 os.rmdir(os.path.join(mounttmp, "testdir"))
585 class FuseRmTest(MountTestBase):
587 collection = arvados.collection.Collection(api_client=self.api)
588 collection.save_new()
590 m = self.make_mount(fuse.CollectionDirectory)
592 m.new_collection(collection.api_response(), collection)
593 self.assertTrue(m.writable())
595 self.pool.apply(fuseRmTestHelperWriteFile, (self.mounttmp,))
598 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
599 self.assertRegexpMatches(collection2["manifest_text"],
600 r'\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
601 self.pool.apply(fuseRmTestHelperDeleteFile, (self.mounttmp,))
603 # Can't have empty directories :-( so manifest will be empty.
604 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
605 self.assertEqual(collection2["manifest_text"], "")
607 self.pool.apply(fuseRmTestHelperRmdir, (self.mounttmp,))
609 # manifest should be empty now.
610 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
611 self.assertEqual(collection2["manifest_text"], "")
614 def fuseMvFileTestHelperWriteFile(mounttmp):
615 class Test(unittest.TestCase):
617 os.mkdir(os.path.join(mounttmp, "testdir"))
619 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
620 f.write("Hello world!")
624 def fuseMvFileTestHelperMoveFile(mounttmp):
625 class Test(unittest.TestCase):
627 d1 = llfuse.listdir(os.path.join(mounttmp))
628 self.assertEqual(["testdir"], d1)
629 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
630 self.assertEqual(["file1.txt"], d1)
632 os.rename(os.path.join(mounttmp, "testdir", "file1.txt"), os.path.join(mounttmp, "file1.txt"))
634 d1 = llfuse.listdir(os.path.join(mounttmp))
635 self.assertEqual(["file1.txt", "testdir"], sorted(d1))
636 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
637 self.assertEqual([], d1)
641 class FuseMvFileTest(MountTestBase):
643 collection = arvados.collection.Collection(api_client=self.api)
644 collection.save_new()
646 m = self.make_mount(fuse.CollectionDirectory)
648 m.new_collection(collection.api_response(), collection)
649 self.assertTrue(m.writable())
651 self.pool.apply(fuseMvFileTestHelperWriteFile, (self.mounttmp,))
654 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
655 self.assertRegexpMatches(collection2["manifest_text"],
656 r'\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
658 self.pool.apply(fuseMvFileTestHelperMoveFile, (self.mounttmp,))
660 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
661 self.assertRegexpMatches(collection2["manifest_text"],
662 r'\. 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
665 def fuseRenameTestHelper(mounttmp):
666 class Test(unittest.TestCase):
668 os.mkdir(os.path.join(mounttmp, "testdir"))
670 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
671 f.write("Hello world!")
675 class FuseRenameTest(MountTestBase):
677 collection = arvados.collection.Collection(api_client=self.api)
678 collection.save_new()
680 m = self.make_mount(fuse.CollectionDirectory)
682 m.new_collection(collection.api_response(), collection)
683 self.assertTrue(m.writable())
685 self.pool.apply(fuseRenameTestHelper, (self.mounttmp,))
688 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
689 self.assertRegexpMatches(collection2["manifest_text"],
690 r'\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
692 d1 = llfuse.listdir(os.path.join(self.mounttmp))
693 self.assertEqual(["testdir"], d1)
694 d1 = llfuse.listdir(os.path.join(self.mounttmp, "testdir"))
695 self.assertEqual(["file1.txt"], d1)
697 os.rename(os.path.join(self.mounttmp, "testdir"), os.path.join(self.mounttmp, "testdir2"))
699 d1 = llfuse.listdir(os.path.join(self.mounttmp))
700 self.assertEqual(["testdir2"], sorted(d1))
701 d1 = llfuse.listdir(os.path.join(self.mounttmp, "testdir2"))
702 self.assertEqual(["file1.txt"], d1)
704 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
705 self.assertRegexpMatches(collection2["manifest_text"],
706 r'\./testdir2 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
709 class FuseUpdateFromEventTest(MountTestBase):
711 collection = arvados.collection.Collection(api_client=self.api)
712 collection.save_new()
714 m = self.make_mount(fuse.CollectionDirectory)
716 m.new_collection(collection.api_response(), collection)
718 self.operations.listen_for_events()
720 d1 = llfuse.listdir(os.path.join(self.mounttmp))
721 self.assertEqual([], sorted(d1))
723 with arvados.collection.Collection(collection.manifest_locator(), api_client=self.api) as collection2:
724 with collection2.open("file1.txt", "w") as f:
727 for attempt in AssertWithTimeout(10):
728 attempt(self.assertEqual, ["file1.txt"], llfuse.listdir(os.path.join(self.mounttmp)))
731 class FuseDeleteProjectEventTest(MountTestBase):
734 aproject = self.api.groups().create(body={
736 "group_class": "project"
739 bproject = self.api.groups().create(body={
741 "group_class": "project",
742 "owner_uuid": aproject["uuid"]
745 self.make_mount(fuse.ProjectDirectory,
746 project_object=self.api.users().current().execute())
748 self.operations.listen_for_events()
750 d1 = llfuse.listdir(os.path.join(self.mounttmp, "aproject"))
751 self.assertEqual(["bproject"], sorted(d1))
753 self.api.groups().delete(uuid=bproject["uuid"]).execute()
755 for attempt in AssertWithTimeout(10):
756 attempt(self.assertEqual, [], llfuse.listdir(os.path.join(self.mounttmp, "aproject")))
759 def fuseFileConflictTestHelper(mounttmp):
760 class Test(unittest.TestCase):
762 with open(os.path.join(mounttmp, "file1.txt"), "w") as f:
765 d1 = sorted(llfuse.listdir(os.path.join(mounttmp)))
766 self.assertEqual(len(d1), 2)
768 with open(os.path.join(mounttmp, "file1.txt"), "r") as f:
769 self.assertEqual(f.read(), "bar")
771 self.assertRegexpMatches(d1[1],
772 r'file1\.txt~\d\d\d\d\d\d\d\d-\d\d\d\d\d\d~conflict~')
774 with open(os.path.join(mounttmp, d1[1]), "r") as f:
775 self.assertEqual(f.read(), "foo")
779 class FuseFileConflictTest(MountTestBase):
781 collection = arvados.collection.Collection(api_client=self.api)
782 collection.save_new()
784 m = self.make_mount(fuse.CollectionDirectory)
786 m.new_collection(collection.api_response(), collection)
788 d1 = llfuse.listdir(os.path.join(self.mounttmp))
789 self.assertEqual([], sorted(d1))
791 with arvados.collection.Collection(collection.manifest_locator(), api_client=self.api) as collection2:
792 with collection2.open("file1.txt", "w") as f:
795 # See note in MountTestBase.setUp
796 self.pool.apply(fuseFileConflictTestHelper, (self.mounttmp,))
799 def fuseUnlinkOpenFileTest(mounttmp):
800 class Test(unittest.TestCase):
802 with open(os.path.join(mounttmp, "file1.txt"), "w+") as f:
805 d1 = llfuse.listdir(os.path.join(mounttmp))
806 self.assertEqual(["file1.txt"], sorted(d1))
808 os.remove(os.path.join(mounttmp, "file1.txt"))
810 d1 = llfuse.listdir(os.path.join(mounttmp))
811 self.assertEqual([], sorted(d1))
814 self.assertEqual(f.read(), "foo")
818 self.assertEqual(f.read(), "foobar")
822 class FuseUnlinkOpenFileTest(MountTestBase):
824 collection = arvados.collection.Collection(api_client=self.api)
825 collection.save_new()
827 m = self.make_mount(fuse.CollectionDirectory)
829 m.new_collection(collection.api_response(), collection)
831 # See note in MountTestBase.setUp
832 self.pool.apply(fuseUnlinkOpenFileTest, (self.mounttmp,))
834 self.assertEqual(collection.manifest_text(), "")
837 def fuseMvFileBetweenCollectionsTest1(mounttmp, uuid1, uuid2):
838 class Test(unittest.TestCase):
840 with open(os.path.join(mounttmp, uuid1, "file1.txt"), "w") as f:
841 f.write("Hello world!")
843 d1 = os.listdir(os.path.join(mounttmp, uuid1))
844 self.assertEqual(["file1.txt"], sorted(d1))
845 d1 = os.listdir(os.path.join(mounttmp, uuid2))
846 self.assertEqual([], sorted(d1))
850 def fuseMvFileBetweenCollectionsTest2(mounttmp, uuid1, uuid2):
851 class Test(unittest.TestCase):
853 os.rename(os.path.join(mounttmp, uuid1, "file1.txt"), os.path.join(mounttmp, uuid2, "file2.txt"))
855 d1 = os.listdir(os.path.join(mounttmp, uuid1))
856 self.assertEqual([], sorted(d1))
857 d1 = os.listdir(os.path.join(mounttmp, uuid2))
858 self.assertEqual(["file2.txt"], sorted(d1))
862 class FuseMvFileBetweenCollectionsTest(MountTestBase):
864 collection1 = arvados.collection.Collection(api_client=self.api)
865 collection1.save_new()
867 collection2 = arvados.collection.Collection(api_client=self.api)
868 collection2.save_new()
870 m = self.make_mount(fuse.MagicDirectory)
872 # See note in MountTestBase.setUp
873 self.pool.apply(fuseMvFileBetweenCollectionsTest1, (self.mounttmp,
874 collection1.manifest_locator(),
875 collection2.manifest_locator()))
880 self.assertRegexpMatches(collection1.manifest_text(), r"\. 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$")
881 self.assertEqual(collection2.manifest_text(), "")
883 self.pool.apply(fuseMvFileBetweenCollectionsTest2, (self.mounttmp,
884 collection1.manifest_locator(),
885 collection2.manifest_locator()))
890 self.assertEqual(collection1.manifest_text(), "")
891 self.assertRegexpMatches(collection2.manifest_text(), r"\. 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file2\.txt$")
893 collection1.stop_threads()
894 collection2.stop_threads()
897 def fuseMvDirBetweenCollectionsTest1(mounttmp, uuid1, uuid2):
898 class Test(unittest.TestCase):
900 os.mkdir(os.path.join(mounttmp, uuid1, "testdir"))
901 with open(os.path.join(mounttmp, uuid1, "testdir", "file1.txt"), "w") as f:
902 f.write("Hello world!")
904 d1 = os.listdir(os.path.join(mounttmp, uuid1))
905 self.assertEqual(["testdir"], sorted(d1))
906 d1 = os.listdir(os.path.join(mounttmp, uuid1, "testdir"))
907 self.assertEqual(["file1.txt"], sorted(d1))
909 d1 = os.listdir(os.path.join(mounttmp, uuid2))
910 self.assertEqual([], sorted(d1))
915 def fuseMvDirBetweenCollectionsTest2(mounttmp, uuid1, uuid2):
916 class Test(unittest.TestCase):
918 os.rename(os.path.join(mounttmp, uuid1, "testdir"), os.path.join(mounttmp, uuid2, "testdir2"))
920 d1 = os.listdir(os.path.join(mounttmp, uuid1))
921 self.assertEqual([], sorted(d1))
923 d1 = os.listdir(os.path.join(mounttmp, uuid2))
924 self.assertEqual(["testdir2"], sorted(d1))
925 d1 = os.listdir(os.path.join(mounttmp, uuid2, "testdir2"))
926 self.assertEqual(["file1.txt"], sorted(d1))
928 with open(os.path.join(mounttmp, uuid2, "testdir2", "file1.txt"), "r") as f:
929 self.assertEqual(f.read(), "Hello world!")
933 class FuseMvDirBetweenCollectionsTest(MountTestBase):
935 collection1 = arvados.collection.Collection(api_client=self.api)
936 collection1.save_new()
938 collection2 = arvados.collection.Collection(api_client=self.api)
939 collection2.save_new()
941 m = self.make_mount(fuse.MagicDirectory)
943 # See note in MountTestBase.setUp
944 self.pool.apply(fuseMvDirBetweenCollectionsTest1, (self.mounttmp,
945 collection1.manifest_locator(),
946 collection2.manifest_locator()))
951 self.assertRegexpMatches(collection1.manifest_text(), r"\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$")
952 self.assertEqual(collection2.manifest_text(), "")
954 self.pool.apply(fuseMvDirBetweenCollectionsTest2, (self.mounttmp,
955 collection1.manifest_locator(),
956 collection2.manifest_locator()))
961 self.assertEqual(collection1.manifest_text(), "")
962 self.assertRegexpMatches(collection2.manifest_text(), r"\./testdir2 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$")
964 collection1.stop_threads()
965 collection2.stop_threads()
967 def fuseProjectMkdirTestHelper1(mounttmp):
968 class Test(unittest.TestCase):
970 os.mkdir(os.path.join(mounttmp, "testcollection"))
971 with self.assertRaises(OSError):
972 os.mkdir(os.path.join(mounttmp, "testcollection"))
975 def fuseProjectMkdirTestHelper2(mounttmp):
976 class Test(unittest.TestCase):
978 with open(os.path.join(mounttmp, "testcollection", "file1.txt"), "w") as f:
979 f.write("Hello world!")
980 with self.assertRaises(OSError):
981 os.rmdir(os.path.join(mounttmp, "testcollection"))
982 os.remove(os.path.join(mounttmp, "testcollection", "file1.txt"))
983 with self.assertRaises(OSError):
984 os.remove(os.path.join(mounttmp, "testcollection"))
985 os.rmdir(os.path.join(mounttmp, "testcollection"))
988 class FuseProjectMkdirRmdirTest(MountTestBase):
990 self.make_mount(fuse.ProjectDirectory,
991 project_object=self.api.users().current().execute())
993 d1 = llfuse.listdir(self.mounttmp)
994 self.assertNotIn('testcollection', d1)
996 self.pool.apply(fuseProjectMkdirTestHelper1, (self.mounttmp,))
998 d1 = llfuse.listdir(self.mounttmp)
999 self.assertIn('testcollection', d1)
1001 self.pool.apply(fuseProjectMkdirTestHelper2, (self.mounttmp,))
1003 d1 = llfuse.listdir(self.mounttmp)
1004 self.assertNotIn('testcollection', d1)
1007 def fuseProjectMvTestHelper1(mounttmp):
1008 class Test(unittest.TestCase):
1010 d1 = llfuse.listdir(mounttmp)
1011 self.assertNotIn('testcollection', d1)
1013 os.mkdir(os.path.join(mounttmp, "testcollection"))
1015 d1 = llfuse.listdir(mounttmp)
1016 self.assertIn('testcollection', d1)
1018 with self.assertRaises(OSError):
1019 os.rename(os.path.join(mounttmp, "testcollection"), os.path.join(mounttmp, 'Unrestricted public data'))
1021 os.rename(os.path.join(mounttmp, "testcollection"), os.path.join(mounttmp, 'Unrestricted public data', 'testcollection'))
1023 d1 = llfuse.listdir(mounttmp)
1024 self.assertNotIn('testcollection', d1)
1026 d1 = llfuse.listdir(os.path.join(mounttmp, 'Unrestricted public data'))
1027 self.assertIn('testcollection', d1)
1031 class FuseProjectMvTest(MountTestBase):
1033 self.make_mount(fuse.ProjectDirectory,
1034 project_object=self.api.users().current().execute())
1036 self.pool.apply(fuseProjectMvTestHelper1, (self.mounttmp,))
1039 def fuseFsyncTestHelper(mounttmp, k):
1040 class Test(unittest.TestCase):
1042 fd = os.open(os.path.join(mounttmp, k), os.O_RDONLY)
1048 class FuseFsyncTest(FuseMagicTest):
1050 self.make_mount(fuse.MagicDirectory)
1051 self.pool.apply(fuseFsyncTestHelper, (self.mounttmp, self.testcollection))
1054 class MagicDirApiError(FuseMagicTest):
1056 api = mock.MagicMock()
1057 super(MagicDirApiError, self).setUp(api=api)
1058 api.collections().get().execute.side_effect = iter([
1059 Exception('API fail'),
1061 "manifest_text": self.test_manifest,
1062 "portable_data_hash": self.test_manifest_pdh,
1065 api.keep.get.side_effect = Exception('Keep fail')
1068 self.make_mount(fuse.MagicDirectory)
1070 self.operations.inodes.inode_cache.cap = 1
1071 self.operations.inodes.inode_cache.min_entries = 2
1073 with self.assertRaises(OSError):
1074 llfuse.listdir(os.path.join(self.mounttmp, self.testcollection))
1076 llfuse.listdir(os.path.join(self.mounttmp, self.testcollection))
1079 class FuseUnitTest(unittest.TestCase):
1080 def test_sanitize_filename(self):
1099 for f in acceptable:
1100 self.assertEqual(f, fuse.sanitize_filename(f))
1101 for f in unacceptable:
1102 self.assertNotEqual(f, fuse.sanitize_filename(f))
1103 # The sanitized filename should be the same length, though.
1104 self.assertEqual(len(f), len(fuse.sanitize_filename(f)))
1106 self.assertEqual("_", fuse.sanitize_filename(""))
1107 self.assertEqual("_", fuse.sanitize_filename("."))
1108 self.assertEqual("__", fuse.sanitize_filename(".."))
1111 class FuseMagicTestPDHOnly(MountTestBase):
1112 def setUp(self, api=None):
1113 super(FuseMagicTestPDHOnly, self).setUp(api=api)
1115 cw = arvados.CollectionWriter()
1117 cw.start_new_file('thing1.txt')
1120 self.testcollection = cw.finish()
1121 self.test_manifest = cw.manifest_text()
1122 created = self.api.collections().create(body={"manifest_text":self.test_manifest}).execute()
1123 self.testcollectionuuid = str(created['uuid'])
1125 def verify_pdh_only(self, pdh_only=False, skip_pdh_only=False):
1126 if skip_pdh_only is True:
1127 self.make_mount(fuse.MagicDirectory) # in this case, the default by_id applies
1129 self.make_mount(fuse.MagicDirectory, pdh_only=pdh_only)
1131 mount_ls = llfuse.listdir(self.mounttmp)
1132 self.assertIn('README', mount_ls)
1133 self.assertFalse(any(arvados.util.keep_locator_pattern.match(fn) or
1134 arvados.util.uuid_pattern.match(fn)
1135 for fn in mount_ls),
1136 "new FUSE MagicDirectory lists Collection")
1138 # look up using pdh should succeed in all cases
1139 self.assertDirContents(self.testcollection, ['thing1.txt'])
1140 self.assertDirContents(os.path.join('by_id', self.testcollection),
1142 mount_ls = llfuse.listdir(self.mounttmp)
1143 self.assertIn('README', mount_ls)
1144 self.assertIn(self.testcollection, mount_ls)
1145 self.assertIn(self.testcollection,
1146 llfuse.listdir(os.path.join(self.mounttmp, 'by_id')))
1149 files[os.path.join(self.mounttmp, self.testcollection, 'thing1.txt')] = 'data 1'
1151 for k, v in files.items():
1152 with open(os.path.join(self.mounttmp, k)) as f:
1153 self.assertEqual(v, f.read())
1155 # look up using uuid should fail when pdh_only is set
1156 if pdh_only is True:
1157 with self.assertRaises(OSError):
1158 self.assertDirContents(os.path.join('by_id', self.testcollectionuuid),
1161 self.assertDirContents(os.path.join('by_id', self.testcollectionuuid),
1164 def test_with_pdh_only_true(self):
1165 self.verify_pdh_only(pdh_only=True)
1167 def test_with_pdh_only_false(self):
1168 self.verify_pdh_only(pdh_only=False)
1170 def test_with_default_by_id(self):
1171 self.verify_pdh_only(skip_pdh_only=True)