1 # Copyright (C) The Arvados Authors. All rights reserved.
3 # SPDX-License-Identifier: AGPL-3.0
15 from pathlib import Path
16 from unittest import mock
19 import arvados_fuse as fuse
22 from arvados_fuse import fusedir
24 from . import run_test_server
25 from .integration_test import IntegrationTest
26 from .mount_test_base import MountTestBase
27 from .test_tmp_collection import storage_classes_desired
29 logger = logging.getLogger('arvados.arv-mount')
31 class AssertWithTimeout(object):
32 """Allow some time for an assertion to pass."""
34 def __init__(self, timeout=0):
35 self.timeout = timeout
38 self.deadline = time.time() + self.timeout
47 def attempt(self, fn, *args, **kwargs):
50 except AssertionError:
51 if time.time() > self.deadline:
57 @parameterized.parameterized_class([{"disk_cache": True}, {"disk_cache": False}])
58 class FuseMountTest(MountTestBase):
60 super(FuseMountTest, self).setUp()
62 cw = arvados.CollectionWriter()
64 cw.start_new_file('thing1.txt')
66 cw.start_new_file('thing2.txt')
69 cw.start_new_stream('dir1')
70 cw.start_new_file('thing3.txt')
72 cw.start_new_file('thing4.txt')
75 cw.start_new_stream('dir2')
76 cw.start_new_file('thing5.txt')
78 cw.start_new_file('thing6.txt')
81 cw.start_new_stream('dir2/dir3')
82 cw.start_new_file('thing7.txt')
85 cw.start_new_file('thing8.txt')
88 cw.start_new_stream('edgecases')
89 for f in ":/.../-/*/ ".split("/"):
93 for f in ":/.../-/*/ ".split("/"):
94 cw.start_new_stream('edgecases/dirs/' + f)
95 cw.start_new_file('x/x')
98 self.testcollection = cw.finish()
99 self.api.collections().create(body={"manifest_text":cw.manifest_text()}).execute()
102 self.make_mount(fuse.CollectionDirectory, collection_record=self.testcollection)
104 self.assertDirContents(None, ['thing1.txt', 'thing2.txt',
105 'edgecases', 'dir1', 'dir2'])
106 self.assertDirContents('dir1', ['thing3.txt', 'thing4.txt'])
107 self.assertDirContents('dir2', ['thing5.txt', 'thing6.txt', 'dir3'])
108 self.assertDirContents('dir2/dir3', ['thing7.txt', 'thing8.txt'])
109 self.assertDirContents('edgecases',
110 "dirs/:/.../-/*/ ".split("/"))
111 self.assertDirContents('edgecases/dirs',
112 ":/.../-/*/ ".split("/"))
114 files = {'thing1.txt': 'data 1',
115 'thing2.txt': 'data 2',
116 'dir1/thing3.txt': 'data 3',
117 'dir1/thing4.txt': 'data 4',
118 'dir2/thing5.txt': 'data 5',
119 'dir2/thing6.txt': 'data 6',
120 'dir2/dir3/thing7.txt': 'data 7',
121 'dir2/dir3/thing8.txt': 'data 8'}
123 for k, v in files.items():
124 with open(os.path.join(self.mounttmp, k), 'rb') as f:
125 self.assertEqual(v, f.read().decode())
128 @parameterized.parameterized_class([{"disk_cache": True}, {"disk_cache": False}])
129 class FuseMagicTest(MountTestBase):
130 def setUp(self, api=None):
131 super(FuseMagicTest, self).setUp(api=api)
133 self.test_project = run_test_server.fixture('groups')['aproject']['uuid']
134 self.non_project_group = run_test_server.fixture('groups')['public_role']['uuid']
135 self.filter_group = run_test_server.fixture('groups')['afiltergroup']['uuid']
136 self.collection_in_test_project = run_test_server.fixture('collections')['foo_collection_in_aproject']['name']
137 self.collection_in_filter_group = run_test_server.fixture('collections')['baz_file']['name']
139 cw = arvados.CollectionWriter()
141 cw.start_new_file('thing1.txt')
144 self.testcollection = cw.finish()
145 self.test_manifest = cw.manifest_text()
146 coll = self.api.collections().create(body={"manifest_text":self.test_manifest}).execute()
147 self.test_manifest_pdh = coll['portable_data_hash']
150 self.make_mount(fuse.MagicDirectory)
152 mount_ls = llfuse.listdir(self.mounttmp)
153 self.assertIn('README', mount_ls)
154 self.assertFalse(any(arvados.util.keep_locator_pattern.match(fn) or
155 arvados.util.uuid_pattern.match(fn)
157 "new FUSE MagicDirectory has no collections or projects")
158 self.assertDirContents(self.testcollection, ['thing1.txt'])
159 self.assertDirContents(os.path.join('by_id', self.testcollection),
161 self.assertIn(self.collection_in_test_project,
162 llfuse.listdir(os.path.join(self.mounttmp, self.test_project)))
163 self.assertIn(self.collection_in_test_project,
164 llfuse.listdir(os.path.join(self.mounttmp, 'by_id', self.test_project)))
165 self.assertIn(self.collection_in_filter_group,
166 llfuse.listdir(os.path.join(self.mounttmp, self.filter_group)))
167 self.assertIn(self.collection_in_filter_group,
168 llfuse.listdir(os.path.join(self.mounttmp, 'by_id', self.filter_group)))
171 mount_ls = llfuse.listdir(self.mounttmp)
172 self.assertIn('README', mount_ls)
173 self.assertIn(self.testcollection, mount_ls)
174 self.assertIn(self.testcollection,
175 llfuse.listdir(os.path.join(self.mounttmp, 'by_id')))
176 self.assertIn(self.test_project, mount_ls)
177 self.assertIn(self.test_project,
178 llfuse.listdir(os.path.join(self.mounttmp, 'by_id')))
179 self.assertIn(self.filter_group,
180 llfuse.listdir(os.path.join(self.mounttmp, 'by_id')))
182 with self.assertRaises(OSError):
183 llfuse.listdir(os.path.join(self.mounttmp, 'by_id', self.non_project_group))
186 files[os.path.join(self.mounttmp, self.testcollection, 'thing1.txt')] = 'data 1'
188 for k, v in files.items():
189 with open(os.path.join(self.mounttmp, k), 'rb') as f:
190 self.assertEqual(v, f.read().decode())
193 class FuseTagsTest(MountTestBase):
195 self.make_mount(fuse.TagsDirectory)
197 d1 = llfuse.listdir(self.mounttmp)
199 self.assertEqual(['foo_tag'], d1)
201 d2 = llfuse.listdir(os.path.join(self.mounttmp, 'foo_tag'))
203 self.assertEqual(['zzzzz-4zz18-fy296fx3hot09f7'], d2)
205 d3 = llfuse.listdir(os.path.join(self.mounttmp, 'foo_tag', 'zzzzz-4zz18-fy296fx3hot09f7'))
207 self.assertEqual(['foo'], d3)
210 class FuseTagsUpdateTest(MountTestBase):
211 def tag_collection(self, coll_uuid, tag_name):
212 return self.api.links().create(
213 body={'link': {'head_uuid': coll_uuid,
219 self.make_mount(fuse.TagsDirectory, poll_time=1)
221 self.assertIn('foo_tag', llfuse.listdir(self.mounttmp))
223 bar_uuid = run_test_server.fixture('collections')['bar_file']['uuid']
224 self.tag_collection(bar_uuid, 'fuse_test_tag')
225 for attempt in AssertWithTimeout(10):
226 attempt(self.assertIn, 'fuse_test_tag', llfuse.listdir(self.mounttmp))
227 self.assertDirContents('fuse_test_tag', [bar_uuid])
229 baz_uuid = run_test_server.fixture('collections')['baz_file']['uuid']
230 l = self.tag_collection(baz_uuid, 'fuse_test_tag')
231 for attempt in AssertWithTimeout(10):
232 attempt(self.assertDirContents, 'fuse_test_tag', [bar_uuid, baz_uuid])
234 self.api.links().delete(uuid=l['uuid']).execute()
235 for attempt in AssertWithTimeout(10):
236 attempt(self.assertDirContents, 'fuse_test_tag', [bar_uuid])
239 def fuseSharedTestHelper(mounttmp):
240 class Test(unittest.TestCase):
242 # Double check that we can open and read objects in this folder as a file,
243 # and that its contents are what we expect.
244 baz_path = os.path.join(
248 'collection in FUSE project',
250 with open(baz_path) as f:
251 self.assertEqual("baz", f.read())
253 # check mtime on collection
254 st = os.stat(baz_path)
256 mtime = st.st_mtime_ns // 1000000000
257 except AttributeError:
259 self.assertEqual(mtime, 1391448174)
261 # shared_dirs is a list of the directories exposed
262 # by fuse.SharedDirectory (i.e. any object visible
263 # to the current user)
264 shared_dirs = llfuse.listdir(mounttmp)
266 self.assertIn('FUSE User', shared_dirs)
268 # fuse_user_objs is a list of the objects owned by the FUSE
269 # test user (which present as files in the 'FUSE User'
271 fuse_user_objs = llfuse.listdir(os.path.join(mounttmp, 'FUSE User'))
272 fuse_user_objs.sort()
273 self.assertEqual(['FUSE Test Project', # project owned by user
274 'collection #1 owned by FUSE', # collection owned by user
275 'collection #2 owned by FUSE' # collection owned by user
278 # test_proj_files is a list of the files in the FUSE Test Project.
279 test_proj_files = llfuse.listdir(os.path.join(mounttmp, 'FUSE User', 'FUSE Test Project'))
280 test_proj_files.sort()
281 self.assertEqual(['collection in FUSE project'
287 @parameterized.parameterized_class([{"disk_cache": True}, {"disk_cache": False}])
288 class FuseSharedTest(MountTestBase):
290 self.make_mount(fuse.SharedDirectory,
291 exclude=self.api.users().current().execute()['uuid'])
292 keep = arvados.keep.KeepClient()
293 keep.put("baz".encode())
295 self.pool.apply(fuseSharedTestHelper, (self.mounttmp,))
298 class FuseHomeTest(MountTestBase):
300 self.make_mount(fuse.ProjectDirectory,
301 project_object=self.api.users().current().execute())
303 d1 = llfuse.listdir(self.mounttmp)
304 self.assertIn('Unrestricted public data', d1)
306 d2 = llfuse.listdir(os.path.join(self.mounttmp, 'Unrestricted public data'))
307 public_project = run_test_server.fixture('groups')[
308 'anonymously_accessible_project']
311 for name, item in run_test_server.fixture('collections').items():
312 if 'name' not in item:
314 elif item['owner_uuid'] == public_project['uuid']:
315 self.assertIn(item['name'], d2)
318 # Artificial assumption here: there is no public
319 # collection fixture with the same name as a
320 # non-public collection.
321 self.assertNotIn(item['name'], d2)
323 self.assertNotEqual(0, found_in)
324 self.assertNotEqual(0, found_not_in)
326 d3 = llfuse.listdir(os.path.join(self.mounttmp, 'Unrestricted public data', 'GNU General Public License, version 3'))
327 self.assertEqual(["GNU_General_Public_License,_version_3.pdf"], d3)
330 def fuseModifyFileTestHelperReadStartContents(mounttmp):
331 class Test(unittest.TestCase):
333 d1 = llfuse.listdir(mounttmp)
334 self.assertEqual(["file1.txt"], d1)
335 with open(os.path.join(mounttmp, "file1.txt")) as f:
336 self.assertEqual("blub", f.read())
339 def fuseModifyFileTestHelperReadEndContents(mounttmp):
340 class Test(unittest.TestCase):
342 d1 = llfuse.listdir(mounttmp)
343 self.assertEqual(["file1.txt"], d1)
344 with open(os.path.join(mounttmp, "file1.txt")) as f:
345 self.assertEqual("plnp", f.read())
348 @parameterized.parameterized_class([{"disk_cache": True}, {"disk_cache": False}])
349 class FuseModifyFileTest(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 self.pool.apply(fuseModifyFileTestHelperReadStartContents, (self.mounttmp,))
363 with collection.open("file1.txt", "w") as f:
366 self.pool.apply(fuseModifyFileTestHelperReadEndContents, (self.mounttmp,))
369 @parameterized.parameterized_class([{"disk_cache": True}, {"disk_cache": False}])
370 class FuseAddFileToCollectionTest(MountTestBase):
372 collection = arvados.collection.Collection(api_client=self.api)
373 with collection.open("file1.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"], d1)
385 with collection.open("file2.txt", "w") as f:
388 d1 = llfuse.listdir(self.mounttmp)
389 self.assertEqual(["file1.txt", "file2.txt"], sorted(d1))
392 @parameterized.parameterized_class([{"disk_cache": True}, {"disk_cache": False}])
393 class FuseRemoveFileFromCollectionTest(MountTestBase):
395 collection = arvados.collection.Collection(api_client=self.api)
396 with collection.open("file1.txt", "w") as f:
399 with collection.open("file2.txt", "w") as f:
402 collection.save_new()
404 m = self.make_mount(fuse.CollectionDirectory)
406 m.new_collection(collection.api_response(), collection)
408 d1 = llfuse.listdir(self.mounttmp)
409 self.assertEqual(["file1.txt", "file2.txt"], sorted(d1))
411 collection.remove("file2.txt")
413 d1 = llfuse.listdir(self.mounttmp)
414 self.assertEqual(["file1.txt"], d1)
417 def fuseCreateFileTestHelper(mounttmp):
418 class Test(unittest.TestCase):
420 with open(os.path.join(mounttmp, "file1.txt"), "w") as f:
424 @parameterized.parameterized_class([{"disk_cache": True}, {"disk_cache": False}])
425 class FuseCreateFileTest(MountTestBase):
427 collection = arvados.collection.Collection(api_client=self.api)
428 collection.save_new()
430 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
431 self.assertEqual(collection2["manifest_text"], "")
433 collection.save_new()
435 m = self.make_mount(fuse.CollectionDirectory)
437 m.new_collection(collection.api_response(), collection)
438 self.assertTrue(m.writable())
440 self.assertNotIn("file1.txt", collection)
442 self.pool.apply(fuseCreateFileTestHelper, (self.mounttmp,))
444 self.assertIn("file1.txt", collection)
446 d1 = llfuse.listdir(self.mounttmp)
447 self.assertEqual(["file1.txt"], d1)
449 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
450 self.assertRegex(collection2["manifest_text"],
451 r'\. d41d8cd98f00b204e9800998ecf8427e\+0\+A\S+ 0:0:file1\.txt$')
454 def fuseWriteFileTestHelperWriteFile(mounttmp):
455 class Test(unittest.TestCase):
457 with open(os.path.join(mounttmp, "file1.txt"), "w") as f:
458 f.write("Hello world!")
461 def fuseWriteFileTestHelperReadFile(mounttmp):
462 class Test(unittest.TestCase):
464 with open(os.path.join(mounttmp, "file1.txt"), "r") as f:
465 self.assertEqual(f.read(), "Hello world!")
468 @parameterized.parameterized_class([{"disk_cache": True}, {"disk_cache": False}])
469 class FuseWriteFileTest(MountTestBase):
471 collection = arvados.collection.Collection(api_client=self.api)
472 collection.save_new()
474 m = self.make_mount(fuse.CollectionDirectory)
476 m.new_collection(collection.api_response(), collection)
477 self.assertTrue(m.writable())
479 self.assertNotIn("file1.txt", collection)
481 self.assertEqual(0, self.operations.write_counter.get())
482 self.pool.apply(fuseWriteFileTestHelperWriteFile, (self.mounttmp,))
483 self.assertEqual(12, self.operations.write_counter.get())
485 with collection.open("file1.txt") as f:
486 self.assertEqual(f.read(), "Hello world!")
488 self.assertEqual(0, self.operations.read_counter.get())
489 self.pool.apply(fuseWriteFileTestHelperReadFile, (self.mounttmp,))
490 self.assertEqual(12, self.operations.read_counter.get())
492 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
493 self.assertRegex(collection2["manifest_text"],
494 r'\. 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
497 def fuseUpdateFileTestHelper(mounttmp):
498 class Test(unittest.TestCase):
500 with open(os.path.join(mounttmp, "file1.txt"), "w") as f:
501 f.write("Hello world!")
503 with open(os.path.join(mounttmp, "file1.txt"), "r+") as f:
505 self.assertEqual(fr, "Hello world!")
507 f.write("Hola mundo!")
510 self.assertEqual(fr, "Hola mundo!!")
512 with open(os.path.join(mounttmp, "file1.txt"), "r") as f:
513 self.assertEqual(f.read(), "Hola mundo!!")
517 @parameterized.parameterized_class([{"disk_cache": True}, {"disk_cache": False}])
518 class FuseUpdateFileTest(MountTestBase):
520 collection = arvados.collection.Collection(api_client=self.api)
521 collection.save_new()
523 m = self.make_mount(fuse.CollectionDirectory)
525 m.new_collection(collection.api_response(), collection)
526 self.assertTrue(m.writable())
528 # See note in MountTestBase.setUp
529 self.pool.apply(fuseUpdateFileTestHelper, (self.mounttmp,))
531 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
532 self.assertRegex(collection2["manifest_text"],
533 r'\. daaef200ebb921e011e3ae922dd3266b\+11\+A\S+ 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:11:file1\.txt 22:1:file1\.txt$')
536 def fuseMkdirTestHelper(mounttmp):
537 class Test(unittest.TestCase):
539 with self.assertRaises(IOError):
540 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
541 f.write("Hello world!")
543 os.mkdir(os.path.join(mounttmp, "testdir"))
545 with self.assertRaises(OSError):
546 os.mkdir(os.path.join(mounttmp, "testdir"))
548 d1 = llfuse.listdir(mounttmp)
549 self.assertEqual(["testdir"], d1)
551 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
552 f.write("Hello world!")
554 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
555 self.assertEqual(["file1.txt"], d1)
559 class FuseMkdirTest(MountTestBase):
561 collection = arvados.collection.Collection(api_client=self.api)
562 collection.save_new()
564 m = self.make_mount(fuse.CollectionDirectory)
566 m.new_collection(collection.api_response(), collection)
567 self.assertTrue(m.writable())
569 self.pool.apply(fuseMkdirTestHelper, (self.mounttmp,))
571 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
572 self.assertRegex(collection2["manifest_text"],
573 r'\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
576 def fuseRmTestHelperWriteFile(mounttmp):
577 class Test(unittest.TestCase):
579 os.mkdir(os.path.join(mounttmp, "testdir"))
581 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
582 f.write("Hello world!")
586 def fuseRmTestHelperDeleteFile(mounttmp):
587 class Test(unittest.TestCase):
589 # Can't delete because it's not empty
590 with self.assertRaises(OSError):
591 os.rmdir(os.path.join(mounttmp, "testdir"))
593 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
594 self.assertEqual(["file1.txt"], d1)
597 os.remove(os.path.join(mounttmp, "testdir", "file1.txt"))
599 # Make sure it's empty
600 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
601 self.assertEqual([], d1)
603 # Try to delete it again
604 with self.assertRaises(OSError):
605 os.remove(os.path.join(mounttmp, "testdir", "file1.txt"))
609 def fuseRmTestHelperRmdir(mounttmp):
610 class Test(unittest.TestCase):
612 # Should be able to delete now that it is empty
613 os.rmdir(os.path.join(mounttmp, "testdir"))
615 # Make sure it's empty
616 d1 = llfuse.listdir(os.path.join(mounttmp))
617 self.assertEqual([], d1)
619 # Try to delete it again
620 with self.assertRaises(OSError):
621 os.rmdir(os.path.join(mounttmp, "testdir"))
625 class FuseRmTest(MountTestBase):
627 collection = arvados.collection.Collection(api_client=self.api)
628 collection.save_new()
630 m = self.make_mount(fuse.CollectionDirectory)
632 m.new_collection(collection.api_response(), collection)
633 self.assertTrue(m.writable())
635 self.pool.apply(fuseRmTestHelperWriteFile, (self.mounttmp,))
638 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
639 self.assertRegex(collection2["manifest_text"],
640 r'\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
641 self.pool.apply(fuseRmTestHelperDeleteFile, (self.mounttmp,))
643 # Empty directories are represented by an empty file named "."
644 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
645 self.assertRegex(collection2["manifest_text"],
646 r'./testdir d41d8cd98f00b204e9800998ecf8427e\+0\+A\S+ 0:0:\\056\n')
648 self.pool.apply(fuseRmTestHelperRmdir, (self.mounttmp,))
650 # manifest should be empty now.
651 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
652 self.assertEqual(collection2["manifest_text"], "")
655 def fuseMvFileTestHelperWriteFile(mounttmp):
656 class Test(unittest.TestCase):
658 os.mkdir(os.path.join(mounttmp, "testdir"))
660 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
661 f.write("Hello world!")
665 def fuseMvFileTestHelperMoveFile(mounttmp):
666 class Test(unittest.TestCase):
668 d1 = llfuse.listdir(os.path.join(mounttmp))
669 self.assertEqual(["testdir"], d1)
670 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
671 self.assertEqual(["file1.txt"], d1)
673 os.rename(os.path.join(mounttmp, "testdir", "file1.txt"), os.path.join(mounttmp, "file1.txt"))
675 d1 = llfuse.listdir(os.path.join(mounttmp))
676 self.assertEqual(["file1.txt", "testdir"], sorted(d1))
677 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
678 self.assertEqual([], d1)
682 class FuseMvFileTest(MountTestBase):
684 collection = arvados.collection.Collection(api_client=self.api)
685 collection.save_new()
687 m = self.make_mount(fuse.CollectionDirectory)
689 m.new_collection(collection.api_response(), collection)
690 self.assertTrue(m.writable())
692 self.pool.apply(fuseMvFileTestHelperWriteFile, (self.mounttmp,))
695 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
696 self.assertRegex(collection2["manifest_text"],
697 r'\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
699 self.pool.apply(fuseMvFileTestHelperMoveFile, (self.mounttmp,))
701 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
702 self.assertRegex(collection2["manifest_text"],
703 r'\. 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt\n\./testdir d41d8cd98f00b204e9800998ecf8427e\+0\+A\S+ 0:0:\\056\n')
706 def fuseRenameTestHelper(mounttmp):
707 class Test(unittest.TestCase):
709 os.mkdir(os.path.join(mounttmp, "testdir"))
711 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
712 f.write("Hello world!")
716 class FuseRenameTest(MountTestBase):
718 collection = arvados.collection.Collection(api_client=self.api)
719 collection.save_new()
721 m = self.make_mount(fuse.CollectionDirectory)
723 m.new_collection(collection.api_response(), collection)
724 self.assertTrue(m.writable())
726 self.pool.apply(fuseRenameTestHelper, (self.mounttmp,))
729 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
730 self.assertRegex(collection2["manifest_text"],
731 r'\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
733 d1 = llfuse.listdir(os.path.join(self.mounttmp))
734 self.assertEqual(["testdir"], d1)
735 d1 = llfuse.listdir(os.path.join(self.mounttmp, "testdir"))
736 self.assertEqual(["file1.txt"], d1)
738 os.rename(os.path.join(self.mounttmp, "testdir"), os.path.join(self.mounttmp, "testdir2"))
740 d1 = llfuse.listdir(os.path.join(self.mounttmp))
741 self.assertEqual(["testdir2"], sorted(d1))
742 d1 = llfuse.listdir(os.path.join(self.mounttmp, "testdir2"))
743 self.assertEqual(["file1.txt"], d1)
745 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
746 self.assertRegex(collection2["manifest_text"],
747 r'\./testdir2 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
750 class FuseUpdateFromEventTest(MountTestBase):
752 collection = arvados.collection.Collection(api_client=self.api)
753 collection.save_new()
755 m = self.make_mount(fuse.CollectionDirectory)
757 m.new_collection(collection.api_response(), collection)
759 self.operations.listen_for_events()
761 d1 = llfuse.listdir(os.path.join(self.mounttmp))
762 self.assertEqual([], sorted(d1))
764 with arvados.collection.Collection(collection.manifest_locator(), api_client=self.api) as collection2:
765 with collection2.open("file1.txt", "w") as f:
768 for attempt in AssertWithTimeout(10):
769 attempt(self.assertEqual, ["file1.txt"], llfuse.listdir(os.path.join(self.mounttmp)))
772 class FuseDeleteProjectEventTest(MountTestBase):
775 aproject = self.api.groups().create(body={
777 "group_class": "project"
780 bproject = self.api.groups().create(body={
782 "group_class": "project",
783 "owner_uuid": aproject["uuid"]
786 self.make_mount(fuse.ProjectDirectory,
787 project_object=self.api.users().current().execute())
789 self.operations.listen_for_events()
791 d1 = llfuse.listdir(os.path.join(self.mounttmp, "aproject"))
792 self.assertEqual(["bproject"], sorted(d1))
794 self.api.groups().delete(uuid=bproject["uuid"]).execute()
796 for attempt in AssertWithTimeout(10):
797 attempt(self.assertEqual, [], llfuse.listdir(os.path.join(self.mounttmp, "aproject")))
800 def fuseFileConflictTestHelper(mounttmp, uuid, keeptmp, settings):
801 class Test(unittest.TestCase):
803 os.environ['KEEP_LOCAL_STORE'] = keeptmp
805 with open(os.path.join(mounttmp, "file1.txt"), "w") as f:
806 with arvados.collection.Collection(uuid, api_client=arvados.api_from_config('v1', apiconfig=settings)) as collection2:
807 with collection2.open("file1.txt", "w") as f2:
811 d1 = sorted(llfuse.listdir(os.path.join(mounttmp)))
812 self.assertEqual(len(d1), 2)
814 with open(os.path.join(mounttmp, "file1.txt"), "r") as f:
815 self.assertEqual(f.read(), "bar")
817 self.assertRegex(d1[1],
818 r'file1\.txt~\d\d\d\d\d\d\d\d-\d\d\d\d\d\d~conflict~')
820 with open(os.path.join(mounttmp, d1[1]), "r") as f:
821 self.assertEqual(f.read(), "foo")
825 class FuseFileConflictTest(MountTestBase):
827 collection = arvados.collection.Collection(api_client=self.api)
828 collection.save_new()
830 m = self.make_mount(fuse.CollectionDirectory)
832 m.new_collection(collection.api_response(), collection)
834 d1 = llfuse.listdir(os.path.join(self.mounttmp))
835 self.assertEqual([], sorted(d1))
837 # See note in MountTestBase.setUp
838 self.pool.apply(fuseFileConflictTestHelper, (self.mounttmp, collection.manifest_locator(), self.keeptmp, arvados.config.settings()))
841 def fuseUnlinkOpenFileTest(mounttmp):
842 class Test(unittest.TestCase):
844 with open(os.path.join(mounttmp, "file1.txt"), "w+") as f:
847 d1 = llfuse.listdir(os.path.join(mounttmp))
848 self.assertEqual(["file1.txt"], sorted(d1))
850 os.remove(os.path.join(mounttmp, "file1.txt"))
852 d1 = llfuse.listdir(os.path.join(mounttmp))
853 self.assertEqual([], sorted(d1))
856 self.assertEqual(f.read(), "foo")
860 self.assertEqual(f.read(), "foobar")
864 class FuseUnlinkOpenFileTest(MountTestBase):
866 collection = arvados.collection.Collection(api_client=self.api)
867 collection.save_new()
869 m = self.make_mount(fuse.CollectionDirectory)
871 m.new_collection(collection.api_response(), collection)
873 # See note in MountTestBase.setUp
874 self.pool.apply(fuseUnlinkOpenFileTest, (self.mounttmp,))
876 self.assertEqual(collection.manifest_text(), "")
879 def fuseMvFileBetweenCollectionsTest1(mounttmp, uuid1, uuid2):
880 class Test(unittest.TestCase):
882 with open(os.path.join(mounttmp, uuid1, "file1.txt"), "w") as f:
883 f.write("Hello world!")
885 d1 = os.listdir(os.path.join(mounttmp, uuid1))
886 self.assertEqual(["file1.txt"], sorted(d1))
887 d1 = os.listdir(os.path.join(mounttmp, uuid2))
888 self.assertEqual([], sorted(d1))
892 def fuseMvFileBetweenCollectionsTest2(mounttmp, uuid1, uuid2):
893 class Test(unittest.TestCase):
895 os.rename(os.path.join(mounttmp, uuid1, "file1.txt"), os.path.join(mounttmp, uuid2, "file2.txt"))
897 d1 = os.listdir(os.path.join(mounttmp, uuid1))
898 self.assertEqual([], sorted(d1))
899 d1 = os.listdir(os.path.join(mounttmp, uuid2))
900 self.assertEqual(["file2.txt"], sorted(d1))
904 class FuseMvFileBetweenCollectionsTest(MountTestBase):
906 collection1 = arvados.collection.Collection(api_client=self.api)
907 collection1.save_new()
909 collection2 = arvados.collection.Collection(api_client=self.api)
910 collection2.save_new()
912 m = self.make_mount(fuse.MagicDirectory)
914 # See note in MountTestBase.setUp
915 self.pool.apply(fuseMvFileBetweenCollectionsTest1, (self.mounttmp,
916 collection1.manifest_locator(),
917 collection2.manifest_locator()))
922 self.assertRegex(collection1.manifest_text(), r"\. 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$")
923 self.assertEqual(collection2.manifest_text(), "")
925 self.pool.apply(fuseMvFileBetweenCollectionsTest2, (self.mounttmp,
926 collection1.manifest_locator(),
927 collection2.manifest_locator()))
932 self.assertEqual(collection1.manifest_text(), "")
933 self.assertRegex(collection2.manifest_text(), r"\. 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file2\.txt$")
935 collection1.stop_threads()
936 collection2.stop_threads()
939 def fuseMvDirBetweenCollectionsTest1(mounttmp, uuid1, uuid2):
940 class Test(unittest.TestCase):
942 os.mkdir(os.path.join(mounttmp, uuid1, "testdir"))
943 with open(os.path.join(mounttmp, uuid1, "testdir", "file1.txt"), "w") as f:
944 f.write("Hello world!")
946 d1 = os.listdir(os.path.join(mounttmp, uuid1))
947 self.assertEqual(["testdir"], sorted(d1))
948 d1 = os.listdir(os.path.join(mounttmp, uuid1, "testdir"))
949 self.assertEqual(["file1.txt"], sorted(d1))
951 d1 = os.listdir(os.path.join(mounttmp, uuid2))
952 self.assertEqual([], sorted(d1))
957 def fuseMvDirBetweenCollectionsTest2(mounttmp, uuid1, uuid2):
958 class Test(unittest.TestCase):
960 os.rename(os.path.join(mounttmp, uuid1, "testdir"), os.path.join(mounttmp, uuid2, "testdir2"))
962 d1 = os.listdir(os.path.join(mounttmp, uuid1))
963 self.assertEqual([], sorted(d1))
965 d1 = os.listdir(os.path.join(mounttmp, uuid2))
966 self.assertEqual(["testdir2"], sorted(d1))
967 d1 = os.listdir(os.path.join(mounttmp, uuid2, "testdir2"))
968 self.assertEqual(["file1.txt"], sorted(d1))
970 with open(os.path.join(mounttmp, uuid2, "testdir2", "file1.txt"), "r") as f:
971 self.assertEqual(f.read(), "Hello world!")
975 class FuseMvDirBetweenCollectionsTest(MountTestBase):
977 collection1 = arvados.collection.Collection(api_client=self.api)
978 collection1.save_new()
980 collection2 = arvados.collection.Collection(api_client=self.api)
981 collection2.save_new()
983 m = self.make_mount(fuse.MagicDirectory)
985 # See note in MountTestBase.setUp
986 self.pool.apply(fuseMvDirBetweenCollectionsTest1, (self.mounttmp,
987 collection1.manifest_locator(),
988 collection2.manifest_locator()))
993 self.assertRegex(collection1.manifest_text(), r"\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$")
994 self.assertEqual(collection2.manifest_text(), "")
996 self.pool.apply(fuseMvDirBetweenCollectionsTest2, (self.mounttmp,
997 collection1.manifest_locator(),
998 collection2.manifest_locator()))
1000 collection1.update()
1001 collection2.update()
1003 self.assertEqual(collection1.manifest_text(), "")
1004 self.assertRegex(collection2.manifest_text(), r"\./testdir2 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$")
1006 collection1.stop_threads()
1007 collection2.stop_threads()
1009 def fuseProjectMkdirTestHelper1(mounttmp):
1010 class Test(unittest.TestCase):
1012 os.mkdir(os.path.join(mounttmp, "testcollection"))
1013 with self.assertRaises(OSError):
1014 os.mkdir(os.path.join(mounttmp, "testcollection"))
1017 def fuseProjectMkdirTestHelper2(mounttmp):
1018 class Test(unittest.TestCase):
1020 with open(os.path.join(mounttmp, "testcollection", "file1.txt"), "w") as f:
1021 f.write("Hello world!")
1022 with self.assertRaises(OSError):
1023 os.rmdir(os.path.join(mounttmp, "testcollection"))
1024 os.remove(os.path.join(mounttmp, "testcollection", "file1.txt"))
1025 with self.assertRaises(OSError):
1026 os.remove(os.path.join(mounttmp, "testcollection"))
1027 os.rmdir(os.path.join(mounttmp, "testcollection"))
1030 class FuseProjectMkdirRmdirTest(MountTestBase):
1032 self.make_mount(fuse.ProjectDirectory,
1033 project_object=self.api.users().current().execute())
1035 d1 = llfuse.listdir(self.mounttmp)
1036 self.assertNotIn('testcollection', d1)
1038 self.pool.apply(fuseProjectMkdirTestHelper1, (self.mounttmp,))
1040 d1 = llfuse.listdir(self.mounttmp)
1041 self.assertIn('testcollection', d1)
1043 self.pool.apply(fuseProjectMkdirTestHelper2, (self.mounttmp,))
1045 d1 = llfuse.listdir(self.mounttmp)
1046 self.assertNotIn('testcollection', d1)
1049 def fuseProjectMvTestHelper1(mounttmp):
1050 class Test(unittest.TestCase):
1052 d1 = llfuse.listdir(mounttmp)
1053 self.assertNotIn('testcollection', d1)
1055 os.mkdir(os.path.join(mounttmp, "testcollection"))
1057 d1 = llfuse.listdir(mounttmp)
1058 self.assertIn('testcollection', d1)
1060 with self.assertRaises(OSError):
1061 os.rename(os.path.join(mounttmp, "testcollection"), os.path.join(mounttmp, 'Unrestricted public data'))
1063 os.rename(os.path.join(mounttmp, "testcollection"), os.path.join(mounttmp, 'Unrestricted public data', 'testcollection'))
1065 d1 = llfuse.listdir(mounttmp)
1066 self.assertNotIn('testcollection', d1)
1068 d1 = llfuse.listdir(os.path.join(mounttmp, 'Unrestricted public data'))
1069 self.assertIn('testcollection', d1)
1073 class FuseProjectMvTest(MountTestBase):
1075 self.make_mount(fuse.ProjectDirectory,
1076 project_object=self.api.users().current().execute())
1078 self.pool.apply(fuseProjectMvTestHelper1, (self.mounttmp,))
1081 def fuseFsyncTestHelper(mounttmp, k):
1082 class Test(unittest.TestCase):
1084 fd = os.open(os.path.join(mounttmp, k), os.O_RDONLY)
1090 class FuseFsyncTest(FuseMagicTest):
1092 self.make_mount(fuse.MagicDirectory)
1093 self.pool.apply(fuseFsyncTestHelper, (self.mounttmp, self.testcollection))
1096 class MagicDirApiError(FuseMagicTest):
1098 api = mock.MagicMock()
1099 api.keep.block_cache = mock.MagicMock(cache_max=1)
1100 super(MagicDirApiError, self).setUp(api=api)
1101 api.collections().get().execute.side_effect = iter([
1102 Exception('API fail'),
1104 "manifest_text": self.test_manifest,
1105 "portable_data_hash": self.test_manifest_pdh,
1108 api.keep.get.side_effect = Exception('Keep fail')
1111 with mock.patch('arvados_fuse.fresh.FreshBase._poll_time', new_callable=mock.PropertyMock, return_value=60) as mock_poll_time:
1112 self.make_mount(fuse.MagicDirectory)
1114 self.operations.inodes.inode_cache.cap = 1
1115 self.operations.inodes.inode_cache.min_entries = 2
1117 with self.assertRaises(OSError):
1118 llfuse.listdir(os.path.join(self.mounttmp, self.testcollection))
1120 llfuse.listdir(os.path.join(self.mounttmp, self.testcollection))
1123 class SanitizeFilenameTest(MountTestBase):
1124 def test_sanitize_filename(self):
1125 pdir = fuse.ProjectDirectory(
1126 1, fuse.Inodes(None), self.api, 0, False, None,
1127 project_object=self.api.users().current().execute(),
1147 for f in acceptable:
1148 self.assertEqual(f, pdir.sanitize_filename(f))
1149 for f in unacceptable:
1150 self.assertNotEqual(f, pdir.sanitize_filename(f))
1151 # The sanitized filename should be the same length, though.
1152 self.assertEqual(len(f), len(pdir.sanitize_filename(f)))
1154 self.assertEqual("_", pdir.sanitize_filename(""))
1155 self.assertEqual("_", pdir.sanitize_filename("."))
1156 self.assertEqual("__", pdir.sanitize_filename(".."))
1159 class FuseMagicTestPDHOnly(MountTestBase):
1160 def setUp(self, api=None):
1161 super(FuseMagicTestPDHOnly, self).setUp(api=api)
1163 cw = arvados.CollectionWriter()
1165 cw.start_new_file('thing1.txt')
1168 self.testcollection = cw.finish()
1169 self.test_manifest = cw.manifest_text()
1170 created = self.api.collections().create(body={"manifest_text":self.test_manifest}).execute()
1171 self.testcollectionuuid = str(created['uuid'])
1173 def verify_pdh_only(self, pdh_only=False, skip_pdh_only=False):
1174 if skip_pdh_only is True:
1175 self.make_mount(fuse.MagicDirectory) # in this case, the default by_id applies
1177 self.make_mount(fuse.MagicDirectory, pdh_only=pdh_only)
1179 mount_ls = llfuse.listdir(self.mounttmp)
1180 self.assertIn('README', mount_ls)
1181 self.assertFalse(any(arvados.util.keep_locator_pattern.match(fn) or
1182 arvados.util.uuid_pattern.match(fn)
1183 for fn in mount_ls),
1184 "new FUSE MagicDirectory lists Collection")
1186 # look up using pdh should succeed in all cases
1187 self.assertDirContents(self.testcollection, ['thing1.txt'])
1188 self.assertDirContents(os.path.join('by_id', self.testcollection),
1190 mount_ls = llfuse.listdir(self.mounttmp)
1191 self.assertIn('README', mount_ls)
1192 self.assertIn(self.testcollection, mount_ls)
1193 self.assertIn(self.testcollection,
1194 llfuse.listdir(os.path.join(self.mounttmp, 'by_id')))
1197 files[os.path.join(self.mounttmp, self.testcollection, 'thing1.txt')] = 'data 1'
1199 for k, v in files.items():
1200 with open(os.path.join(self.mounttmp, k), 'rb') as f:
1201 self.assertEqual(v, f.read().decode())
1203 # look up using uuid should fail when pdh_only is set
1204 if pdh_only is True:
1205 with self.assertRaises(OSError):
1206 self.assertDirContents(os.path.join('by_id', self.testcollectionuuid),
1209 self.assertDirContents(os.path.join('by_id', self.testcollectionuuid),
1212 def test_with_pdh_only_true(self):
1213 self.verify_pdh_only(pdh_only=True)
1215 def test_with_pdh_only_false(self):
1216 self.verify_pdh_only(pdh_only=False)
1218 def test_with_default_by_id(self):
1219 self.verify_pdh_only(skip_pdh_only=True)
1222 class SlashSubstitutionTest(IntegrationTest):
1225 '--mount-home', 'zzz',
1230 super(SlashSubstitutionTest, self).setUp()
1232 self.api = arvados.safeapi.ThreadSafeApiCache(
1233 arvados.config.settings(),
1236 self.testcoll = self.api.collections().create(body={"name": "foo/bar/baz"}).execute()
1237 self.testcolleasy = self.api.collections().create(body={"name": "foo-bar-baz"}).execute()
1238 self.fusename = 'foo[SLASH]bar[SLASH]baz'
1240 @IntegrationTest.mount(argv=mnt_args)
1241 def test_slash_substitution_before_listing(self):
1242 self.pool_test(os.path.join(self.mnt, 'zzz'), self.fusename)
1243 self.checkContents()
1245 def _test_slash_substitution_before_listing(self, tmpdir, fusename):
1246 with open(os.path.join(tmpdir, 'foo-bar-baz', 'waz'), 'w') as f:
1248 with open(os.path.join(tmpdir, fusename, 'waz'), 'w') as f:
1251 @IntegrationTest.mount(argv=mnt_args)
1252 @mock.patch('arvados.util.get_config_once')
1253 def test_slash_substitution_after_listing(self, get_config_once):
1254 get_config_once.return_value = {"Collections": {"ForwardSlashNameSubstitution": "[SLASH]"}}
1255 self.pool_test(os.path.join(self.mnt, 'zzz'), self.fusename)
1256 self.checkContents()
1258 def _test_slash_substitution_after_listing(self, tmpdir, fusename):
1259 with open(os.path.join(tmpdir, 'foo-bar-baz', 'waz'), 'w') as f:
1262 with open(os.path.join(tmpdir, fusename, 'waz'), 'w') as f:
1265 def checkContents(self):
1266 self.assertRegexpMatches(self.api.collections().get(uuid=self.testcoll['uuid']).execute()['manifest_text'], ' acbd18db') # md5(foo)
1267 self.assertRegexpMatches(self.api.collections().get(uuid=self.testcolleasy['uuid']).execute()['manifest_text'], ' f561aaf6') # md5(xxx)
1269 @IntegrationTest.mount(argv=mnt_args)
1270 @mock.patch('arvados.util.get_config_once')
1271 def test_slash_substitution_conflict(self, get_config_once):
1272 self.testcollconflict = self.api.collections().create(body={"name": self.fusename}).execute()
1273 get_config_once.return_value = {"Collections": {"ForwardSlashNameSubstitution": "[SLASH]"}}
1274 self.pool_test(os.path.join(self.mnt, 'zzz'), self.fusename)
1275 self.assertRegexpMatches(self.api.collections().get(uuid=self.testcollconflict['uuid']).execute()['manifest_text'], ' acbd18db') # md5(foo)
1276 # foo/bar/baz collection unchanged, because it is masked by foo[SLASH]bar[SLASH]baz
1277 self.assertEqual(self.api.collections().get(uuid=self.testcoll['uuid']).execute()['manifest_text'], '')
1279 def _test_slash_substitution_conflict(self, tmpdir, fusename):
1280 with open(os.path.join(tmpdir, fusename, 'waz'), 'w') as f:
1283 class StorageClassesTest(IntegrationTest):
1286 '--mount-home', 'homedir',
1290 super(StorageClassesTest, self).setUp()
1291 self.api = arvados.safeapi.ThreadSafeApiCache(
1292 arvados.config.settings(),
1296 @IntegrationTest.mount(argv=mnt_args)
1297 def test_collection_default_storage_classes(self):
1298 coll_path = os.path.join(self.mnt, 'homedir', 'a_collection')
1299 self.api.collections().create(body={'name':'a_collection'}).execute()
1300 self.pool_test(coll_path)
1302 def _test_collection_default_storage_classes(self, coll):
1303 self.assertEqual(storage_classes_desired(coll), ['default'])
1305 @IntegrationTest.mount(argv=mnt_args+['--storage-classes', 'foo'])
1306 def test_collection_custom_storage_classes(self):
1307 coll_path = os.path.join(self.mnt, 'homedir', 'new_coll')
1309 self.pool_test(coll_path)
1311 def _test_collection_custom_storage_classes(self, coll):
1312 self.assertEqual(storage_classes_desired(coll), ['foo'])
1314 def _readonlyCollectionTestHelper(mounttmp):
1315 f = open(os.path.join(mounttmp, 'thing1.txt'), 'rt')
1316 # Testing that close() doesn't raise an error.
1319 class ReadonlyCollectionTest(MountTestBase):
1321 super(ReadonlyCollectionTest, self).setUp()
1322 cw = arvados.collection.Collection()
1323 with cw.open('thing1.txt', 'wt') as f:
1325 cw.save_new(owner_uuid=run_test_server.fixture("groups")["aproject"]["uuid"])
1326 self.testcollection = cw.api_response()
1329 settings = arvados.config.settings().copy()
1330 settings["ARVADOS_API_TOKEN"] = run_test_server.fixture("api_client_authorizations")["project_viewer"]["api_token"]
1331 self.api = arvados.safeapi.ThreadSafeApiCache(settings, version='v1')
1332 self.make_mount(fuse.CollectionDirectory, collection_record=self.testcollection, enable_write=False)
1334 self.pool.apply(_readonlyCollectionTestHelper, (self.mounttmp,))
1337 @parameterized.parameterized_class([
1338 {'root_class': fusedir.ProjectDirectory, 'root_kwargs': {
1339 'project_object': run_test_server.fixture('users')['admin'],
1341 {'root_class': fusedir.ProjectDirectory, 'root_kwargs': {
1342 'project_object': run_test_server.fixture('groups')['public'],
1345 class UnsupportedCreateTest(MountTestBase):
1351 if 'prefs' in self.root_kwargs.get('project_object', ()):
1352 self.root_kwargs['project_object']['prefs'] = {}
1353 self.make_mount(self.root_class, **self.root_kwargs)
1354 # Make sure the directory knows about its top-level ents.
1355 os.listdir(self.mounttmp)
1357 def test_create(self):
1358 test_path = Path(self.mounttmp, 'test_create')
1359 with self.assertRaises(OSError) as exc_check:
1360 with test_path.open('w'):
1362 self.assertEqual(exc_check.exception.errno, errno.ENOTSUP)
1365 # FIXME: IMO, for consistency with the "create inside a project" case,
1366 # these operations should also return ENOTSUP instead of EPERM.
1367 # Right now they're returning EPERM because the clasess' writable() method
1368 # usually returns False, and the Operations class transforms that accordingly.
1369 # However, for cases where the mount will never be writable, I think ENOTSUP
1370 # is a clearer error: it lets the user know they can't fix the problem by
1371 # adding permissions in Arvados, etc.
1372 @parameterized.parameterized_class([
1373 {'root_class': fusedir.MagicDirectory,
1374 'preset_dir': 'by_id',
1375 'preset_file': 'README',
1378 {'root_class': fusedir.SharedDirectory,
1380 'exclude': run_test_server.fixture('users')['admin']['uuid'],
1382 'preset_dir': 'Active User',
1385 {'root_class': fusedir.TagDirectory,
1387 'tag': run_test_server.fixture('links')['foo_collection_tag']['name'],
1389 'preset_dir': run_test_server.fixture('collections')['foo_collection_in_aproject']['uuid'],
1392 {'root_class': fusedir.TagsDirectory,
1393 'preset_dir': run_test_server.fixture('links')['foo_collection_tag']['name'],
1396 class UnsupportedOperationsTest(UnsupportedCreateTest):
1400 def test_create(self):
1401 test_path = Path(self.mounttmp, 'test_create')
1402 with self.assertRaises(OSError) as exc_check:
1403 with test_path.open('w'):
1405 self.assertEqual(exc_check.exception.errno, errno.EPERM)
1407 def test_mkdir(self):
1408 test_path = Path(self.mounttmp, 'test_mkdir')
1409 with self.assertRaises(OSError) as exc_check:
1411 self.assertEqual(exc_check.exception.errno, errno.EPERM)
1413 def test_rename(self):
1414 src_name = self.preset_dir or self.preset_file
1415 if src_name is None:
1417 test_src = Path(self.mounttmp, src_name)
1418 test_dst = test_src.with_name('test_dst')
1419 with self.assertRaises(OSError) as exc_check:
1420 test_src.rename(test_dst)
1421 self.assertEqual(exc_check.exception.errno, errno.EPERM)
1423 def test_rmdir(self):
1424 if self.preset_dir is None:
1426 test_path = Path(self.mounttmp, self.preset_dir)
1427 with self.assertRaises(OSError) as exc_check:
1429 self.assertEqual(exc_check.exception.errno, errno.EPERM)
1431 def test_unlink(self):
1432 if self.preset_file is None:
1434 test_path = Path(self.mounttmp, self.preset_file)
1435 with self.assertRaises(OSError) as exc_check:
1437 self.assertEqual(exc_check.exception.errno, errno.EPERM)