1 # Copyright (C) The Arvados Authors. All rights reserved.
3 # SPDX-License-Identifier: AGPL-3.0
5 from __future__ import absolute_import
16 import arvados_fuse as fuse
17 from . import run_test_server
19 from .mount_test_base import MountTestBase
21 logger = logging.getLogger('arvados.arv-mount')
24 class AssertWithTimeout(object):
25 """Allow some time for an assertion to pass."""
27 def __init__(self, timeout=0):
28 self.timeout = timeout
31 self.deadline = time.time() + self.timeout
40 def attempt(self, fn, *args, **kwargs):
43 except AssertionError:
44 if time.time() > self.deadline:
51 class FuseMountTest(MountTestBase):
53 super(FuseMountTest, self).setUp()
55 cw = arvados.CollectionWriter()
57 cw.start_new_file('thing1.txt')
59 cw.start_new_file('thing2.txt')
62 cw.start_new_stream('dir1')
63 cw.start_new_file('thing3.txt')
65 cw.start_new_file('thing4.txt')
68 cw.start_new_stream('dir2')
69 cw.start_new_file('thing5.txt')
71 cw.start_new_file('thing6.txt')
74 cw.start_new_stream('dir2/dir3')
75 cw.start_new_file('thing7.txt')
78 cw.start_new_file('thing8.txt')
81 cw.start_new_stream('edgecases')
82 for f in ":/.../-/*/ ".split("/"):
86 for f in ":/.../-/*/ ".split("/"):
87 cw.start_new_stream('edgecases/dirs/' + f)
88 cw.start_new_file('x/x')
91 self.testcollection = cw.finish()
92 self.api.collections().create(body={"manifest_text":cw.manifest_text()}).execute()
95 self.make_mount(fuse.CollectionDirectory, collection_record=self.testcollection)
97 self.assertDirContents(None, ['thing1.txt', 'thing2.txt',
98 'edgecases', 'dir1', 'dir2'])
99 self.assertDirContents('dir1', ['thing3.txt', 'thing4.txt'])
100 self.assertDirContents('dir2', ['thing5.txt', 'thing6.txt', 'dir3'])
101 self.assertDirContents('dir2/dir3', ['thing7.txt', 'thing8.txt'])
102 self.assertDirContents('edgecases',
103 "dirs/:/.../-/*/ ".split("/"))
104 self.assertDirContents('edgecases/dirs',
105 ":/.../-/*/ ".split("/"))
107 files = {'thing1.txt': 'data 1',
108 'thing2.txt': 'data 2',
109 'dir1/thing3.txt': 'data 3',
110 'dir1/thing4.txt': 'data 4',
111 'dir2/thing5.txt': 'data 5',
112 'dir2/thing6.txt': 'data 6',
113 'dir2/dir3/thing7.txt': 'data 7',
114 'dir2/dir3/thing8.txt': 'data 8'}
116 for k, v in files.items():
117 with open(os.path.join(self.mounttmp, k)) as f:
118 self.assertEqual(v, f.read())
121 class FuseMagicTest(MountTestBase):
122 def setUp(self, api=None):
123 super(FuseMagicTest, self).setUp(api=api)
125 self.test_project = run_test_server.fixture('groups')['aproject']['uuid']
126 self.non_project_group = run_test_server.fixture('groups')['public']['uuid']
127 self.collection_in_test_project = run_test_server.fixture('collections')['foo_collection_in_aproject']['name']
129 cw = arvados.CollectionWriter()
131 cw.start_new_file('thing1.txt')
134 self.testcollection = cw.finish()
135 self.test_manifest = cw.manifest_text()
136 coll = self.api.collections().create(body={"manifest_text":self.test_manifest}).execute()
137 self.test_manifest_pdh = coll['portable_data_hash']
140 self.make_mount(fuse.MagicDirectory)
142 mount_ls = llfuse.listdir(self.mounttmp)
143 self.assertIn('README', mount_ls)
144 self.assertFalse(any(arvados.util.keep_locator_pattern.match(fn) or
145 arvados.util.uuid_pattern.match(fn)
147 "new FUSE MagicDirectory has no collections or projects")
148 self.assertDirContents(self.testcollection, ['thing1.txt'])
149 self.assertDirContents(os.path.join('by_id', self.testcollection),
151 self.assertIn(self.collection_in_test_project,
152 llfuse.listdir(os.path.join(self.mounttmp, self.test_project)))
153 self.assertIn(self.collection_in_test_project,
154 llfuse.listdir(os.path.join(self.mounttmp, 'by_id', self.test_project)))
156 mount_ls = llfuse.listdir(self.mounttmp)
157 self.assertIn('README', mount_ls)
158 self.assertIn(self.testcollection, mount_ls)
159 self.assertIn(self.testcollection,
160 llfuse.listdir(os.path.join(self.mounttmp, 'by_id')))
161 self.assertIn(self.test_project, mount_ls)
162 self.assertIn(self.test_project,
163 llfuse.listdir(os.path.join(self.mounttmp, 'by_id')))
165 with self.assertRaises(OSError):
166 llfuse.listdir(os.path.join(self.mounttmp, 'by_id', self.non_project_group))
169 files[os.path.join(self.mounttmp, self.testcollection, 'thing1.txt')] = 'data 1'
171 for k, v in files.items():
172 with open(os.path.join(self.mounttmp, k)) as f:
173 self.assertEqual(v, f.read())
176 class FuseTagsTest(MountTestBase):
178 self.make_mount(fuse.TagsDirectory)
180 d1 = llfuse.listdir(self.mounttmp)
182 self.assertEqual(['foo_tag'], d1)
184 d2 = llfuse.listdir(os.path.join(self.mounttmp, 'foo_tag'))
186 self.assertEqual(['zzzzz-4zz18-fy296fx3hot09f7'], d2)
188 d3 = llfuse.listdir(os.path.join(self.mounttmp, 'foo_tag', 'zzzzz-4zz18-fy296fx3hot09f7'))
190 self.assertEqual(['foo'], d3)
193 class FuseTagsUpdateTest(MountTestBase):
194 def tag_collection(self, coll_uuid, tag_name):
195 return self.api.links().create(
196 body={'link': {'head_uuid': coll_uuid,
202 self.make_mount(fuse.TagsDirectory, poll_time=1)
204 self.assertIn('foo_tag', llfuse.listdir(self.mounttmp))
206 bar_uuid = run_test_server.fixture('collections')['bar_file']['uuid']
207 self.tag_collection(bar_uuid, 'fuse_test_tag')
208 for attempt in AssertWithTimeout(10):
209 attempt(self.assertIn, 'fuse_test_tag', llfuse.listdir(self.mounttmp))
210 self.assertDirContents('fuse_test_tag', [bar_uuid])
212 baz_uuid = run_test_server.fixture('collections')['baz_file']['uuid']
213 l = self.tag_collection(baz_uuid, 'fuse_test_tag')
214 for attempt in AssertWithTimeout(10):
215 attempt(self.assertDirContents, 'fuse_test_tag', [bar_uuid, baz_uuid])
217 self.api.links().delete(uuid=l['uuid']).execute()
218 for attempt in AssertWithTimeout(10):
219 attempt(self.assertDirContents, 'fuse_test_tag', [bar_uuid])
222 def fuseSharedTestHelper(mounttmp):
223 class Test(unittest.TestCase):
225 # Double check that we can open and read objects in this folder as a file,
226 # and that its contents are what we expect.
227 baz_path = os.path.join(
231 'collection in FUSE project',
233 with open(baz_path) as f:
234 self.assertEqual("baz", f.read())
236 # check mtime on collection
237 st = os.stat(baz_path)
239 mtime = st.st_mtime_ns / 1000000000
240 except AttributeError:
242 self.assertEqual(mtime, 1391448174)
244 # shared_dirs is a list of the directories exposed
245 # by fuse.SharedDirectory (i.e. any object visible
246 # to the current user)
247 shared_dirs = llfuse.listdir(mounttmp)
249 self.assertIn('FUSE User', shared_dirs)
251 # fuse_user_objs is a list of the objects owned by the FUSE
252 # test user (which present as files in the 'FUSE User'
254 fuse_user_objs = llfuse.listdir(os.path.join(mounttmp, 'FUSE User'))
255 fuse_user_objs.sort()
256 self.assertEqual(['FUSE Test Project', # project owned by user
257 'collection #1 owned by FUSE', # collection owned by user
258 'collection #2 owned by FUSE' # collection owned by user
261 # test_proj_files is a list of the files in the FUSE Test Project.
262 test_proj_files = llfuse.listdir(os.path.join(mounttmp, 'FUSE User', 'FUSE Test Project'))
263 test_proj_files.sort()
264 self.assertEqual(['collection in FUSE project'
270 class FuseSharedTest(MountTestBase):
272 self.make_mount(fuse.SharedDirectory,
273 exclude=self.api.users().current().execute()['uuid'])
274 keep = arvados.keep.KeepClient()
277 self.pool.apply(fuseSharedTestHelper, (self.mounttmp,))
280 class FuseHomeTest(MountTestBase):
282 self.make_mount(fuse.ProjectDirectory,
283 project_object=self.api.users().current().execute())
285 d1 = llfuse.listdir(self.mounttmp)
286 self.assertIn('Unrestricted public data', d1)
288 d2 = llfuse.listdir(os.path.join(self.mounttmp, 'Unrestricted public data'))
289 public_project = run_test_server.fixture('groups')[
290 'anonymously_accessible_project']
293 for name, item in run_test_server.fixture('collections').iteritems():
294 if 'name' not in item:
296 elif item['owner_uuid'] == public_project['uuid']:
297 self.assertIn(item['name'], d2)
300 # Artificial assumption here: there is no public
301 # collection fixture with the same name as a
302 # non-public collection.
303 self.assertNotIn(item['name'], d2)
305 self.assertNotEqual(0, found_in)
306 self.assertNotEqual(0, found_not_in)
308 d3 = llfuse.listdir(os.path.join(self.mounttmp, 'Unrestricted public data', 'GNU General Public License, version 3'))
309 self.assertEqual(["GNU_General_Public_License,_version_3.pdf"], d3)
312 def fuseModifyFileTestHelperReadStartContents(mounttmp):
313 class Test(unittest.TestCase):
315 d1 = llfuse.listdir(mounttmp)
316 self.assertEqual(["file1.txt"], d1)
317 with open(os.path.join(mounttmp, "file1.txt")) as f:
318 self.assertEqual("blub", f.read())
321 def fuseModifyFileTestHelperReadEndContents(mounttmp):
322 class Test(unittest.TestCase):
324 d1 = llfuse.listdir(mounttmp)
325 self.assertEqual(["file1.txt"], d1)
326 with open(os.path.join(mounttmp, "file1.txt")) as f:
327 self.assertEqual("plnp", f.read())
330 class FuseModifyFileTest(MountTestBase):
332 collection = arvados.collection.Collection(api_client=self.api)
333 with collection.open("file1.txt", "w") as f:
336 collection.save_new()
338 m = self.make_mount(fuse.CollectionDirectory)
340 m.new_collection(collection.api_response(), collection)
342 self.pool.apply(fuseModifyFileTestHelperReadStartContents, (self.mounttmp,))
344 with collection.open("file1.txt", "w") as f:
347 self.pool.apply(fuseModifyFileTestHelperReadEndContents, (self.mounttmp,))
350 class FuseAddFileToCollectionTest(MountTestBase):
352 collection = arvados.collection.Collection(api_client=self.api)
353 with collection.open("file1.txt", "w") as f:
356 collection.save_new()
358 m = self.make_mount(fuse.CollectionDirectory)
360 m.new_collection(collection.api_response(), collection)
362 d1 = llfuse.listdir(self.mounttmp)
363 self.assertEqual(["file1.txt"], d1)
365 with collection.open("file2.txt", "w") as f:
368 d1 = llfuse.listdir(self.mounttmp)
369 self.assertEqual(["file1.txt", "file2.txt"], sorted(d1))
372 class FuseRemoveFileFromCollectionTest(MountTestBase):
374 collection = arvados.collection.Collection(api_client=self.api)
375 with collection.open("file1.txt", "w") as f:
378 with collection.open("file2.txt", "w") as f:
381 collection.save_new()
383 m = self.make_mount(fuse.CollectionDirectory)
385 m.new_collection(collection.api_response(), collection)
387 d1 = llfuse.listdir(self.mounttmp)
388 self.assertEqual(["file1.txt", "file2.txt"], sorted(d1))
390 collection.remove("file2.txt")
392 d1 = llfuse.listdir(self.mounttmp)
393 self.assertEqual(["file1.txt"], d1)
396 def fuseCreateFileTestHelper(mounttmp):
397 class Test(unittest.TestCase):
399 with open(os.path.join(mounttmp, "file1.txt"), "w") as f:
403 class FuseCreateFileTest(MountTestBase):
405 collection = arvados.collection.Collection(api_client=self.api)
406 collection.save_new()
408 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
409 self.assertEqual(collection2["manifest_text"], "")
411 collection.save_new()
413 m = self.make_mount(fuse.CollectionDirectory)
415 m.new_collection(collection.api_response(), collection)
416 self.assertTrue(m.writable())
418 self.assertNotIn("file1.txt", collection)
420 self.pool.apply(fuseCreateFileTestHelper, (self.mounttmp,))
422 self.assertIn("file1.txt", collection)
424 d1 = llfuse.listdir(self.mounttmp)
425 self.assertEqual(["file1.txt"], d1)
427 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
428 self.assertRegexpMatches(collection2["manifest_text"],
429 r'\. d41d8cd98f00b204e9800998ecf8427e\+0\+A\S+ 0:0:file1\.txt$')
432 def fuseWriteFileTestHelperWriteFile(mounttmp):
433 class Test(unittest.TestCase):
435 with open(os.path.join(mounttmp, "file1.txt"), "w") as f:
436 f.write("Hello world!")
439 def fuseWriteFileTestHelperReadFile(mounttmp):
440 class Test(unittest.TestCase):
442 with open(os.path.join(mounttmp, "file1.txt"), "r") as f:
443 self.assertEqual(f.read(), "Hello world!")
446 class FuseWriteFileTest(MountTestBase):
448 collection = arvados.collection.Collection(api_client=self.api)
449 collection.save_new()
451 m = self.make_mount(fuse.CollectionDirectory)
453 m.new_collection(collection.api_response(), collection)
454 self.assertTrue(m.writable())
456 self.assertNotIn("file1.txt", collection)
458 self.assertEqual(0, self.operations.write_counter.get())
459 self.pool.apply(fuseWriteFileTestHelperWriteFile, (self.mounttmp,))
460 self.assertEqual(12, self.operations.write_counter.get())
462 with collection.open("file1.txt") as f:
463 self.assertEqual(f.read(), "Hello world!")
465 self.assertEqual(0, self.operations.read_counter.get())
466 self.pool.apply(fuseWriteFileTestHelperReadFile, (self.mounttmp,))
467 self.assertEqual(12, self.operations.read_counter.get())
469 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
470 self.assertRegexpMatches(collection2["manifest_text"],
471 r'\. 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
474 def fuseUpdateFileTestHelper(mounttmp):
475 class Test(unittest.TestCase):
477 with open(os.path.join(mounttmp, "file1.txt"), "w") as f:
478 f.write("Hello world!")
480 with open(os.path.join(mounttmp, "file1.txt"), "r+") as f:
482 self.assertEqual(fr, "Hello world!")
484 f.write("Hola mundo!")
487 self.assertEqual(fr, "Hola mundo!!")
489 with open(os.path.join(mounttmp, "file1.txt"), "r") as f:
490 self.assertEqual(f.read(), "Hola mundo!!")
494 class FuseUpdateFileTest(MountTestBase):
496 collection = arvados.collection.Collection(api_client=self.api)
497 collection.save_new()
499 m = self.make_mount(fuse.CollectionDirectory)
501 m.new_collection(collection.api_response(), collection)
502 self.assertTrue(m.writable())
504 # See note in MountTestBase.setUp
505 self.pool.apply(fuseUpdateFileTestHelper, (self.mounttmp,))
507 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
508 self.assertRegexpMatches(collection2["manifest_text"],
509 r'\. daaef200ebb921e011e3ae922dd3266b\+11\+A\S+ 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:11:file1\.txt 22:1:file1\.txt$')
512 def fuseMkdirTestHelper(mounttmp):
513 class Test(unittest.TestCase):
515 with self.assertRaises(IOError):
516 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
517 f.write("Hello world!")
519 os.mkdir(os.path.join(mounttmp, "testdir"))
521 with self.assertRaises(OSError):
522 os.mkdir(os.path.join(mounttmp, "testdir"))
524 d1 = llfuse.listdir(mounttmp)
525 self.assertEqual(["testdir"], d1)
527 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
528 f.write("Hello world!")
530 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
531 self.assertEqual(["file1.txt"], d1)
535 class FuseMkdirTest(MountTestBase):
537 collection = arvados.collection.Collection(api_client=self.api)
538 collection.save_new()
540 m = self.make_mount(fuse.CollectionDirectory)
542 m.new_collection(collection.api_response(), collection)
543 self.assertTrue(m.writable())
545 self.pool.apply(fuseMkdirTestHelper, (self.mounttmp,))
547 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
548 self.assertRegexpMatches(collection2["manifest_text"],
549 r'\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
552 def fuseRmTestHelperWriteFile(mounttmp):
553 class Test(unittest.TestCase):
555 os.mkdir(os.path.join(mounttmp, "testdir"))
557 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
558 f.write("Hello world!")
562 def fuseRmTestHelperDeleteFile(mounttmp):
563 class Test(unittest.TestCase):
565 # Can't delete because it's not empty
566 with self.assertRaises(OSError):
567 os.rmdir(os.path.join(mounttmp, "testdir"))
569 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
570 self.assertEqual(["file1.txt"], d1)
573 os.remove(os.path.join(mounttmp, "testdir", "file1.txt"))
575 # Make sure it's empty
576 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
577 self.assertEqual([], d1)
579 # Try to delete it again
580 with self.assertRaises(OSError):
581 os.remove(os.path.join(mounttmp, "testdir", "file1.txt"))
585 def fuseRmTestHelperRmdir(mounttmp):
586 class Test(unittest.TestCase):
588 # Should be able to delete now that it is empty
589 os.rmdir(os.path.join(mounttmp, "testdir"))
591 # Make sure it's empty
592 d1 = llfuse.listdir(os.path.join(mounttmp))
593 self.assertEqual([], d1)
595 # Try to delete it again
596 with self.assertRaises(OSError):
597 os.rmdir(os.path.join(mounttmp, "testdir"))
601 class FuseRmTest(MountTestBase):
603 collection = arvados.collection.Collection(api_client=self.api)
604 collection.save_new()
606 m = self.make_mount(fuse.CollectionDirectory)
608 m.new_collection(collection.api_response(), collection)
609 self.assertTrue(m.writable())
611 self.pool.apply(fuseRmTestHelperWriteFile, (self.mounttmp,))
614 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
615 self.assertRegexpMatches(collection2["manifest_text"],
616 r'\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
617 self.pool.apply(fuseRmTestHelperDeleteFile, (self.mounttmp,))
619 # Empty directories are represented by an empty file named "."
620 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
621 self.assertRegexpMatches(collection2["manifest_text"],
622 r'./testdir d41d8cd98f00b204e9800998ecf8427e\+0\+A\S+ 0:0:\\056\n')
624 self.pool.apply(fuseRmTestHelperRmdir, (self.mounttmp,))
626 # manifest should be empty now.
627 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
628 self.assertEqual(collection2["manifest_text"], "")
631 def fuseMvFileTestHelperWriteFile(mounttmp):
632 class Test(unittest.TestCase):
634 os.mkdir(os.path.join(mounttmp, "testdir"))
636 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
637 f.write("Hello world!")
641 def fuseMvFileTestHelperMoveFile(mounttmp):
642 class Test(unittest.TestCase):
644 d1 = llfuse.listdir(os.path.join(mounttmp))
645 self.assertEqual(["testdir"], d1)
646 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
647 self.assertEqual(["file1.txt"], d1)
649 os.rename(os.path.join(mounttmp, "testdir", "file1.txt"), os.path.join(mounttmp, "file1.txt"))
651 d1 = llfuse.listdir(os.path.join(mounttmp))
652 self.assertEqual(["file1.txt", "testdir"], sorted(d1))
653 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
654 self.assertEqual([], d1)
658 class FuseMvFileTest(MountTestBase):
660 collection = arvados.collection.Collection(api_client=self.api)
661 collection.save_new()
663 m = self.make_mount(fuse.CollectionDirectory)
665 m.new_collection(collection.api_response(), collection)
666 self.assertTrue(m.writable())
668 self.pool.apply(fuseMvFileTestHelperWriteFile, (self.mounttmp,))
671 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
672 self.assertRegexpMatches(collection2["manifest_text"],
673 r'\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
675 self.pool.apply(fuseMvFileTestHelperMoveFile, (self.mounttmp,))
677 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
678 self.assertRegexpMatches(collection2["manifest_text"],
679 r'\. 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt\n\./testdir d41d8cd98f00b204e9800998ecf8427e\+0\+A\S+ 0:0:\\056\n')
682 def fuseRenameTestHelper(mounttmp):
683 class Test(unittest.TestCase):
685 os.mkdir(os.path.join(mounttmp, "testdir"))
687 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
688 f.write("Hello world!")
692 class FuseRenameTest(MountTestBase):
694 collection = arvados.collection.Collection(api_client=self.api)
695 collection.save_new()
697 m = self.make_mount(fuse.CollectionDirectory)
699 m.new_collection(collection.api_response(), collection)
700 self.assertTrue(m.writable())
702 self.pool.apply(fuseRenameTestHelper, (self.mounttmp,))
705 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
706 self.assertRegexpMatches(collection2["manifest_text"],
707 r'\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
709 d1 = llfuse.listdir(os.path.join(self.mounttmp))
710 self.assertEqual(["testdir"], d1)
711 d1 = llfuse.listdir(os.path.join(self.mounttmp, "testdir"))
712 self.assertEqual(["file1.txt"], d1)
714 os.rename(os.path.join(self.mounttmp, "testdir"), os.path.join(self.mounttmp, "testdir2"))
716 d1 = llfuse.listdir(os.path.join(self.mounttmp))
717 self.assertEqual(["testdir2"], sorted(d1))
718 d1 = llfuse.listdir(os.path.join(self.mounttmp, "testdir2"))
719 self.assertEqual(["file1.txt"], d1)
721 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
722 self.assertRegexpMatches(collection2["manifest_text"],
723 r'\./testdir2 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
726 class FuseUpdateFromEventTest(MountTestBase):
728 collection = arvados.collection.Collection(api_client=self.api)
729 collection.save_new()
731 m = self.make_mount(fuse.CollectionDirectory)
733 m.new_collection(collection.api_response(), collection)
735 self.operations.listen_for_events()
737 d1 = llfuse.listdir(os.path.join(self.mounttmp))
738 self.assertEqual([], sorted(d1))
740 with arvados.collection.Collection(collection.manifest_locator(), api_client=self.api) as collection2:
741 with collection2.open("file1.txt", "w") as f:
744 for attempt in AssertWithTimeout(10):
745 attempt(self.assertEqual, ["file1.txt"], llfuse.listdir(os.path.join(self.mounttmp)))
748 class FuseDeleteProjectEventTest(MountTestBase):
751 aproject = self.api.groups().create(body={
753 "group_class": "project"
756 bproject = self.api.groups().create(body={
758 "group_class": "project",
759 "owner_uuid": aproject["uuid"]
762 self.make_mount(fuse.ProjectDirectory,
763 project_object=self.api.users().current().execute())
765 self.operations.listen_for_events()
767 d1 = llfuse.listdir(os.path.join(self.mounttmp, "aproject"))
768 self.assertEqual(["bproject"], sorted(d1))
770 self.api.groups().delete(uuid=bproject["uuid"]).execute()
772 for attempt in AssertWithTimeout(10):
773 attempt(self.assertEqual, [], llfuse.listdir(os.path.join(self.mounttmp, "aproject")))
776 def fuseFileConflictTestHelper(mounttmp):
777 class Test(unittest.TestCase):
779 with open(os.path.join(mounttmp, "file1.txt"), "w") as f:
782 d1 = sorted(llfuse.listdir(os.path.join(mounttmp)))
783 self.assertEqual(len(d1), 2)
785 with open(os.path.join(mounttmp, "file1.txt"), "r") as f:
786 self.assertEqual(f.read(), "bar")
788 self.assertRegexpMatches(d1[1],
789 r'file1\.txt~\d\d\d\d\d\d\d\d-\d\d\d\d\d\d~conflict~')
791 with open(os.path.join(mounttmp, d1[1]), "r") as f:
792 self.assertEqual(f.read(), "foo")
796 class FuseFileConflictTest(MountTestBase):
798 collection = arvados.collection.Collection(api_client=self.api)
799 collection.save_new()
801 m = self.make_mount(fuse.CollectionDirectory)
803 m.new_collection(collection.api_response(), collection)
805 d1 = llfuse.listdir(os.path.join(self.mounttmp))
806 self.assertEqual([], sorted(d1))
808 with arvados.collection.Collection(collection.manifest_locator(), api_client=self.api) as collection2:
809 with collection2.open("file1.txt", "w") as f:
812 # See note in MountTestBase.setUp
813 self.pool.apply(fuseFileConflictTestHelper, (self.mounttmp,))
816 def fuseUnlinkOpenFileTest(mounttmp):
817 class Test(unittest.TestCase):
819 with open(os.path.join(mounttmp, "file1.txt"), "w+") as f:
822 d1 = llfuse.listdir(os.path.join(mounttmp))
823 self.assertEqual(["file1.txt"], sorted(d1))
825 os.remove(os.path.join(mounttmp, "file1.txt"))
827 d1 = llfuse.listdir(os.path.join(mounttmp))
828 self.assertEqual([], sorted(d1))
831 self.assertEqual(f.read(), "foo")
835 self.assertEqual(f.read(), "foobar")
839 class FuseUnlinkOpenFileTest(MountTestBase):
841 collection = arvados.collection.Collection(api_client=self.api)
842 collection.save_new()
844 m = self.make_mount(fuse.CollectionDirectory)
846 m.new_collection(collection.api_response(), collection)
848 # See note in MountTestBase.setUp
849 self.pool.apply(fuseUnlinkOpenFileTest, (self.mounttmp,))
851 self.assertEqual(collection.manifest_text(), "")
854 def fuseMvFileBetweenCollectionsTest1(mounttmp, uuid1, uuid2):
855 class Test(unittest.TestCase):
857 with open(os.path.join(mounttmp, uuid1, "file1.txt"), "w") as f:
858 f.write("Hello world!")
860 d1 = os.listdir(os.path.join(mounttmp, uuid1))
861 self.assertEqual(["file1.txt"], sorted(d1))
862 d1 = os.listdir(os.path.join(mounttmp, uuid2))
863 self.assertEqual([], sorted(d1))
867 def fuseMvFileBetweenCollectionsTest2(mounttmp, uuid1, uuid2):
868 class Test(unittest.TestCase):
870 os.rename(os.path.join(mounttmp, uuid1, "file1.txt"), os.path.join(mounttmp, uuid2, "file2.txt"))
872 d1 = os.listdir(os.path.join(mounttmp, uuid1))
873 self.assertEqual([], sorted(d1))
874 d1 = os.listdir(os.path.join(mounttmp, uuid2))
875 self.assertEqual(["file2.txt"], sorted(d1))
879 class FuseMvFileBetweenCollectionsTest(MountTestBase):
881 collection1 = arvados.collection.Collection(api_client=self.api)
882 collection1.save_new()
884 collection2 = arvados.collection.Collection(api_client=self.api)
885 collection2.save_new()
887 m = self.make_mount(fuse.MagicDirectory)
889 # See note in MountTestBase.setUp
890 self.pool.apply(fuseMvFileBetweenCollectionsTest1, (self.mounttmp,
891 collection1.manifest_locator(),
892 collection2.manifest_locator()))
897 self.assertRegexpMatches(collection1.manifest_text(), r"\. 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$")
898 self.assertEqual(collection2.manifest_text(), "")
900 self.pool.apply(fuseMvFileBetweenCollectionsTest2, (self.mounttmp,
901 collection1.manifest_locator(),
902 collection2.manifest_locator()))
907 self.assertEqual(collection1.manifest_text(), "")
908 self.assertRegexpMatches(collection2.manifest_text(), r"\. 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file2\.txt$")
910 collection1.stop_threads()
911 collection2.stop_threads()
914 def fuseMvDirBetweenCollectionsTest1(mounttmp, uuid1, uuid2):
915 class Test(unittest.TestCase):
917 os.mkdir(os.path.join(mounttmp, uuid1, "testdir"))
918 with open(os.path.join(mounttmp, uuid1, "testdir", "file1.txt"), "w") as f:
919 f.write("Hello world!")
921 d1 = os.listdir(os.path.join(mounttmp, uuid1))
922 self.assertEqual(["testdir"], sorted(d1))
923 d1 = os.listdir(os.path.join(mounttmp, uuid1, "testdir"))
924 self.assertEqual(["file1.txt"], sorted(d1))
926 d1 = os.listdir(os.path.join(mounttmp, uuid2))
927 self.assertEqual([], sorted(d1))
932 def fuseMvDirBetweenCollectionsTest2(mounttmp, uuid1, uuid2):
933 class Test(unittest.TestCase):
935 os.rename(os.path.join(mounttmp, uuid1, "testdir"), os.path.join(mounttmp, uuid2, "testdir2"))
937 d1 = os.listdir(os.path.join(mounttmp, uuid1))
938 self.assertEqual([], sorted(d1))
940 d1 = os.listdir(os.path.join(mounttmp, uuid2))
941 self.assertEqual(["testdir2"], sorted(d1))
942 d1 = os.listdir(os.path.join(mounttmp, uuid2, "testdir2"))
943 self.assertEqual(["file1.txt"], sorted(d1))
945 with open(os.path.join(mounttmp, uuid2, "testdir2", "file1.txt"), "r") as f:
946 self.assertEqual(f.read(), "Hello world!")
950 class FuseMvDirBetweenCollectionsTest(MountTestBase):
952 collection1 = arvados.collection.Collection(api_client=self.api)
953 collection1.save_new()
955 collection2 = arvados.collection.Collection(api_client=self.api)
956 collection2.save_new()
958 m = self.make_mount(fuse.MagicDirectory)
960 # See note in MountTestBase.setUp
961 self.pool.apply(fuseMvDirBetweenCollectionsTest1, (self.mounttmp,
962 collection1.manifest_locator(),
963 collection2.manifest_locator()))
968 self.assertRegexpMatches(collection1.manifest_text(), r"\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$")
969 self.assertEqual(collection2.manifest_text(), "")
971 self.pool.apply(fuseMvDirBetweenCollectionsTest2, (self.mounttmp,
972 collection1.manifest_locator(),
973 collection2.manifest_locator()))
978 self.assertEqual(collection1.manifest_text(), "")
979 self.assertRegexpMatches(collection2.manifest_text(), r"\./testdir2 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$")
981 collection1.stop_threads()
982 collection2.stop_threads()
984 def fuseProjectMkdirTestHelper1(mounttmp):
985 class Test(unittest.TestCase):
987 os.mkdir(os.path.join(mounttmp, "testcollection"))
988 with self.assertRaises(OSError):
989 os.mkdir(os.path.join(mounttmp, "testcollection"))
992 def fuseProjectMkdirTestHelper2(mounttmp):
993 class Test(unittest.TestCase):
995 with open(os.path.join(mounttmp, "testcollection", "file1.txt"), "w") as f:
996 f.write("Hello world!")
997 with self.assertRaises(OSError):
998 os.rmdir(os.path.join(mounttmp, "testcollection"))
999 os.remove(os.path.join(mounttmp, "testcollection", "file1.txt"))
1000 with self.assertRaises(OSError):
1001 os.remove(os.path.join(mounttmp, "testcollection"))
1002 os.rmdir(os.path.join(mounttmp, "testcollection"))
1005 class FuseProjectMkdirRmdirTest(MountTestBase):
1007 self.make_mount(fuse.ProjectDirectory,
1008 project_object=self.api.users().current().execute())
1010 d1 = llfuse.listdir(self.mounttmp)
1011 self.assertNotIn('testcollection', d1)
1013 self.pool.apply(fuseProjectMkdirTestHelper1, (self.mounttmp,))
1015 d1 = llfuse.listdir(self.mounttmp)
1016 self.assertIn('testcollection', d1)
1018 self.pool.apply(fuseProjectMkdirTestHelper2, (self.mounttmp,))
1020 d1 = llfuse.listdir(self.mounttmp)
1021 self.assertNotIn('testcollection', d1)
1024 def fuseProjectMvTestHelper1(mounttmp):
1025 class Test(unittest.TestCase):
1027 d1 = llfuse.listdir(mounttmp)
1028 self.assertNotIn('testcollection', d1)
1030 os.mkdir(os.path.join(mounttmp, "testcollection"))
1032 d1 = llfuse.listdir(mounttmp)
1033 self.assertIn('testcollection', d1)
1035 with self.assertRaises(OSError):
1036 os.rename(os.path.join(mounttmp, "testcollection"), os.path.join(mounttmp, 'Unrestricted public data'))
1038 os.rename(os.path.join(mounttmp, "testcollection"), os.path.join(mounttmp, 'Unrestricted public data', 'testcollection'))
1040 d1 = llfuse.listdir(mounttmp)
1041 self.assertNotIn('testcollection', d1)
1043 d1 = llfuse.listdir(os.path.join(mounttmp, 'Unrestricted public data'))
1044 self.assertIn('testcollection', d1)
1048 class FuseProjectMvTest(MountTestBase):
1050 self.make_mount(fuse.ProjectDirectory,
1051 project_object=self.api.users().current().execute())
1053 self.pool.apply(fuseProjectMvTestHelper1, (self.mounttmp,))
1056 def fuseFsyncTestHelper(mounttmp, k):
1057 class Test(unittest.TestCase):
1059 fd = os.open(os.path.join(mounttmp, k), os.O_RDONLY)
1065 class FuseFsyncTest(FuseMagicTest):
1067 self.make_mount(fuse.MagicDirectory)
1068 self.pool.apply(fuseFsyncTestHelper, (self.mounttmp, self.testcollection))
1071 class MagicDirApiError(FuseMagicTest):
1073 api = mock.MagicMock()
1074 super(MagicDirApiError, self).setUp(api=api)
1075 api.collections().get().execute.side_effect = iter([
1076 Exception('API fail'),
1078 "manifest_text": self.test_manifest,
1079 "portable_data_hash": self.test_manifest_pdh,
1082 api.keep.get.side_effect = Exception('Keep fail')
1085 self.make_mount(fuse.MagicDirectory)
1087 self.operations.inodes.inode_cache.cap = 1
1088 self.operations.inodes.inode_cache.min_entries = 2
1090 with self.assertRaises(OSError):
1091 llfuse.listdir(os.path.join(self.mounttmp, self.testcollection))
1093 llfuse.listdir(os.path.join(self.mounttmp, self.testcollection))
1096 class FuseUnitTest(unittest.TestCase):
1097 def test_sanitize_filename(self):
1116 for f in acceptable:
1117 self.assertEqual(f, fuse.sanitize_filename(f))
1118 for f in unacceptable:
1119 self.assertNotEqual(f, fuse.sanitize_filename(f))
1120 # The sanitized filename should be the same length, though.
1121 self.assertEqual(len(f), len(fuse.sanitize_filename(f)))
1123 self.assertEqual("_", fuse.sanitize_filename(""))
1124 self.assertEqual("_", fuse.sanitize_filename("."))
1125 self.assertEqual("__", fuse.sanitize_filename(".."))
1128 class FuseMagicTestPDHOnly(MountTestBase):
1129 def setUp(self, api=None):
1130 super(FuseMagicTestPDHOnly, self).setUp(api=api)
1132 cw = arvados.CollectionWriter()
1134 cw.start_new_file('thing1.txt')
1137 self.testcollection = cw.finish()
1138 self.test_manifest = cw.manifest_text()
1139 created = self.api.collections().create(body={"manifest_text":self.test_manifest}).execute()
1140 self.testcollectionuuid = str(created['uuid'])
1142 def verify_pdh_only(self, pdh_only=False, skip_pdh_only=False):
1143 if skip_pdh_only is True:
1144 self.make_mount(fuse.MagicDirectory) # in this case, the default by_id applies
1146 self.make_mount(fuse.MagicDirectory, pdh_only=pdh_only)
1148 mount_ls = llfuse.listdir(self.mounttmp)
1149 self.assertIn('README', mount_ls)
1150 self.assertFalse(any(arvados.util.keep_locator_pattern.match(fn) or
1151 arvados.util.uuid_pattern.match(fn)
1152 for fn in mount_ls),
1153 "new FUSE MagicDirectory lists Collection")
1155 # look up using pdh should succeed in all cases
1156 self.assertDirContents(self.testcollection, ['thing1.txt'])
1157 self.assertDirContents(os.path.join('by_id', self.testcollection),
1159 mount_ls = llfuse.listdir(self.mounttmp)
1160 self.assertIn('README', mount_ls)
1161 self.assertIn(self.testcollection, mount_ls)
1162 self.assertIn(self.testcollection,
1163 llfuse.listdir(os.path.join(self.mounttmp, 'by_id')))
1166 files[os.path.join(self.mounttmp, self.testcollection, 'thing1.txt')] = 'data 1'
1168 for k, v in files.items():
1169 with open(os.path.join(self.mounttmp, k)) as f:
1170 self.assertEqual(v, f.read())
1172 # look up using uuid should fail when pdh_only is set
1173 if pdh_only is True:
1174 with self.assertRaises(OSError):
1175 self.assertDirContents(os.path.join('by_id', self.testcollectionuuid),
1178 self.assertDirContents(os.path.join('by_id', self.testcollectionuuid),
1181 def test_with_pdh_only_true(self):
1182 self.verify_pdh_only(pdh_only=True)
1184 def test_with_pdh_only_false(self):
1185 self.verify_pdh_only(pdh_only=False)
1187 def test_with_default_by_id(self):
1188 self.verify_pdh_only(skip_pdh_only=True)