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 self.test_project = run_test_server.fixture('groups')['aproject']['uuid']
125 self.collection_in_test_project = run_test_server.fixture('collections')['foo_collection_in_aproject']['name']
127 cw = arvados.CollectionWriter()
129 cw.start_new_file('thing1.txt')
132 self.testcollection = cw.finish()
133 self.test_manifest = cw.manifest_text()
134 coll = self.api.collections().create(body={"manifest_text":self.test_manifest}).execute()
135 self.test_manifest_pdh = coll['portable_data_hash']
138 self.make_mount(fuse.MagicDirectory)
140 mount_ls = llfuse.listdir(self.mounttmp)
141 self.assertIn('README', mount_ls)
142 self.assertFalse(any(arvados.util.keep_locator_pattern.match(fn) or
143 arvados.util.uuid_pattern.match(fn)
145 "new FUSE MagicDirectory has no collections or projects")
146 self.assertDirContents(self.testcollection, ['thing1.txt'])
147 self.assertDirContents(os.path.join('by_id', self.testcollection),
149 self.assertIn(self.collection_in_test_project,
150 llfuse.listdir(os.path.join(self.mounttmp, self.test_project)))
151 self.assertIn(self.collection_in_test_project,
152 llfuse.listdir(os.path.join(self.mounttmp, 'by_id', self.test_project)))
154 mount_ls = llfuse.listdir(self.mounttmp)
155 self.assertIn('README', mount_ls)
156 self.assertIn(self.testcollection, mount_ls)
157 self.assertIn(self.testcollection,
158 llfuse.listdir(os.path.join(self.mounttmp, 'by_id')))
159 self.assertIn(self.test_project, mount_ls)
160 self.assertIn(self.test_project,
161 llfuse.listdir(os.path.join(self.mounttmp, 'by_id')))
164 files[os.path.join(self.mounttmp, self.testcollection, 'thing1.txt')] = 'data 1'
166 for k, v in files.items():
167 with open(os.path.join(self.mounttmp, k)) as f:
168 self.assertEqual(v, f.read())
171 class FuseTagsTest(MountTestBase):
173 self.make_mount(fuse.TagsDirectory)
175 d1 = llfuse.listdir(self.mounttmp)
177 self.assertEqual(['foo_tag'], d1)
179 d2 = llfuse.listdir(os.path.join(self.mounttmp, 'foo_tag'))
181 self.assertEqual(['zzzzz-4zz18-fy296fx3hot09f7'], d2)
183 d3 = llfuse.listdir(os.path.join(self.mounttmp, 'foo_tag', 'zzzzz-4zz18-fy296fx3hot09f7'))
185 self.assertEqual(['foo'], d3)
188 class FuseTagsUpdateTest(MountTestBase):
189 def tag_collection(self, coll_uuid, tag_name):
190 return self.api.links().create(
191 body={'link': {'head_uuid': coll_uuid,
197 self.make_mount(fuse.TagsDirectory, poll_time=1)
199 self.assertIn('foo_tag', llfuse.listdir(self.mounttmp))
201 bar_uuid = run_test_server.fixture('collections')['bar_file']['uuid']
202 self.tag_collection(bar_uuid, 'fuse_test_tag')
203 for attempt in AssertWithTimeout(10):
204 attempt(self.assertIn, 'fuse_test_tag', llfuse.listdir(self.mounttmp))
205 self.assertDirContents('fuse_test_tag', [bar_uuid])
207 baz_uuid = run_test_server.fixture('collections')['baz_file']['uuid']
208 l = self.tag_collection(baz_uuid, 'fuse_test_tag')
209 for attempt in AssertWithTimeout(10):
210 attempt(self.assertDirContents, 'fuse_test_tag', [bar_uuid, baz_uuid])
212 self.api.links().delete(uuid=l['uuid']).execute()
213 for attempt in AssertWithTimeout(10):
214 attempt(self.assertDirContents, 'fuse_test_tag', [bar_uuid])
217 def fuseSharedTestHelper(mounttmp):
218 class Test(unittest.TestCase):
220 # Double check that we can open and read objects in this folder as a file,
221 # and that its contents are what we expect.
222 baz_path = os.path.join(
226 'collection in FUSE project',
228 with open(baz_path) as f:
229 self.assertEqual("baz", f.read())
231 # check mtime on collection
232 st = os.stat(baz_path)
234 mtime = st.st_mtime_ns / 1000000000
235 except AttributeError:
237 self.assertEqual(mtime, 1391448174)
239 # shared_dirs is a list of the directories exposed
240 # by fuse.SharedDirectory (i.e. any object visible
241 # to the current user)
242 shared_dirs = llfuse.listdir(mounttmp)
244 self.assertIn('FUSE User', shared_dirs)
246 # fuse_user_objs is a list of the objects owned by the FUSE
247 # test user (which present as files in the 'FUSE User'
249 fuse_user_objs = llfuse.listdir(os.path.join(mounttmp, 'FUSE User'))
250 fuse_user_objs.sort()
251 self.assertEqual(['FUSE Test Project', # project owned by user
252 'collection #1 owned by FUSE', # collection owned by user
253 'collection #2 owned by FUSE' # collection owned by user
256 # test_proj_files is a list of the files in the FUSE Test Project.
257 test_proj_files = llfuse.listdir(os.path.join(mounttmp, 'FUSE User', 'FUSE Test Project'))
258 test_proj_files.sort()
259 self.assertEqual(['collection in FUSE project'
265 class FuseSharedTest(MountTestBase):
267 self.make_mount(fuse.SharedDirectory,
268 exclude=self.api.users().current().execute()['uuid'])
269 keep = arvados.keep.KeepClient()
272 self.pool.apply(fuseSharedTestHelper, (self.mounttmp,))
275 class FuseHomeTest(MountTestBase):
277 self.make_mount(fuse.ProjectDirectory,
278 project_object=self.api.users().current().execute())
280 d1 = llfuse.listdir(self.mounttmp)
281 self.assertIn('Unrestricted public data', d1)
283 d2 = llfuse.listdir(os.path.join(self.mounttmp, 'Unrestricted public data'))
284 public_project = run_test_server.fixture('groups')[
285 'anonymously_accessible_project']
288 for name, item in run_test_server.fixture('collections').iteritems():
289 if 'name' not in item:
291 elif item['owner_uuid'] == public_project['uuid']:
292 self.assertIn(item['name'], d2)
295 # Artificial assumption here: there is no public
296 # collection fixture with the same name as a
297 # non-public collection.
298 self.assertNotIn(item['name'], d2)
300 self.assertNotEqual(0, found_in)
301 self.assertNotEqual(0, found_not_in)
303 d3 = llfuse.listdir(os.path.join(self.mounttmp, 'Unrestricted public data', 'GNU General Public License, version 3'))
304 self.assertEqual(["GNU_General_Public_License,_version_3.pdf"], d3)
307 def fuseModifyFileTestHelperReadStartContents(mounttmp):
308 class Test(unittest.TestCase):
310 d1 = llfuse.listdir(mounttmp)
311 self.assertEqual(["file1.txt"], d1)
312 with open(os.path.join(mounttmp, "file1.txt")) as f:
313 self.assertEqual("blub", f.read())
316 def fuseModifyFileTestHelperReadEndContents(mounttmp):
317 class Test(unittest.TestCase):
319 d1 = llfuse.listdir(mounttmp)
320 self.assertEqual(["file1.txt"], d1)
321 with open(os.path.join(mounttmp, "file1.txt")) as f:
322 self.assertEqual("plnp", f.read())
325 class FuseModifyFileTest(MountTestBase):
327 collection = arvados.collection.Collection(api_client=self.api)
328 with collection.open("file1.txt", "w") as f:
331 collection.save_new()
333 m = self.make_mount(fuse.CollectionDirectory)
335 m.new_collection(collection.api_response(), collection)
337 self.pool.apply(fuseModifyFileTestHelperReadStartContents, (self.mounttmp,))
339 with collection.open("file1.txt", "w") as f:
342 self.pool.apply(fuseModifyFileTestHelperReadEndContents, (self.mounttmp,))
345 class FuseAddFileToCollectionTest(MountTestBase):
347 collection = arvados.collection.Collection(api_client=self.api)
348 with collection.open("file1.txt", "w") as f:
351 collection.save_new()
353 m = self.make_mount(fuse.CollectionDirectory)
355 m.new_collection(collection.api_response(), collection)
357 d1 = llfuse.listdir(self.mounttmp)
358 self.assertEqual(["file1.txt"], d1)
360 with collection.open("file2.txt", "w") as f:
363 d1 = llfuse.listdir(self.mounttmp)
364 self.assertEqual(["file1.txt", "file2.txt"], sorted(d1))
367 class FuseRemoveFileFromCollectionTest(MountTestBase):
369 collection = arvados.collection.Collection(api_client=self.api)
370 with collection.open("file1.txt", "w") as f:
373 with collection.open("file2.txt", "w") as f:
376 collection.save_new()
378 m = self.make_mount(fuse.CollectionDirectory)
380 m.new_collection(collection.api_response(), collection)
382 d1 = llfuse.listdir(self.mounttmp)
383 self.assertEqual(["file1.txt", "file2.txt"], sorted(d1))
385 collection.remove("file2.txt")
387 d1 = llfuse.listdir(self.mounttmp)
388 self.assertEqual(["file1.txt"], d1)
391 def fuseCreateFileTestHelper(mounttmp):
392 class Test(unittest.TestCase):
394 with open(os.path.join(mounttmp, "file1.txt"), "w") as f:
398 class FuseCreateFileTest(MountTestBase):
400 collection = arvados.collection.Collection(api_client=self.api)
401 collection.save_new()
403 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
404 self.assertEqual(collection2["manifest_text"], "")
406 collection.save_new()
408 m = self.make_mount(fuse.CollectionDirectory)
410 m.new_collection(collection.api_response(), collection)
411 self.assertTrue(m.writable())
413 self.assertNotIn("file1.txt", collection)
415 self.pool.apply(fuseCreateFileTestHelper, (self.mounttmp,))
417 self.assertIn("file1.txt", collection)
419 d1 = llfuse.listdir(self.mounttmp)
420 self.assertEqual(["file1.txt"], d1)
422 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
423 self.assertRegexpMatches(collection2["manifest_text"],
424 r'\. d41d8cd98f00b204e9800998ecf8427e\+0\+A\S+ 0:0:file1\.txt$')
427 def fuseWriteFileTestHelperWriteFile(mounttmp):
428 class Test(unittest.TestCase):
430 with open(os.path.join(mounttmp, "file1.txt"), "w") as f:
431 f.write("Hello world!")
434 def fuseWriteFileTestHelperReadFile(mounttmp):
435 class Test(unittest.TestCase):
437 with open(os.path.join(mounttmp, "file1.txt"), "r") as f:
438 self.assertEqual(f.read(), "Hello world!")
441 class FuseWriteFileTest(MountTestBase):
443 collection = arvados.collection.Collection(api_client=self.api)
444 collection.save_new()
446 m = self.make_mount(fuse.CollectionDirectory)
448 m.new_collection(collection.api_response(), collection)
449 self.assertTrue(m.writable())
451 self.assertNotIn("file1.txt", collection)
453 self.assertEqual(0, self.operations.write_counter.get())
454 self.pool.apply(fuseWriteFileTestHelperWriteFile, (self.mounttmp,))
455 self.assertEqual(12, self.operations.write_counter.get())
457 with collection.open("file1.txt") as f:
458 self.assertEqual(f.read(), "Hello world!")
460 self.assertEqual(0, self.operations.read_counter.get())
461 self.pool.apply(fuseWriteFileTestHelperReadFile, (self.mounttmp,))
462 self.assertEqual(12, self.operations.read_counter.get())
464 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
465 self.assertRegexpMatches(collection2["manifest_text"],
466 r'\. 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
469 def fuseUpdateFileTestHelper(mounttmp):
470 class Test(unittest.TestCase):
472 with open(os.path.join(mounttmp, "file1.txt"), "w") as f:
473 f.write("Hello world!")
475 with open(os.path.join(mounttmp, "file1.txt"), "r+") as f:
477 self.assertEqual(fr, "Hello world!")
479 f.write("Hola mundo!")
482 self.assertEqual(fr, "Hola mundo!!")
484 with open(os.path.join(mounttmp, "file1.txt"), "r") as f:
485 self.assertEqual(f.read(), "Hola mundo!!")
489 class FuseUpdateFileTest(MountTestBase):
491 collection = arvados.collection.Collection(api_client=self.api)
492 collection.save_new()
494 m = self.make_mount(fuse.CollectionDirectory)
496 m.new_collection(collection.api_response(), collection)
497 self.assertTrue(m.writable())
499 # See note in MountTestBase.setUp
500 self.pool.apply(fuseUpdateFileTestHelper, (self.mounttmp,))
502 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
503 self.assertRegexpMatches(collection2["manifest_text"],
504 r'\. daaef200ebb921e011e3ae922dd3266b\+11\+A\S+ 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:11:file1\.txt 22:1:file1\.txt$')
507 def fuseMkdirTestHelper(mounttmp):
508 class Test(unittest.TestCase):
510 with self.assertRaises(IOError):
511 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
512 f.write("Hello world!")
514 os.mkdir(os.path.join(mounttmp, "testdir"))
516 with self.assertRaises(OSError):
517 os.mkdir(os.path.join(mounttmp, "testdir"))
519 d1 = llfuse.listdir(mounttmp)
520 self.assertEqual(["testdir"], d1)
522 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
523 f.write("Hello world!")
525 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
526 self.assertEqual(["file1.txt"], d1)
530 class FuseMkdirTest(MountTestBase):
532 collection = arvados.collection.Collection(api_client=self.api)
533 collection.save_new()
535 m = self.make_mount(fuse.CollectionDirectory)
537 m.new_collection(collection.api_response(), collection)
538 self.assertTrue(m.writable())
540 self.pool.apply(fuseMkdirTestHelper, (self.mounttmp,))
542 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
543 self.assertRegexpMatches(collection2["manifest_text"],
544 r'\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
547 def fuseRmTestHelperWriteFile(mounttmp):
548 class Test(unittest.TestCase):
550 os.mkdir(os.path.join(mounttmp, "testdir"))
552 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
553 f.write("Hello world!")
557 def fuseRmTestHelperDeleteFile(mounttmp):
558 class Test(unittest.TestCase):
560 # Can't delete because it's not empty
561 with self.assertRaises(OSError):
562 os.rmdir(os.path.join(mounttmp, "testdir"))
564 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
565 self.assertEqual(["file1.txt"], d1)
568 os.remove(os.path.join(mounttmp, "testdir", "file1.txt"))
570 # Make sure it's empty
571 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
572 self.assertEqual([], d1)
574 # Try to delete it again
575 with self.assertRaises(OSError):
576 os.remove(os.path.join(mounttmp, "testdir", "file1.txt"))
580 def fuseRmTestHelperRmdir(mounttmp):
581 class Test(unittest.TestCase):
583 # Should be able to delete now that it is empty
584 os.rmdir(os.path.join(mounttmp, "testdir"))
586 # Make sure it's empty
587 d1 = llfuse.listdir(os.path.join(mounttmp))
588 self.assertEqual([], d1)
590 # Try to delete it again
591 with self.assertRaises(OSError):
592 os.rmdir(os.path.join(mounttmp, "testdir"))
596 class FuseRmTest(MountTestBase):
598 collection = arvados.collection.Collection(api_client=self.api)
599 collection.save_new()
601 m = self.make_mount(fuse.CollectionDirectory)
603 m.new_collection(collection.api_response(), collection)
604 self.assertTrue(m.writable())
606 self.pool.apply(fuseRmTestHelperWriteFile, (self.mounttmp,))
609 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
610 self.assertRegexpMatches(collection2["manifest_text"],
611 r'\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
612 self.pool.apply(fuseRmTestHelperDeleteFile, (self.mounttmp,))
614 # Can't have empty directories :-( so manifest will be empty.
615 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
616 self.assertEqual(collection2["manifest_text"], "")
618 self.pool.apply(fuseRmTestHelperRmdir, (self.mounttmp,))
620 # manifest should be empty now.
621 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
622 self.assertEqual(collection2["manifest_text"], "")
625 def fuseMvFileTestHelperWriteFile(mounttmp):
626 class Test(unittest.TestCase):
628 os.mkdir(os.path.join(mounttmp, "testdir"))
630 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
631 f.write("Hello world!")
635 def fuseMvFileTestHelperMoveFile(mounttmp):
636 class Test(unittest.TestCase):
638 d1 = llfuse.listdir(os.path.join(mounttmp))
639 self.assertEqual(["testdir"], d1)
640 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
641 self.assertEqual(["file1.txt"], d1)
643 os.rename(os.path.join(mounttmp, "testdir", "file1.txt"), os.path.join(mounttmp, "file1.txt"))
645 d1 = llfuse.listdir(os.path.join(mounttmp))
646 self.assertEqual(["file1.txt", "testdir"], sorted(d1))
647 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
648 self.assertEqual([], d1)
652 class FuseMvFileTest(MountTestBase):
654 collection = arvados.collection.Collection(api_client=self.api)
655 collection.save_new()
657 m = self.make_mount(fuse.CollectionDirectory)
659 m.new_collection(collection.api_response(), collection)
660 self.assertTrue(m.writable())
662 self.pool.apply(fuseMvFileTestHelperWriteFile, (self.mounttmp,))
665 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
666 self.assertRegexpMatches(collection2["manifest_text"],
667 r'\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
669 self.pool.apply(fuseMvFileTestHelperMoveFile, (self.mounttmp,))
671 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
672 self.assertRegexpMatches(collection2["manifest_text"],
673 r'\. 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
676 def fuseRenameTestHelper(mounttmp):
677 class Test(unittest.TestCase):
679 os.mkdir(os.path.join(mounttmp, "testdir"))
681 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
682 f.write("Hello world!")
686 class FuseRenameTest(MountTestBase):
688 collection = arvados.collection.Collection(api_client=self.api)
689 collection.save_new()
691 m = self.make_mount(fuse.CollectionDirectory)
693 m.new_collection(collection.api_response(), collection)
694 self.assertTrue(m.writable())
696 self.pool.apply(fuseRenameTestHelper, (self.mounttmp,))
699 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
700 self.assertRegexpMatches(collection2["manifest_text"],
701 r'\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
703 d1 = llfuse.listdir(os.path.join(self.mounttmp))
704 self.assertEqual(["testdir"], d1)
705 d1 = llfuse.listdir(os.path.join(self.mounttmp, "testdir"))
706 self.assertEqual(["file1.txt"], d1)
708 os.rename(os.path.join(self.mounttmp, "testdir"), os.path.join(self.mounttmp, "testdir2"))
710 d1 = llfuse.listdir(os.path.join(self.mounttmp))
711 self.assertEqual(["testdir2"], sorted(d1))
712 d1 = llfuse.listdir(os.path.join(self.mounttmp, "testdir2"))
713 self.assertEqual(["file1.txt"], d1)
715 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
716 self.assertRegexpMatches(collection2["manifest_text"],
717 r'\./testdir2 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
720 class FuseUpdateFromEventTest(MountTestBase):
722 collection = arvados.collection.Collection(api_client=self.api)
723 collection.save_new()
725 m = self.make_mount(fuse.CollectionDirectory)
727 m.new_collection(collection.api_response(), collection)
729 self.operations.listen_for_events()
731 d1 = llfuse.listdir(os.path.join(self.mounttmp))
732 self.assertEqual([], sorted(d1))
734 with arvados.collection.Collection(collection.manifest_locator(), api_client=self.api) as collection2:
735 with collection2.open("file1.txt", "w") as f:
738 for attempt in AssertWithTimeout(10):
739 attempt(self.assertEqual, ["file1.txt"], llfuse.listdir(os.path.join(self.mounttmp)))
742 class FuseDeleteProjectEventTest(MountTestBase):
745 aproject = self.api.groups().create(body={
747 "group_class": "project"
750 bproject = self.api.groups().create(body={
752 "group_class": "project",
753 "owner_uuid": aproject["uuid"]
756 self.make_mount(fuse.ProjectDirectory,
757 project_object=self.api.users().current().execute())
759 self.operations.listen_for_events()
761 d1 = llfuse.listdir(os.path.join(self.mounttmp, "aproject"))
762 self.assertEqual(["bproject"], sorted(d1))
764 self.api.groups().delete(uuid=bproject["uuid"]).execute()
766 for attempt in AssertWithTimeout(10):
767 attempt(self.assertEqual, [], llfuse.listdir(os.path.join(self.mounttmp, "aproject")))
770 def fuseFileConflictTestHelper(mounttmp):
771 class Test(unittest.TestCase):
773 with open(os.path.join(mounttmp, "file1.txt"), "w") as f:
776 d1 = sorted(llfuse.listdir(os.path.join(mounttmp)))
777 self.assertEqual(len(d1), 2)
779 with open(os.path.join(mounttmp, "file1.txt"), "r") as f:
780 self.assertEqual(f.read(), "bar")
782 self.assertRegexpMatches(d1[1],
783 r'file1\.txt~\d\d\d\d\d\d\d\d-\d\d\d\d\d\d~conflict~')
785 with open(os.path.join(mounttmp, d1[1]), "r") as f:
786 self.assertEqual(f.read(), "foo")
790 class FuseFileConflictTest(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 d1 = llfuse.listdir(os.path.join(self.mounttmp))
800 self.assertEqual([], sorted(d1))
802 with arvados.collection.Collection(collection.manifest_locator(), api_client=self.api) as collection2:
803 with collection2.open("file1.txt", "w") as f:
806 # See note in MountTestBase.setUp
807 self.pool.apply(fuseFileConflictTestHelper, (self.mounttmp,))
810 def fuseUnlinkOpenFileTest(mounttmp):
811 class Test(unittest.TestCase):
813 with open(os.path.join(mounttmp, "file1.txt"), "w+") as f:
816 d1 = llfuse.listdir(os.path.join(mounttmp))
817 self.assertEqual(["file1.txt"], sorted(d1))
819 os.remove(os.path.join(mounttmp, "file1.txt"))
821 d1 = llfuse.listdir(os.path.join(mounttmp))
822 self.assertEqual([], sorted(d1))
825 self.assertEqual(f.read(), "foo")
829 self.assertEqual(f.read(), "foobar")
833 class FuseUnlinkOpenFileTest(MountTestBase):
835 collection = arvados.collection.Collection(api_client=self.api)
836 collection.save_new()
838 m = self.make_mount(fuse.CollectionDirectory)
840 m.new_collection(collection.api_response(), collection)
842 # See note in MountTestBase.setUp
843 self.pool.apply(fuseUnlinkOpenFileTest, (self.mounttmp,))
845 self.assertEqual(collection.manifest_text(), "")
848 def fuseMvFileBetweenCollectionsTest1(mounttmp, uuid1, uuid2):
849 class Test(unittest.TestCase):
851 with open(os.path.join(mounttmp, uuid1, "file1.txt"), "w") as f:
852 f.write("Hello world!")
854 d1 = os.listdir(os.path.join(mounttmp, uuid1))
855 self.assertEqual(["file1.txt"], sorted(d1))
856 d1 = os.listdir(os.path.join(mounttmp, uuid2))
857 self.assertEqual([], sorted(d1))
861 def fuseMvFileBetweenCollectionsTest2(mounttmp, uuid1, uuid2):
862 class Test(unittest.TestCase):
864 os.rename(os.path.join(mounttmp, uuid1, "file1.txt"), os.path.join(mounttmp, uuid2, "file2.txt"))
866 d1 = os.listdir(os.path.join(mounttmp, uuid1))
867 self.assertEqual([], sorted(d1))
868 d1 = os.listdir(os.path.join(mounttmp, uuid2))
869 self.assertEqual(["file2.txt"], sorted(d1))
873 class FuseMvFileBetweenCollectionsTest(MountTestBase):
875 collection1 = arvados.collection.Collection(api_client=self.api)
876 collection1.save_new()
878 collection2 = arvados.collection.Collection(api_client=self.api)
879 collection2.save_new()
881 m = self.make_mount(fuse.MagicDirectory)
883 # See note in MountTestBase.setUp
884 self.pool.apply(fuseMvFileBetweenCollectionsTest1, (self.mounttmp,
885 collection1.manifest_locator(),
886 collection2.manifest_locator()))
891 self.assertRegexpMatches(collection1.manifest_text(), r"\. 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$")
892 self.assertEqual(collection2.manifest_text(), "")
894 self.pool.apply(fuseMvFileBetweenCollectionsTest2, (self.mounttmp,
895 collection1.manifest_locator(),
896 collection2.manifest_locator()))
901 self.assertEqual(collection1.manifest_text(), "")
902 self.assertRegexpMatches(collection2.manifest_text(), r"\. 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file2\.txt$")
904 collection1.stop_threads()
905 collection2.stop_threads()
908 def fuseMvDirBetweenCollectionsTest1(mounttmp, uuid1, uuid2):
909 class Test(unittest.TestCase):
911 os.mkdir(os.path.join(mounttmp, uuid1, "testdir"))
912 with open(os.path.join(mounttmp, uuid1, "testdir", "file1.txt"), "w") as f:
913 f.write("Hello world!")
915 d1 = os.listdir(os.path.join(mounttmp, uuid1))
916 self.assertEqual(["testdir"], sorted(d1))
917 d1 = os.listdir(os.path.join(mounttmp, uuid1, "testdir"))
918 self.assertEqual(["file1.txt"], sorted(d1))
920 d1 = os.listdir(os.path.join(mounttmp, uuid2))
921 self.assertEqual([], sorted(d1))
926 def fuseMvDirBetweenCollectionsTest2(mounttmp, uuid1, uuid2):
927 class Test(unittest.TestCase):
929 os.rename(os.path.join(mounttmp, uuid1, "testdir"), os.path.join(mounttmp, uuid2, "testdir2"))
931 d1 = os.listdir(os.path.join(mounttmp, uuid1))
932 self.assertEqual([], sorted(d1))
934 d1 = os.listdir(os.path.join(mounttmp, uuid2))
935 self.assertEqual(["testdir2"], sorted(d1))
936 d1 = os.listdir(os.path.join(mounttmp, uuid2, "testdir2"))
937 self.assertEqual(["file1.txt"], sorted(d1))
939 with open(os.path.join(mounttmp, uuid2, "testdir2", "file1.txt"), "r") as f:
940 self.assertEqual(f.read(), "Hello world!")
944 class FuseMvDirBetweenCollectionsTest(MountTestBase):
946 collection1 = arvados.collection.Collection(api_client=self.api)
947 collection1.save_new()
949 collection2 = arvados.collection.Collection(api_client=self.api)
950 collection2.save_new()
952 m = self.make_mount(fuse.MagicDirectory)
954 # See note in MountTestBase.setUp
955 self.pool.apply(fuseMvDirBetweenCollectionsTest1, (self.mounttmp,
956 collection1.manifest_locator(),
957 collection2.manifest_locator()))
962 self.assertRegexpMatches(collection1.manifest_text(), r"\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$")
963 self.assertEqual(collection2.manifest_text(), "")
965 self.pool.apply(fuseMvDirBetweenCollectionsTest2, (self.mounttmp,
966 collection1.manifest_locator(),
967 collection2.manifest_locator()))
972 self.assertEqual(collection1.manifest_text(), "")
973 self.assertRegexpMatches(collection2.manifest_text(), r"\./testdir2 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$")
975 collection1.stop_threads()
976 collection2.stop_threads()
978 def fuseProjectMkdirTestHelper1(mounttmp):
979 class Test(unittest.TestCase):
981 os.mkdir(os.path.join(mounttmp, "testcollection"))
982 with self.assertRaises(OSError):
983 os.mkdir(os.path.join(mounttmp, "testcollection"))
986 def fuseProjectMkdirTestHelper2(mounttmp):
987 class Test(unittest.TestCase):
989 with open(os.path.join(mounttmp, "testcollection", "file1.txt"), "w") as f:
990 f.write("Hello world!")
991 with self.assertRaises(OSError):
992 os.rmdir(os.path.join(mounttmp, "testcollection"))
993 os.remove(os.path.join(mounttmp, "testcollection", "file1.txt"))
994 with self.assertRaises(OSError):
995 os.remove(os.path.join(mounttmp, "testcollection"))
996 os.rmdir(os.path.join(mounttmp, "testcollection"))
999 class FuseProjectMkdirRmdirTest(MountTestBase):
1001 self.make_mount(fuse.ProjectDirectory,
1002 project_object=self.api.users().current().execute())
1004 d1 = llfuse.listdir(self.mounttmp)
1005 self.assertNotIn('testcollection', d1)
1007 self.pool.apply(fuseProjectMkdirTestHelper1, (self.mounttmp,))
1009 d1 = llfuse.listdir(self.mounttmp)
1010 self.assertIn('testcollection', d1)
1012 self.pool.apply(fuseProjectMkdirTestHelper2, (self.mounttmp,))
1014 d1 = llfuse.listdir(self.mounttmp)
1015 self.assertNotIn('testcollection', d1)
1018 def fuseProjectMvTestHelper1(mounttmp):
1019 class Test(unittest.TestCase):
1021 d1 = llfuse.listdir(mounttmp)
1022 self.assertNotIn('testcollection', d1)
1024 os.mkdir(os.path.join(mounttmp, "testcollection"))
1026 d1 = llfuse.listdir(mounttmp)
1027 self.assertIn('testcollection', d1)
1029 with self.assertRaises(OSError):
1030 os.rename(os.path.join(mounttmp, "testcollection"), os.path.join(mounttmp, 'Unrestricted public data'))
1032 os.rename(os.path.join(mounttmp, "testcollection"), os.path.join(mounttmp, 'Unrestricted public data', 'testcollection'))
1034 d1 = llfuse.listdir(mounttmp)
1035 self.assertNotIn('testcollection', d1)
1037 d1 = llfuse.listdir(os.path.join(mounttmp, 'Unrestricted public data'))
1038 self.assertIn('testcollection', d1)
1042 class FuseProjectMvTest(MountTestBase):
1044 self.make_mount(fuse.ProjectDirectory,
1045 project_object=self.api.users().current().execute())
1047 self.pool.apply(fuseProjectMvTestHelper1, (self.mounttmp,))
1050 def fuseFsyncTestHelper(mounttmp, k):
1051 class Test(unittest.TestCase):
1053 fd = os.open(os.path.join(mounttmp, k), os.O_RDONLY)
1059 class FuseFsyncTest(FuseMagicTest):
1061 self.make_mount(fuse.MagicDirectory)
1062 self.pool.apply(fuseFsyncTestHelper, (self.mounttmp, self.testcollection))
1065 class MagicDirApiError(FuseMagicTest):
1067 api = mock.MagicMock()
1068 super(MagicDirApiError, self).setUp(api=api)
1069 api.collections().get().execute.side_effect = iter([
1070 Exception('API fail'),
1072 "manifest_text": self.test_manifest,
1073 "portable_data_hash": self.test_manifest_pdh,
1076 api.keep.get.side_effect = Exception('Keep fail')
1079 self.make_mount(fuse.MagicDirectory)
1081 self.operations.inodes.inode_cache.cap = 1
1082 self.operations.inodes.inode_cache.min_entries = 2
1084 with self.assertRaises(OSError):
1085 llfuse.listdir(os.path.join(self.mounttmp, self.testcollection))
1087 llfuse.listdir(os.path.join(self.mounttmp, self.testcollection))
1090 class FuseUnitTest(unittest.TestCase):
1091 def test_sanitize_filename(self):
1110 for f in acceptable:
1111 self.assertEqual(f, fuse.sanitize_filename(f))
1112 for f in unacceptable:
1113 self.assertNotEqual(f, fuse.sanitize_filename(f))
1114 # The sanitized filename should be the same length, though.
1115 self.assertEqual(len(f), len(fuse.sanitize_filename(f)))
1117 self.assertEqual("_", fuse.sanitize_filename(""))
1118 self.assertEqual("_", fuse.sanitize_filename("."))
1119 self.assertEqual("__", fuse.sanitize_filename(".."))
1122 class FuseMagicTestPDHOnly(MountTestBase):
1123 def setUp(self, api=None):
1124 super(FuseMagicTestPDHOnly, self).setUp(api=api)
1126 cw = arvados.CollectionWriter()
1128 cw.start_new_file('thing1.txt')
1131 self.testcollection = cw.finish()
1132 self.test_manifest = cw.manifest_text()
1133 created = self.api.collections().create(body={"manifest_text":self.test_manifest}).execute()
1134 self.testcollectionuuid = str(created['uuid'])
1136 def verify_pdh_only(self, pdh_only=False, skip_pdh_only=False):
1137 if skip_pdh_only is True:
1138 self.make_mount(fuse.MagicDirectory) # in this case, the default by_id applies
1140 self.make_mount(fuse.MagicDirectory, pdh_only=pdh_only)
1142 mount_ls = llfuse.listdir(self.mounttmp)
1143 self.assertIn('README', mount_ls)
1144 self.assertFalse(any(arvados.util.keep_locator_pattern.match(fn) or
1145 arvados.util.uuid_pattern.match(fn)
1146 for fn in mount_ls),
1147 "new FUSE MagicDirectory lists Collection")
1149 # look up using pdh should succeed in all cases
1150 self.assertDirContents(self.testcollection, ['thing1.txt'])
1151 self.assertDirContents(os.path.join('by_id', self.testcollection),
1153 mount_ls = llfuse.listdir(self.mounttmp)
1154 self.assertIn('README', mount_ls)
1155 self.assertIn(self.testcollection, mount_ls)
1156 self.assertIn(self.testcollection,
1157 llfuse.listdir(os.path.join(self.mounttmp, 'by_id')))
1160 files[os.path.join(self.mounttmp, self.testcollection, 'thing1.txt')] = 'data 1'
1162 for k, v in files.items():
1163 with open(os.path.join(self.mounttmp, k)) as f:
1164 self.assertEqual(v, f.read())
1166 # look up using uuid should fail when pdh_only is set
1167 if pdh_only is True:
1168 with self.assertRaises(OSError):
1169 self.assertDirContents(os.path.join('by_id', self.testcollectionuuid),
1172 self.assertDirContents(os.path.join('by_id', self.testcollectionuuid),
1175 def test_with_pdh_only_true(self):
1176 self.verify_pdh_only(pdh_only=True)
1178 def test_with_pdh_only_false(self):
1179 self.verify_pdh_only(pdh_only=False)
1181 def test_with_default_by_id(self):
1182 self.verify_pdh_only(skip_pdh_only=True)