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.non_project_group = run_test_server.fixture('groups')['public']['uuid']
126 self.collection_in_test_project = run_test_server.fixture('collections')['foo_collection_in_aproject']['name']
128 cw = arvados.CollectionWriter()
130 cw.start_new_file('thing1.txt')
133 self.testcollection = cw.finish()
134 self.test_manifest = cw.manifest_text()
135 coll = self.api.collections().create(body={"manifest_text":self.test_manifest}).execute()
136 self.test_manifest_pdh = coll['portable_data_hash']
139 self.make_mount(fuse.MagicDirectory)
141 mount_ls = llfuse.listdir(self.mounttmp)
142 self.assertIn('README', mount_ls)
143 self.assertFalse(any(arvados.util.keep_locator_pattern.match(fn) or
144 arvados.util.uuid_pattern.match(fn)
146 "new FUSE MagicDirectory has no collections or projects")
147 self.assertDirContents(self.testcollection, ['thing1.txt'])
148 self.assertDirContents(os.path.join('by_id', self.testcollection),
150 self.assertIn(self.collection_in_test_project,
151 llfuse.listdir(os.path.join(self.mounttmp, self.test_project)))
152 self.assertIn(self.collection_in_test_project,
153 llfuse.listdir(os.path.join(self.mounttmp, 'by_id', self.test_project)))
155 mount_ls = llfuse.listdir(self.mounttmp)
156 self.assertIn('README', mount_ls)
157 self.assertIn(self.testcollection, mount_ls)
158 self.assertIn(self.testcollection,
159 llfuse.listdir(os.path.join(self.mounttmp, 'by_id')))
160 self.assertIn(self.test_project, mount_ls)
161 self.assertIn(self.test_project,
162 llfuse.listdir(os.path.join(self.mounttmp, 'by_id')))
164 with self.assertRaises(OSError):
165 llfuse.listdir(os.path.join(self.mounttmp, 'by_id', self.non_project_group))
168 files[os.path.join(self.mounttmp, self.testcollection, 'thing1.txt')] = 'data 1'
170 for k, v in files.items():
171 with open(os.path.join(self.mounttmp, k)) as f:
172 self.assertEqual(v, f.read())
175 class FuseTagsTest(MountTestBase):
177 self.make_mount(fuse.TagsDirectory)
179 d1 = llfuse.listdir(self.mounttmp)
181 self.assertEqual(['foo_tag'], d1)
183 d2 = llfuse.listdir(os.path.join(self.mounttmp, 'foo_tag'))
185 self.assertEqual(['zzzzz-4zz18-fy296fx3hot09f7'], d2)
187 d3 = llfuse.listdir(os.path.join(self.mounttmp, 'foo_tag', 'zzzzz-4zz18-fy296fx3hot09f7'))
189 self.assertEqual(['foo'], d3)
192 class FuseTagsUpdateTest(MountTestBase):
193 def tag_collection(self, coll_uuid, tag_name):
194 return self.api.links().create(
195 body={'link': {'head_uuid': coll_uuid,
201 self.make_mount(fuse.TagsDirectory, poll_time=1)
203 self.assertIn('foo_tag', llfuse.listdir(self.mounttmp))
205 bar_uuid = run_test_server.fixture('collections')['bar_file']['uuid']
206 self.tag_collection(bar_uuid, 'fuse_test_tag')
207 for attempt in AssertWithTimeout(10):
208 attempt(self.assertIn, 'fuse_test_tag', llfuse.listdir(self.mounttmp))
209 self.assertDirContents('fuse_test_tag', [bar_uuid])
211 baz_uuid = run_test_server.fixture('collections')['baz_file']['uuid']
212 l = self.tag_collection(baz_uuid, 'fuse_test_tag')
213 for attempt in AssertWithTimeout(10):
214 attempt(self.assertDirContents, 'fuse_test_tag', [bar_uuid, baz_uuid])
216 self.api.links().delete(uuid=l['uuid']).execute()
217 for attempt in AssertWithTimeout(10):
218 attempt(self.assertDirContents, 'fuse_test_tag', [bar_uuid])
221 def fuseSharedTestHelper(mounttmp):
222 class Test(unittest.TestCase):
224 # Double check that we can open and read objects in this folder as a file,
225 # and that its contents are what we expect.
226 baz_path = os.path.join(
230 'collection in FUSE project',
232 with open(baz_path) as f:
233 self.assertEqual("baz", f.read())
235 # check mtime on collection
236 st = os.stat(baz_path)
238 mtime = st.st_mtime_ns / 1000000000
239 except AttributeError:
241 self.assertEqual(mtime, 1391448174)
243 # shared_dirs is a list of the directories exposed
244 # by fuse.SharedDirectory (i.e. any object visible
245 # to the current user)
246 shared_dirs = llfuse.listdir(mounttmp)
248 self.assertIn('FUSE User', shared_dirs)
250 # fuse_user_objs is a list of the objects owned by the FUSE
251 # test user (which present as files in the 'FUSE User'
253 fuse_user_objs = llfuse.listdir(os.path.join(mounttmp, 'FUSE User'))
254 fuse_user_objs.sort()
255 self.assertEqual(['FUSE Test Project', # project owned by user
256 'collection #1 owned by FUSE', # collection owned by user
257 'collection #2 owned by FUSE' # collection owned by user
260 # test_proj_files is a list of the files in the FUSE Test Project.
261 test_proj_files = llfuse.listdir(os.path.join(mounttmp, 'FUSE User', 'FUSE Test Project'))
262 test_proj_files.sort()
263 self.assertEqual(['collection in FUSE project'
269 class FuseSharedTest(MountTestBase):
271 self.make_mount(fuse.SharedDirectory,
272 exclude=self.api.users().current().execute()['uuid'])
273 keep = arvados.keep.KeepClient()
276 self.pool.apply(fuseSharedTestHelper, (self.mounttmp,))
279 class FuseHomeTest(MountTestBase):
281 self.make_mount(fuse.ProjectDirectory,
282 project_object=self.api.users().current().execute())
284 d1 = llfuse.listdir(self.mounttmp)
285 self.assertIn('Unrestricted public data', d1)
287 d2 = llfuse.listdir(os.path.join(self.mounttmp, 'Unrestricted public data'))
288 public_project = run_test_server.fixture('groups')[
289 'anonymously_accessible_project']
292 for name, item in run_test_server.fixture('collections').iteritems():
293 if 'name' not in item:
295 elif item['owner_uuid'] == public_project['uuid']:
296 self.assertIn(item['name'], d2)
299 # Artificial assumption here: there is no public
300 # collection fixture with the same name as a
301 # non-public collection.
302 self.assertNotIn(item['name'], d2)
304 self.assertNotEqual(0, found_in)
305 self.assertNotEqual(0, found_not_in)
307 d3 = llfuse.listdir(os.path.join(self.mounttmp, 'Unrestricted public data', 'GNU General Public License, version 3'))
308 self.assertEqual(["GNU_General_Public_License,_version_3.pdf"], d3)
311 def fuseModifyFileTestHelperReadStartContents(mounttmp):
312 class Test(unittest.TestCase):
314 d1 = llfuse.listdir(mounttmp)
315 self.assertEqual(["file1.txt"], d1)
316 with open(os.path.join(mounttmp, "file1.txt")) as f:
317 self.assertEqual("blub", f.read())
320 def fuseModifyFileTestHelperReadEndContents(mounttmp):
321 class Test(unittest.TestCase):
323 d1 = llfuse.listdir(mounttmp)
324 self.assertEqual(["file1.txt"], d1)
325 with open(os.path.join(mounttmp, "file1.txt")) as f:
326 self.assertEqual("plnp", f.read())
329 class FuseModifyFileTest(MountTestBase):
331 collection = arvados.collection.Collection(api_client=self.api)
332 with collection.open("file1.txt", "w") as f:
335 collection.save_new()
337 m = self.make_mount(fuse.CollectionDirectory)
339 m.new_collection(collection.api_response(), collection)
341 self.pool.apply(fuseModifyFileTestHelperReadStartContents, (self.mounttmp,))
343 with collection.open("file1.txt", "w") as f:
346 self.pool.apply(fuseModifyFileTestHelperReadEndContents, (self.mounttmp,))
349 class FuseAddFileToCollectionTest(MountTestBase):
351 collection = arvados.collection.Collection(api_client=self.api)
352 with collection.open("file1.txt", "w") as f:
355 collection.save_new()
357 m = self.make_mount(fuse.CollectionDirectory)
359 m.new_collection(collection.api_response(), collection)
361 d1 = llfuse.listdir(self.mounttmp)
362 self.assertEqual(["file1.txt"], d1)
364 with collection.open("file2.txt", "w") as f:
367 d1 = llfuse.listdir(self.mounttmp)
368 self.assertEqual(["file1.txt", "file2.txt"], sorted(d1))
371 class FuseRemoveFileFromCollectionTest(MountTestBase):
373 collection = arvados.collection.Collection(api_client=self.api)
374 with collection.open("file1.txt", "w") as f:
377 with collection.open("file2.txt", "w") as f:
380 collection.save_new()
382 m = self.make_mount(fuse.CollectionDirectory)
384 m.new_collection(collection.api_response(), collection)
386 d1 = llfuse.listdir(self.mounttmp)
387 self.assertEqual(["file1.txt", "file2.txt"], sorted(d1))
389 collection.remove("file2.txt")
391 d1 = llfuse.listdir(self.mounttmp)
392 self.assertEqual(["file1.txt"], d1)
395 def fuseCreateFileTestHelper(mounttmp):
396 class Test(unittest.TestCase):
398 with open(os.path.join(mounttmp, "file1.txt"), "w") as f:
402 class FuseCreateFileTest(MountTestBase):
404 collection = arvados.collection.Collection(api_client=self.api)
405 collection.save_new()
407 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
408 self.assertEqual(collection2["manifest_text"], "")
410 collection.save_new()
412 m = self.make_mount(fuse.CollectionDirectory)
414 m.new_collection(collection.api_response(), collection)
415 self.assertTrue(m.writable())
417 self.assertNotIn("file1.txt", collection)
419 self.pool.apply(fuseCreateFileTestHelper, (self.mounttmp,))
421 self.assertIn("file1.txt", collection)
423 d1 = llfuse.listdir(self.mounttmp)
424 self.assertEqual(["file1.txt"], d1)
426 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
427 self.assertRegexpMatches(collection2["manifest_text"],
428 r'\. d41d8cd98f00b204e9800998ecf8427e\+0\+A\S+ 0:0:file1\.txt$')
431 def fuseWriteFileTestHelperWriteFile(mounttmp):
432 class Test(unittest.TestCase):
434 with open(os.path.join(mounttmp, "file1.txt"), "w") as f:
435 f.write("Hello world!")
438 def fuseWriteFileTestHelperReadFile(mounttmp):
439 class Test(unittest.TestCase):
441 with open(os.path.join(mounttmp, "file1.txt"), "r") as f:
442 self.assertEqual(f.read(), "Hello world!")
445 class FuseWriteFileTest(MountTestBase):
447 collection = arvados.collection.Collection(api_client=self.api)
448 collection.save_new()
450 m = self.make_mount(fuse.CollectionDirectory)
452 m.new_collection(collection.api_response(), collection)
453 self.assertTrue(m.writable())
455 self.assertNotIn("file1.txt", collection)
457 self.assertEqual(0, self.operations.write_counter.get())
458 self.pool.apply(fuseWriteFileTestHelperWriteFile, (self.mounttmp,))
459 self.assertEqual(12, self.operations.write_counter.get())
461 with collection.open("file1.txt") as f:
462 self.assertEqual(f.read(), "Hello world!")
464 self.assertEqual(0, self.operations.read_counter.get())
465 self.pool.apply(fuseWriteFileTestHelperReadFile, (self.mounttmp,))
466 self.assertEqual(12, self.operations.read_counter.get())
468 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
469 self.assertRegexpMatches(collection2["manifest_text"],
470 r'\. 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
473 def fuseUpdateFileTestHelper(mounttmp):
474 class Test(unittest.TestCase):
476 with open(os.path.join(mounttmp, "file1.txt"), "w") as f:
477 f.write("Hello world!")
479 with open(os.path.join(mounttmp, "file1.txt"), "r+") as f:
481 self.assertEqual(fr, "Hello world!")
483 f.write("Hola mundo!")
486 self.assertEqual(fr, "Hola mundo!!")
488 with open(os.path.join(mounttmp, "file1.txt"), "r") as f:
489 self.assertEqual(f.read(), "Hola mundo!!")
493 class FuseUpdateFileTest(MountTestBase):
495 collection = arvados.collection.Collection(api_client=self.api)
496 collection.save_new()
498 m = self.make_mount(fuse.CollectionDirectory)
500 m.new_collection(collection.api_response(), collection)
501 self.assertTrue(m.writable())
503 # See note in MountTestBase.setUp
504 self.pool.apply(fuseUpdateFileTestHelper, (self.mounttmp,))
506 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
507 self.assertRegexpMatches(collection2["manifest_text"],
508 r'\. daaef200ebb921e011e3ae922dd3266b\+11\+A\S+ 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:11:file1\.txt 22:1:file1\.txt$')
511 def fuseMkdirTestHelper(mounttmp):
512 class Test(unittest.TestCase):
514 with self.assertRaises(IOError):
515 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
516 f.write("Hello world!")
518 os.mkdir(os.path.join(mounttmp, "testdir"))
520 with self.assertRaises(OSError):
521 os.mkdir(os.path.join(mounttmp, "testdir"))
523 d1 = llfuse.listdir(mounttmp)
524 self.assertEqual(["testdir"], d1)
526 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
527 f.write("Hello world!")
529 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
530 self.assertEqual(["file1.txt"], d1)
534 class FuseMkdirTest(MountTestBase):
536 collection = arvados.collection.Collection(api_client=self.api)
537 collection.save_new()
539 m = self.make_mount(fuse.CollectionDirectory)
541 m.new_collection(collection.api_response(), collection)
542 self.assertTrue(m.writable())
544 self.pool.apply(fuseMkdirTestHelper, (self.mounttmp,))
546 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
547 self.assertRegexpMatches(collection2["manifest_text"],
548 r'\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
551 def fuseRmTestHelperWriteFile(mounttmp):
552 class Test(unittest.TestCase):
554 os.mkdir(os.path.join(mounttmp, "testdir"))
556 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
557 f.write("Hello world!")
561 def fuseRmTestHelperDeleteFile(mounttmp):
562 class Test(unittest.TestCase):
564 # Can't delete because it's not empty
565 with self.assertRaises(OSError):
566 os.rmdir(os.path.join(mounttmp, "testdir"))
568 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
569 self.assertEqual(["file1.txt"], d1)
572 os.remove(os.path.join(mounttmp, "testdir", "file1.txt"))
574 # Make sure it's empty
575 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
576 self.assertEqual([], d1)
578 # Try to delete it again
579 with self.assertRaises(OSError):
580 os.remove(os.path.join(mounttmp, "testdir", "file1.txt"))
584 def fuseRmTestHelperRmdir(mounttmp):
585 class Test(unittest.TestCase):
587 # Should be able to delete now that it is empty
588 os.rmdir(os.path.join(mounttmp, "testdir"))
590 # Make sure it's empty
591 d1 = llfuse.listdir(os.path.join(mounttmp))
592 self.assertEqual([], d1)
594 # Try to delete it again
595 with self.assertRaises(OSError):
596 os.rmdir(os.path.join(mounttmp, "testdir"))
600 class FuseRmTest(MountTestBase):
602 collection = arvados.collection.Collection(api_client=self.api)
603 collection.save_new()
605 m = self.make_mount(fuse.CollectionDirectory)
607 m.new_collection(collection.api_response(), collection)
608 self.assertTrue(m.writable())
610 self.pool.apply(fuseRmTestHelperWriteFile, (self.mounttmp,))
613 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
614 self.assertRegexpMatches(collection2["manifest_text"],
615 r'\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
616 self.pool.apply(fuseRmTestHelperDeleteFile, (self.mounttmp,))
618 # Empty directories are represented by an empty file named "."
619 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
620 self.assertRegexpMatches(collection2["manifest_text"],
621 r'./testdir d41d8cd98f00b204e9800998ecf8427e\+0\+A\S+ 0:0:\\056\n')
623 self.pool.apply(fuseRmTestHelperRmdir, (self.mounttmp,))
625 # manifest should be empty now.
626 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
627 self.assertEqual(collection2["manifest_text"], "")
630 def fuseMvFileTestHelperWriteFile(mounttmp):
631 class Test(unittest.TestCase):
633 os.mkdir(os.path.join(mounttmp, "testdir"))
635 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
636 f.write("Hello world!")
640 def fuseMvFileTestHelperMoveFile(mounttmp):
641 class Test(unittest.TestCase):
643 d1 = llfuse.listdir(os.path.join(mounttmp))
644 self.assertEqual(["testdir"], d1)
645 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
646 self.assertEqual(["file1.txt"], d1)
648 os.rename(os.path.join(mounttmp, "testdir", "file1.txt"), os.path.join(mounttmp, "file1.txt"))
650 d1 = llfuse.listdir(os.path.join(mounttmp))
651 self.assertEqual(["file1.txt", "testdir"], sorted(d1))
652 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
653 self.assertEqual([], d1)
657 class FuseMvFileTest(MountTestBase):
659 collection = arvados.collection.Collection(api_client=self.api)
660 collection.save_new()
662 m = self.make_mount(fuse.CollectionDirectory)
664 m.new_collection(collection.api_response(), collection)
665 self.assertTrue(m.writable())
667 self.pool.apply(fuseMvFileTestHelperWriteFile, (self.mounttmp,))
670 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
671 self.assertRegexpMatches(collection2["manifest_text"],
672 r'\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
674 self.pool.apply(fuseMvFileTestHelperMoveFile, (self.mounttmp,))
676 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
677 self.assertRegexpMatches(collection2["manifest_text"],
678 r'\. 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt\n\./testdir d41d8cd98f00b204e9800998ecf8427e\+0\+A\S+ 0:0:\\056\n')
681 def fuseRenameTestHelper(mounttmp):
682 class Test(unittest.TestCase):
684 os.mkdir(os.path.join(mounttmp, "testdir"))
686 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
687 f.write("Hello world!")
691 class FuseRenameTest(MountTestBase):
693 collection = arvados.collection.Collection(api_client=self.api)
694 collection.save_new()
696 m = self.make_mount(fuse.CollectionDirectory)
698 m.new_collection(collection.api_response(), collection)
699 self.assertTrue(m.writable())
701 self.pool.apply(fuseRenameTestHelper, (self.mounttmp,))
704 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
705 self.assertRegexpMatches(collection2["manifest_text"],
706 r'\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
708 d1 = llfuse.listdir(os.path.join(self.mounttmp))
709 self.assertEqual(["testdir"], d1)
710 d1 = llfuse.listdir(os.path.join(self.mounttmp, "testdir"))
711 self.assertEqual(["file1.txt"], d1)
713 os.rename(os.path.join(self.mounttmp, "testdir"), os.path.join(self.mounttmp, "testdir2"))
715 d1 = llfuse.listdir(os.path.join(self.mounttmp))
716 self.assertEqual(["testdir2"], sorted(d1))
717 d1 = llfuse.listdir(os.path.join(self.mounttmp, "testdir2"))
718 self.assertEqual(["file1.txt"], d1)
720 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
721 self.assertRegexpMatches(collection2["manifest_text"],
722 r'\./testdir2 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
725 class FuseUpdateFromEventTest(MountTestBase):
727 collection = arvados.collection.Collection(api_client=self.api)
728 collection.save_new()
730 m = self.make_mount(fuse.CollectionDirectory)
732 m.new_collection(collection.api_response(), collection)
734 self.operations.listen_for_events()
736 d1 = llfuse.listdir(os.path.join(self.mounttmp))
737 self.assertEqual([], sorted(d1))
739 with arvados.collection.Collection(collection.manifest_locator(), api_client=self.api) as collection2:
740 with collection2.open("file1.txt", "w") as f:
743 for attempt in AssertWithTimeout(10):
744 attempt(self.assertEqual, ["file1.txt"], llfuse.listdir(os.path.join(self.mounttmp)))
747 class FuseDeleteProjectEventTest(MountTestBase):
750 aproject = self.api.groups().create(body={
752 "group_class": "project"
755 bproject = self.api.groups().create(body={
757 "group_class": "project",
758 "owner_uuid": aproject["uuid"]
761 self.make_mount(fuse.ProjectDirectory,
762 project_object=self.api.users().current().execute())
764 self.operations.listen_for_events()
766 d1 = llfuse.listdir(os.path.join(self.mounttmp, "aproject"))
767 self.assertEqual(["bproject"], sorted(d1))
769 self.api.groups().delete(uuid=bproject["uuid"]).execute()
771 for attempt in AssertWithTimeout(10):
772 attempt(self.assertEqual, [], llfuse.listdir(os.path.join(self.mounttmp, "aproject")))
775 def fuseFileConflictTestHelper(mounttmp):
776 class Test(unittest.TestCase):
778 with open(os.path.join(mounttmp, "file1.txt"), "w") as f:
781 d1 = sorted(llfuse.listdir(os.path.join(mounttmp)))
782 self.assertEqual(len(d1), 2)
784 with open(os.path.join(mounttmp, "file1.txt"), "r") as f:
785 self.assertEqual(f.read(), "bar")
787 self.assertRegexpMatches(d1[1],
788 r'file1\.txt~\d\d\d\d\d\d\d\d-\d\d\d\d\d\d~conflict~')
790 with open(os.path.join(mounttmp, d1[1]), "r") as f:
791 self.assertEqual(f.read(), "foo")
795 class FuseFileConflictTest(MountTestBase):
797 collection = arvados.collection.Collection(api_client=self.api)
798 collection.save_new()
800 m = self.make_mount(fuse.CollectionDirectory)
802 m.new_collection(collection.api_response(), collection)
804 d1 = llfuse.listdir(os.path.join(self.mounttmp))
805 self.assertEqual([], sorted(d1))
807 with arvados.collection.Collection(collection.manifest_locator(), api_client=self.api) as collection2:
808 with collection2.open("file1.txt", "w") as f:
811 # See note in MountTestBase.setUp
812 self.pool.apply(fuseFileConflictTestHelper, (self.mounttmp,))
815 def fuseUnlinkOpenFileTest(mounttmp):
816 class Test(unittest.TestCase):
818 with open(os.path.join(mounttmp, "file1.txt"), "w+") as f:
821 d1 = llfuse.listdir(os.path.join(mounttmp))
822 self.assertEqual(["file1.txt"], sorted(d1))
824 os.remove(os.path.join(mounttmp, "file1.txt"))
826 d1 = llfuse.listdir(os.path.join(mounttmp))
827 self.assertEqual([], sorted(d1))
830 self.assertEqual(f.read(), "foo")
834 self.assertEqual(f.read(), "foobar")
838 class FuseUnlinkOpenFileTest(MountTestBase):
840 collection = arvados.collection.Collection(api_client=self.api)
841 collection.save_new()
843 m = self.make_mount(fuse.CollectionDirectory)
845 m.new_collection(collection.api_response(), collection)
847 # See note in MountTestBase.setUp
848 self.pool.apply(fuseUnlinkOpenFileTest, (self.mounttmp,))
850 self.assertEqual(collection.manifest_text(), "")
853 def fuseMvFileBetweenCollectionsTest1(mounttmp, uuid1, uuid2):
854 class Test(unittest.TestCase):
856 with open(os.path.join(mounttmp, uuid1, "file1.txt"), "w") as f:
857 f.write("Hello world!")
859 d1 = os.listdir(os.path.join(mounttmp, uuid1))
860 self.assertEqual(["file1.txt"], sorted(d1))
861 d1 = os.listdir(os.path.join(mounttmp, uuid2))
862 self.assertEqual([], sorted(d1))
866 def fuseMvFileBetweenCollectionsTest2(mounttmp, uuid1, uuid2):
867 class Test(unittest.TestCase):
869 os.rename(os.path.join(mounttmp, uuid1, "file1.txt"), os.path.join(mounttmp, uuid2, "file2.txt"))
871 d1 = os.listdir(os.path.join(mounttmp, uuid1))
872 self.assertEqual([], sorted(d1))
873 d1 = os.listdir(os.path.join(mounttmp, uuid2))
874 self.assertEqual(["file2.txt"], sorted(d1))
878 class FuseMvFileBetweenCollectionsTest(MountTestBase):
880 collection1 = arvados.collection.Collection(api_client=self.api)
881 collection1.save_new()
883 collection2 = arvados.collection.Collection(api_client=self.api)
884 collection2.save_new()
886 m = self.make_mount(fuse.MagicDirectory)
888 # See note in MountTestBase.setUp
889 self.pool.apply(fuseMvFileBetweenCollectionsTest1, (self.mounttmp,
890 collection1.manifest_locator(),
891 collection2.manifest_locator()))
896 self.assertRegexpMatches(collection1.manifest_text(), r"\. 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$")
897 self.assertEqual(collection2.manifest_text(), "")
899 self.pool.apply(fuseMvFileBetweenCollectionsTest2, (self.mounttmp,
900 collection1.manifest_locator(),
901 collection2.manifest_locator()))
906 self.assertEqual(collection1.manifest_text(), "")
907 self.assertRegexpMatches(collection2.manifest_text(), r"\. 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file2\.txt$")
909 collection1.stop_threads()
910 collection2.stop_threads()
913 def fuseMvDirBetweenCollectionsTest1(mounttmp, uuid1, uuid2):
914 class Test(unittest.TestCase):
916 os.mkdir(os.path.join(mounttmp, uuid1, "testdir"))
917 with open(os.path.join(mounttmp, uuid1, "testdir", "file1.txt"), "w") as f:
918 f.write("Hello world!")
920 d1 = os.listdir(os.path.join(mounttmp, uuid1))
921 self.assertEqual(["testdir"], sorted(d1))
922 d1 = os.listdir(os.path.join(mounttmp, uuid1, "testdir"))
923 self.assertEqual(["file1.txt"], sorted(d1))
925 d1 = os.listdir(os.path.join(mounttmp, uuid2))
926 self.assertEqual([], sorted(d1))
931 def fuseMvDirBetweenCollectionsTest2(mounttmp, uuid1, uuid2):
932 class Test(unittest.TestCase):
934 os.rename(os.path.join(mounttmp, uuid1, "testdir"), os.path.join(mounttmp, uuid2, "testdir2"))
936 d1 = os.listdir(os.path.join(mounttmp, uuid1))
937 self.assertEqual([], sorted(d1))
939 d1 = os.listdir(os.path.join(mounttmp, uuid2))
940 self.assertEqual(["testdir2"], sorted(d1))
941 d1 = os.listdir(os.path.join(mounttmp, uuid2, "testdir2"))
942 self.assertEqual(["file1.txt"], sorted(d1))
944 with open(os.path.join(mounttmp, uuid2, "testdir2", "file1.txt"), "r") as f:
945 self.assertEqual(f.read(), "Hello world!")
949 class FuseMvDirBetweenCollectionsTest(MountTestBase):
951 collection1 = arvados.collection.Collection(api_client=self.api)
952 collection1.save_new()
954 collection2 = arvados.collection.Collection(api_client=self.api)
955 collection2.save_new()
957 m = self.make_mount(fuse.MagicDirectory)
959 # See note in MountTestBase.setUp
960 self.pool.apply(fuseMvDirBetweenCollectionsTest1, (self.mounttmp,
961 collection1.manifest_locator(),
962 collection2.manifest_locator()))
967 self.assertRegexpMatches(collection1.manifest_text(), r"\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$")
968 self.assertEqual(collection2.manifest_text(), "")
970 self.pool.apply(fuseMvDirBetweenCollectionsTest2, (self.mounttmp,
971 collection1.manifest_locator(),
972 collection2.manifest_locator()))
977 self.assertEqual(collection1.manifest_text(), "")
978 self.assertRegexpMatches(collection2.manifest_text(), r"\./testdir2 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$")
980 collection1.stop_threads()
981 collection2.stop_threads()
983 def fuseProjectMkdirTestHelper1(mounttmp):
984 class Test(unittest.TestCase):
986 os.mkdir(os.path.join(mounttmp, "testcollection"))
987 with self.assertRaises(OSError):
988 os.mkdir(os.path.join(mounttmp, "testcollection"))
991 def fuseProjectMkdirTestHelper2(mounttmp):
992 class Test(unittest.TestCase):
994 with open(os.path.join(mounttmp, "testcollection", "file1.txt"), "w") as f:
995 f.write("Hello world!")
996 with self.assertRaises(OSError):
997 os.rmdir(os.path.join(mounttmp, "testcollection"))
998 os.remove(os.path.join(mounttmp, "testcollection", "file1.txt"))
999 with self.assertRaises(OSError):
1000 os.remove(os.path.join(mounttmp, "testcollection"))
1001 os.rmdir(os.path.join(mounttmp, "testcollection"))
1004 class FuseProjectMkdirRmdirTest(MountTestBase):
1006 self.make_mount(fuse.ProjectDirectory,
1007 project_object=self.api.users().current().execute())
1009 d1 = llfuse.listdir(self.mounttmp)
1010 self.assertNotIn('testcollection', d1)
1012 self.pool.apply(fuseProjectMkdirTestHelper1, (self.mounttmp,))
1014 d1 = llfuse.listdir(self.mounttmp)
1015 self.assertIn('testcollection', d1)
1017 self.pool.apply(fuseProjectMkdirTestHelper2, (self.mounttmp,))
1019 d1 = llfuse.listdir(self.mounttmp)
1020 self.assertNotIn('testcollection', d1)
1023 def fuseProjectMvTestHelper1(mounttmp):
1024 class Test(unittest.TestCase):
1026 d1 = llfuse.listdir(mounttmp)
1027 self.assertNotIn('testcollection', d1)
1029 os.mkdir(os.path.join(mounttmp, "testcollection"))
1031 d1 = llfuse.listdir(mounttmp)
1032 self.assertIn('testcollection', d1)
1034 with self.assertRaises(OSError):
1035 os.rename(os.path.join(mounttmp, "testcollection"), os.path.join(mounttmp, 'Unrestricted public data'))
1037 os.rename(os.path.join(mounttmp, "testcollection"), os.path.join(mounttmp, 'Unrestricted public data', 'testcollection'))
1039 d1 = llfuse.listdir(mounttmp)
1040 self.assertNotIn('testcollection', d1)
1042 d1 = llfuse.listdir(os.path.join(mounttmp, 'Unrestricted public data'))
1043 self.assertIn('testcollection', d1)
1047 class FuseProjectMvTest(MountTestBase):
1049 self.make_mount(fuse.ProjectDirectory,
1050 project_object=self.api.users().current().execute())
1052 self.pool.apply(fuseProjectMvTestHelper1, (self.mounttmp,))
1055 def fuseFsyncTestHelper(mounttmp, k):
1056 class Test(unittest.TestCase):
1058 fd = os.open(os.path.join(mounttmp, k), os.O_RDONLY)
1064 class FuseFsyncTest(FuseMagicTest):
1066 self.make_mount(fuse.MagicDirectory)
1067 self.pool.apply(fuseFsyncTestHelper, (self.mounttmp, self.testcollection))
1070 class MagicDirApiError(FuseMagicTest):
1072 api = mock.MagicMock()
1073 super(MagicDirApiError, self).setUp(api=api)
1074 api.collections().get().execute.side_effect = iter([
1075 Exception('API fail'),
1077 "manifest_text": self.test_manifest,
1078 "portable_data_hash": self.test_manifest_pdh,
1081 api.keep.get.side_effect = Exception('Keep fail')
1084 self.make_mount(fuse.MagicDirectory)
1086 self.operations.inodes.inode_cache.cap = 1
1087 self.operations.inodes.inode_cache.min_entries = 2
1089 with self.assertRaises(OSError):
1090 llfuse.listdir(os.path.join(self.mounttmp, self.testcollection))
1092 llfuse.listdir(os.path.join(self.mounttmp, self.testcollection))
1095 class FuseUnitTest(unittest.TestCase):
1096 def test_sanitize_filename(self):
1115 for f in acceptable:
1116 self.assertEqual(f, fuse.sanitize_filename(f))
1117 for f in unacceptable:
1118 self.assertNotEqual(f, fuse.sanitize_filename(f))
1119 # The sanitized filename should be the same length, though.
1120 self.assertEqual(len(f), len(fuse.sanitize_filename(f)))
1122 self.assertEqual("_", fuse.sanitize_filename(""))
1123 self.assertEqual("_", fuse.sanitize_filename("."))
1124 self.assertEqual("__", fuse.sanitize_filename(".."))
1127 class FuseMagicTestPDHOnly(MountTestBase):
1128 def setUp(self, api=None):
1129 super(FuseMagicTestPDHOnly, self).setUp(api=api)
1131 cw = arvados.CollectionWriter()
1133 cw.start_new_file('thing1.txt')
1136 self.testcollection = cw.finish()
1137 self.test_manifest = cw.manifest_text()
1138 created = self.api.collections().create(body={"manifest_text":self.test_manifest}).execute()
1139 self.testcollectionuuid = str(created['uuid'])
1141 def verify_pdh_only(self, pdh_only=False, skip_pdh_only=False):
1142 if skip_pdh_only is True:
1143 self.make_mount(fuse.MagicDirectory) # in this case, the default by_id applies
1145 self.make_mount(fuse.MagicDirectory, pdh_only=pdh_only)
1147 mount_ls = llfuse.listdir(self.mounttmp)
1148 self.assertIn('README', mount_ls)
1149 self.assertFalse(any(arvados.util.keep_locator_pattern.match(fn) or
1150 arvados.util.uuid_pattern.match(fn)
1151 for fn in mount_ls),
1152 "new FUSE MagicDirectory lists Collection")
1154 # look up using pdh should succeed in all cases
1155 self.assertDirContents(self.testcollection, ['thing1.txt'])
1156 self.assertDirContents(os.path.join('by_id', self.testcollection),
1158 mount_ls = llfuse.listdir(self.mounttmp)
1159 self.assertIn('README', mount_ls)
1160 self.assertIn(self.testcollection, mount_ls)
1161 self.assertIn(self.testcollection,
1162 llfuse.listdir(os.path.join(self.mounttmp, 'by_id')))
1165 files[os.path.join(self.mounttmp, self.testcollection, 'thing1.txt')] = 'data 1'
1167 for k, v in files.items():
1168 with open(os.path.join(self.mounttmp, k)) as f:
1169 self.assertEqual(v, f.read())
1171 # look up using uuid should fail when pdh_only is set
1172 if pdh_only is True:
1173 with self.assertRaises(OSError):
1174 self.assertDirContents(os.path.join('by_id', self.testcollectionuuid),
1177 self.assertDirContents(os.path.join('by_id', self.testcollectionuuid),
1180 def test_with_pdh_only_true(self):
1181 self.verify_pdh_only(pdh_only=True)
1183 def test_with_pdh_only_false(self):
1184 self.verify_pdh_only(pdh_only=False)
1186 def test_with_default_by_id(self):
1187 self.verify_pdh_only(skip_pdh_only=True)