1 # Copyright (C) The Arvados Authors. All rights reserved.
3 # SPDX-License-Identifier: AGPL-3.0
5 from __future__ import absolute_import
6 from future.utils import viewitems
7 from builtins import str
8 from builtins import object
9 from pathlib import Path
10 from six import assertRegex
22 from unittest import mock
25 import arvados_fuse as fuse
26 from arvados_fuse import fusedir
27 from . import run_test_server
29 from .integration_test import IntegrationTest
30 from .mount_test_base import MountTestBase
31 from .test_tmp_collection import storage_classes_desired
33 logger = logging.getLogger('arvados.arv-mount')
36 class AssertWithTimeout(object):
37 """Allow some time for an assertion to pass."""
39 def __init__(self, timeout=0):
40 self.timeout = timeout
43 self.deadline = time.time() + self.timeout
52 def attempt(self, fn, *args, **kwargs):
55 except AssertionError:
56 if time.time() > self.deadline:
62 @parameterized.parameterized_class([{"disk_cache": True}, {"disk_cache": False}])
63 class FuseMountTest(MountTestBase):
65 super(FuseMountTest, self).setUp()
67 cw = arvados.CollectionWriter()
69 cw.start_new_file('thing1.txt')
71 cw.start_new_file('thing2.txt')
74 cw.start_new_stream('dir1')
75 cw.start_new_file('thing3.txt')
77 cw.start_new_file('thing4.txt')
80 cw.start_new_stream('dir2')
81 cw.start_new_file('thing5.txt')
83 cw.start_new_file('thing6.txt')
86 cw.start_new_stream('dir2/dir3')
87 cw.start_new_file('thing7.txt')
90 cw.start_new_file('thing8.txt')
93 cw.start_new_stream('edgecases')
94 for f in ":/.../-/*/ ".split("/"):
98 for f in ":/.../-/*/ ".split("/"):
99 cw.start_new_stream('edgecases/dirs/' + f)
100 cw.start_new_file('x/x')
103 self.testcollection = cw.finish()
104 self.api.collections().create(body={"manifest_text":cw.manifest_text()}).execute()
107 self.make_mount(fuse.CollectionDirectory, collection_record=self.testcollection)
109 self.assertDirContents(None, ['thing1.txt', 'thing2.txt',
110 'edgecases', 'dir1', 'dir2'])
111 self.assertDirContents('dir1', ['thing3.txt', 'thing4.txt'])
112 self.assertDirContents('dir2', ['thing5.txt', 'thing6.txt', 'dir3'])
113 self.assertDirContents('dir2/dir3', ['thing7.txt', 'thing8.txt'])
114 self.assertDirContents('edgecases',
115 "dirs/:/.../-/*/ ".split("/"))
116 self.assertDirContents('edgecases/dirs',
117 ":/.../-/*/ ".split("/"))
119 files = {'thing1.txt': 'data 1',
120 'thing2.txt': 'data 2',
121 'dir1/thing3.txt': 'data 3',
122 'dir1/thing4.txt': 'data 4',
123 'dir2/thing5.txt': 'data 5',
124 'dir2/thing6.txt': 'data 6',
125 'dir2/dir3/thing7.txt': 'data 7',
126 'dir2/dir3/thing8.txt': 'data 8'}
128 for k, v in viewitems(files):
129 with open(os.path.join(self.mounttmp, k), 'rb') as f:
130 self.assertEqual(v, f.read().decode())
133 @parameterized.parameterized_class([{"disk_cache": True}, {"disk_cache": False}])
134 class FuseMagicTest(MountTestBase):
135 def setUp(self, api=None):
136 super(FuseMagicTest, self).setUp(api=api)
138 self.test_project = run_test_server.fixture('groups')['aproject']['uuid']
139 self.non_project_group = run_test_server.fixture('groups')['public_role']['uuid']
140 self.filter_group = run_test_server.fixture('groups')['afiltergroup']['uuid']
141 self.collection_in_test_project = run_test_server.fixture('collections')['foo_collection_in_aproject']['name']
142 self.collection_in_filter_group = run_test_server.fixture('collections')['baz_file']['name']
144 cw = arvados.CollectionWriter()
146 cw.start_new_file('thing1.txt')
149 self.testcollection = cw.finish()
150 self.test_manifest = cw.manifest_text()
151 coll = self.api.collections().create(body={"manifest_text":self.test_manifest}).execute()
152 self.test_manifest_pdh = coll['portable_data_hash']
155 self.make_mount(fuse.MagicDirectory)
157 mount_ls = llfuse.listdir(self.mounttmp)
158 self.assertIn('README', mount_ls)
159 self.assertFalse(any(arvados.util.keep_locator_pattern.match(fn) or
160 arvados.util.uuid_pattern.match(fn)
162 "new FUSE MagicDirectory has no collections or projects")
163 self.assertDirContents(self.testcollection, ['thing1.txt'])
164 self.assertDirContents(os.path.join('by_id', self.testcollection),
166 self.assertIn(self.collection_in_test_project,
167 llfuse.listdir(os.path.join(self.mounttmp, self.test_project)))
168 self.assertIn(self.collection_in_test_project,
169 llfuse.listdir(os.path.join(self.mounttmp, 'by_id', self.test_project)))
170 self.assertIn(self.collection_in_filter_group,
171 llfuse.listdir(os.path.join(self.mounttmp, self.filter_group)))
172 self.assertIn(self.collection_in_filter_group,
173 llfuse.listdir(os.path.join(self.mounttmp, 'by_id', self.filter_group)))
176 mount_ls = llfuse.listdir(self.mounttmp)
177 self.assertIn('README', mount_ls)
178 self.assertIn(self.testcollection, mount_ls)
179 self.assertIn(self.testcollection,
180 llfuse.listdir(os.path.join(self.mounttmp, 'by_id')))
181 self.assertIn(self.test_project, mount_ls)
182 self.assertIn(self.test_project,
183 llfuse.listdir(os.path.join(self.mounttmp, 'by_id')))
184 self.assertIn(self.filter_group,
185 llfuse.listdir(os.path.join(self.mounttmp, 'by_id')))
187 with self.assertRaises(OSError):
188 llfuse.listdir(os.path.join(self.mounttmp, 'by_id', self.non_project_group))
191 files[os.path.join(self.mounttmp, self.testcollection, 'thing1.txt')] = 'data 1'
193 for k, v in viewitems(files):
194 with open(os.path.join(self.mounttmp, k), 'rb') as f:
195 self.assertEqual(v, f.read().decode())
198 class FuseTagsTest(MountTestBase):
200 self.make_mount(fuse.TagsDirectory)
202 d1 = llfuse.listdir(self.mounttmp)
204 self.assertEqual(['foo_tag'], d1)
206 d2 = llfuse.listdir(os.path.join(self.mounttmp, 'foo_tag'))
208 self.assertEqual(['zzzzz-4zz18-fy296fx3hot09f7'], d2)
210 d3 = llfuse.listdir(os.path.join(self.mounttmp, 'foo_tag', 'zzzzz-4zz18-fy296fx3hot09f7'))
212 self.assertEqual(['foo'], d3)
215 class FuseTagsUpdateTest(MountTestBase):
216 def tag_collection(self, coll_uuid, tag_name):
217 return self.api.links().create(
218 body={'link': {'head_uuid': coll_uuid,
224 self.make_mount(fuse.TagsDirectory, poll_time=1)
226 self.assertIn('foo_tag', llfuse.listdir(self.mounttmp))
228 bar_uuid = run_test_server.fixture('collections')['bar_file']['uuid']
229 self.tag_collection(bar_uuid, 'fuse_test_tag')
230 for attempt in AssertWithTimeout(10):
231 attempt(self.assertIn, 'fuse_test_tag', llfuse.listdir(self.mounttmp))
232 self.assertDirContents('fuse_test_tag', [bar_uuid])
234 baz_uuid = run_test_server.fixture('collections')['baz_file']['uuid']
235 l = self.tag_collection(baz_uuid, 'fuse_test_tag')
236 for attempt in AssertWithTimeout(10):
237 attempt(self.assertDirContents, 'fuse_test_tag', [bar_uuid, baz_uuid])
239 self.api.links().delete(uuid=l['uuid']).execute()
240 for attempt in AssertWithTimeout(10):
241 attempt(self.assertDirContents, 'fuse_test_tag', [bar_uuid])
244 def fuseSharedTestHelper(mounttmp):
245 class Test(unittest.TestCase):
247 # Double check that we can open and read objects in this folder as a file,
248 # and that its contents are what we expect.
249 baz_path = os.path.join(
253 'collection in FUSE project',
255 with open(baz_path) as f:
256 self.assertEqual("baz", f.read())
258 # check mtime on collection
259 st = os.stat(baz_path)
261 mtime = st.st_mtime_ns // 1000000000
262 except AttributeError:
264 self.assertEqual(mtime, 1391448174)
266 # shared_dirs is a list of the directories exposed
267 # by fuse.SharedDirectory (i.e. any object visible
268 # to the current user)
269 shared_dirs = llfuse.listdir(mounttmp)
271 self.assertIn('FUSE User', shared_dirs)
273 # fuse_user_objs is a list of the objects owned by the FUSE
274 # test user (which present as files in the 'FUSE User'
276 fuse_user_objs = llfuse.listdir(os.path.join(mounttmp, 'FUSE User'))
277 fuse_user_objs.sort()
278 self.assertEqual(['FUSE Test Project', # project owned by user
279 'collection #1 owned by FUSE', # collection owned by user
280 'collection #2 owned by FUSE' # collection owned by user
283 # test_proj_files is a list of the files in the FUSE Test Project.
284 test_proj_files = llfuse.listdir(os.path.join(mounttmp, 'FUSE User', 'FUSE Test Project'))
285 test_proj_files.sort()
286 self.assertEqual(['collection in FUSE project'
292 @parameterized.parameterized_class([{"disk_cache": True}, {"disk_cache": False}])
293 class FuseSharedTest(MountTestBase):
295 self.make_mount(fuse.SharedDirectory,
296 exclude=self.api.users().current().execute()['uuid'])
297 keep = arvados.keep.KeepClient()
298 keep.put("baz".encode())
300 self.pool.apply(fuseSharedTestHelper, (self.mounttmp,))
303 class FuseHomeTest(MountTestBase):
305 self.make_mount(fuse.ProjectDirectory,
306 project_object=self.api.users().current().execute())
308 d1 = llfuse.listdir(self.mounttmp)
309 self.assertIn('Unrestricted public data', d1)
311 d2 = llfuse.listdir(os.path.join(self.mounttmp, 'Unrestricted public data'))
312 public_project = run_test_server.fixture('groups')[
313 'anonymously_accessible_project']
316 for name, item in viewitems(run_test_server.fixture('collections')):
317 if 'name' not in item:
319 elif item['owner_uuid'] == public_project['uuid']:
320 self.assertIn(item['name'], d2)
323 # Artificial assumption here: there is no public
324 # collection fixture with the same name as a
325 # non-public collection.
326 self.assertNotIn(item['name'], d2)
328 self.assertNotEqual(0, found_in)
329 self.assertNotEqual(0, found_not_in)
331 d3 = llfuse.listdir(os.path.join(self.mounttmp, 'Unrestricted public data', 'GNU General Public License, version 3'))
332 self.assertEqual(["GNU_General_Public_License,_version_3.pdf"], d3)
335 def fuseModifyFileTestHelperReadStartContents(mounttmp):
336 class Test(unittest.TestCase):
338 d1 = llfuse.listdir(mounttmp)
339 self.assertEqual(["file1.txt"], d1)
340 with open(os.path.join(mounttmp, "file1.txt")) as f:
341 self.assertEqual("blub", f.read())
344 def fuseModifyFileTestHelperReadEndContents(mounttmp):
345 class Test(unittest.TestCase):
347 d1 = llfuse.listdir(mounttmp)
348 self.assertEqual(["file1.txt"], d1)
349 with open(os.path.join(mounttmp, "file1.txt")) as f:
350 self.assertEqual("plnp", f.read())
353 @parameterized.parameterized_class([{"disk_cache": True}, {"disk_cache": False}])
354 class FuseModifyFileTest(MountTestBase):
356 collection = arvados.collection.Collection(api_client=self.api)
357 with collection.open("file1.txt", "w") as f:
360 collection.save_new()
362 m = self.make_mount(fuse.CollectionDirectory)
364 m.new_collection(collection.api_response(), collection)
366 self.pool.apply(fuseModifyFileTestHelperReadStartContents, (self.mounttmp,))
368 with collection.open("file1.txt", "w") as f:
371 self.pool.apply(fuseModifyFileTestHelperReadEndContents, (self.mounttmp,))
374 @parameterized.parameterized_class([{"disk_cache": True}, {"disk_cache": False}])
375 class FuseAddFileToCollectionTest(MountTestBase):
377 collection = arvados.collection.Collection(api_client=self.api)
378 with collection.open("file1.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"], d1)
390 with collection.open("file2.txt", "w") as f:
393 d1 = llfuse.listdir(self.mounttmp)
394 self.assertEqual(["file1.txt", "file2.txt"], sorted(d1))
397 @parameterized.parameterized_class([{"disk_cache": True}, {"disk_cache": False}])
398 class FuseRemoveFileFromCollectionTest(MountTestBase):
400 collection = arvados.collection.Collection(api_client=self.api)
401 with collection.open("file1.txt", "w") as f:
404 with collection.open("file2.txt", "w") as f:
407 collection.save_new()
409 m = self.make_mount(fuse.CollectionDirectory)
411 m.new_collection(collection.api_response(), collection)
413 d1 = llfuse.listdir(self.mounttmp)
414 self.assertEqual(["file1.txt", "file2.txt"], sorted(d1))
416 collection.remove("file2.txt")
418 d1 = llfuse.listdir(self.mounttmp)
419 self.assertEqual(["file1.txt"], d1)
422 def fuseCreateFileTestHelper(mounttmp):
423 class Test(unittest.TestCase):
425 with open(os.path.join(mounttmp, "file1.txt"), "w") as f:
429 @parameterized.parameterized_class([{"disk_cache": True}, {"disk_cache": False}])
430 class FuseCreateFileTest(MountTestBase):
432 collection = arvados.collection.Collection(api_client=self.api)
433 collection.save_new()
435 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
436 self.assertEqual(collection2["manifest_text"], "")
438 collection.save_new()
440 m = self.make_mount(fuse.CollectionDirectory)
442 m.new_collection(collection.api_response(), collection)
443 self.assertTrue(m.writable())
445 self.assertNotIn("file1.txt", collection)
447 self.pool.apply(fuseCreateFileTestHelper, (self.mounttmp,))
449 self.assertIn("file1.txt", collection)
451 d1 = llfuse.listdir(self.mounttmp)
452 self.assertEqual(["file1.txt"], d1)
454 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
455 assertRegex(self, collection2["manifest_text"],
456 r'\. d41d8cd98f00b204e9800998ecf8427e\+0\+A\S+ 0:0:file1\.txt$')
459 def fuseWriteFileTestHelperWriteFile(mounttmp):
460 class Test(unittest.TestCase):
462 with open(os.path.join(mounttmp, "file1.txt"), "w") as f:
463 f.write("Hello world!")
466 def fuseWriteFileTestHelperReadFile(mounttmp):
467 class Test(unittest.TestCase):
469 with open(os.path.join(mounttmp, "file1.txt"), "r") as f:
470 self.assertEqual(f.read(), "Hello world!")
473 @parameterized.parameterized_class([{"disk_cache": True}, {"disk_cache": False}])
474 class FuseWriteFileTest(MountTestBase):
476 collection = arvados.collection.Collection(api_client=self.api)
477 collection.save_new()
479 m = self.make_mount(fuse.CollectionDirectory)
481 m.new_collection(collection.api_response(), collection)
482 self.assertTrue(m.writable())
484 self.assertNotIn("file1.txt", collection)
486 self.assertEqual(0, self.operations.write_counter.get())
487 self.pool.apply(fuseWriteFileTestHelperWriteFile, (self.mounttmp,))
488 self.assertEqual(12, self.operations.write_counter.get())
490 with collection.open("file1.txt") as f:
491 self.assertEqual(f.read(), "Hello world!")
493 self.assertEqual(0, self.operations.read_counter.get())
494 self.pool.apply(fuseWriteFileTestHelperReadFile, (self.mounttmp,))
495 self.assertEqual(12, self.operations.read_counter.get())
497 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
498 assertRegex(self, collection2["manifest_text"],
499 r'\. 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
502 def fuseUpdateFileTestHelper(mounttmp):
503 class Test(unittest.TestCase):
505 with open(os.path.join(mounttmp, "file1.txt"), "w") as f:
506 f.write("Hello world!")
508 with open(os.path.join(mounttmp, "file1.txt"), "r+") as f:
510 self.assertEqual(fr, "Hello world!")
512 f.write("Hola mundo!")
515 self.assertEqual(fr, "Hola mundo!!")
517 with open(os.path.join(mounttmp, "file1.txt"), "r") as f:
518 self.assertEqual(f.read(), "Hola mundo!!")
522 @parameterized.parameterized_class([{"disk_cache": True}, {"disk_cache": False}])
523 class FuseUpdateFileTest(MountTestBase):
525 collection = arvados.collection.Collection(api_client=self.api)
526 collection.save_new()
528 m = self.make_mount(fuse.CollectionDirectory)
530 m.new_collection(collection.api_response(), collection)
531 self.assertTrue(m.writable())
533 # See note in MountTestBase.setUp
534 self.pool.apply(fuseUpdateFileTestHelper, (self.mounttmp,))
536 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
537 assertRegex(self, collection2["manifest_text"],
538 r'\. daaef200ebb921e011e3ae922dd3266b\+11\+A\S+ 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:11:file1\.txt 22:1:file1\.txt$')
541 def fuseMkdirTestHelper(mounttmp):
542 class Test(unittest.TestCase):
544 with self.assertRaises(IOError):
545 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
546 f.write("Hello world!")
548 os.mkdir(os.path.join(mounttmp, "testdir"))
550 with self.assertRaises(OSError):
551 os.mkdir(os.path.join(mounttmp, "testdir"))
553 d1 = llfuse.listdir(mounttmp)
554 self.assertEqual(["testdir"], d1)
556 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
557 f.write("Hello world!")
559 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
560 self.assertEqual(["file1.txt"], d1)
564 class FuseMkdirTest(MountTestBase):
566 collection = arvados.collection.Collection(api_client=self.api)
567 collection.save_new()
569 m = self.make_mount(fuse.CollectionDirectory)
571 m.new_collection(collection.api_response(), collection)
572 self.assertTrue(m.writable())
574 self.pool.apply(fuseMkdirTestHelper, (self.mounttmp,))
576 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
577 assertRegex(self, collection2["manifest_text"],
578 r'\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
581 def fuseRmTestHelperWriteFile(mounttmp):
582 class Test(unittest.TestCase):
584 os.mkdir(os.path.join(mounttmp, "testdir"))
586 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
587 f.write("Hello world!")
591 def fuseRmTestHelperDeleteFile(mounttmp):
592 class Test(unittest.TestCase):
594 # Can't delete because it's not empty
595 with self.assertRaises(OSError):
596 os.rmdir(os.path.join(mounttmp, "testdir"))
598 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
599 self.assertEqual(["file1.txt"], d1)
602 os.remove(os.path.join(mounttmp, "testdir", "file1.txt"))
604 # Make sure it's empty
605 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
606 self.assertEqual([], d1)
608 # Try to delete it again
609 with self.assertRaises(OSError):
610 os.remove(os.path.join(mounttmp, "testdir", "file1.txt"))
614 def fuseRmTestHelperRmdir(mounttmp):
615 class Test(unittest.TestCase):
617 # Should be able to delete now that it is empty
618 os.rmdir(os.path.join(mounttmp, "testdir"))
620 # Make sure it's empty
621 d1 = llfuse.listdir(os.path.join(mounttmp))
622 self.assertEqual([], d1)
624 # Try to delete it again
625 with self.assertRaises(OSError):
626 os.rmdir(os.path.join(mounttmp, "testdir"))
630 class FuseRmTest(MountTestBase):
632 collection = arvados.collection.Collection(api_client=self.api)
633 collection.save_new()
635 m = self.make_mount(fuse.CollectionDirectory)
637 m.new_collection(collection.api_response(), collection)
638 self.assertTrue(m.writable())
640 self.pool.apply(fuseRmTestHelperWriteFile, (self.mounttmp,))
643 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
644 assertRegex(self, collection2["manifest_text"],
645 r'\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
646 self.pool.apply(fuseRmTestHelperDeleteFile, (self.mounttmp,))
648 # Empty directories are represented by an empty file named "."
649 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
650 assertRegex(self, collection2["manifest_text"],
651 r'./testdir d41d8cd98f00b204e9800998ecf8427e\+0\+A\S+ 0:0:\\056\n')
653 self.pool.apply(fuseRmTestHelperRmdir, (self.mounttmp,))
655 # manifest should be empty now.
656 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
657 self.assertEqual(collection2["manifest_text"], "")
660 def fuseMvFileTestHelperWriteFile(mounttmp):
661 class Test(unittest.TestCase):
663 os.mkdir(os.path.join(mounttmp, "testdir"))
665 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
666 f.write("Hello world!")
670 def fuseMvFileTestHelperMoveFile(mounttmp):
671 class Test(unittest.TestCase):
673 d1 = llfuse.listdir(os.path.join(mounttmp))
674 self.assertEqual(["testdir"], d1)
675 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
676 self.assertEqual(["file1.txt"], d1)
678 os.rename(os.path.join(mounttmp, "testdir", "file1.txt"), os.path.join(mounttmp, "file1.txt"))
680 d1 = llfuse.listdir(os.path.join(mounttmp))
681 self.assertEqual(["file1.txt", "testdir"], sorted(d1))
682 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
683 self.assertEqual([], d1)
687 class FuseMvFileTest(MountTestBase):
689 collection = arvados.collection.Collection(api_client=self.api)
690 collection.save_new()
692 m = self.make_mount(fuse.CollectionDirectory)
694 m.new_collection(collection.api_response(), collection)
695 self.assertTrue(m.writable())
697 self.pool.apply(fuseMvFileTestHelperWriteFile, (self.mounttmp,))
700 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
701 assertRegex(self, collection2["manifest_text"],
702 r'\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
704 self.pool.apply(fuseMvFileTestHelperMoveFile, (self.mounttmp,))
706 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
707 assertRegex(self, collection2["manifest_text"],
708 r'\. 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt\n\./testdir d41d8cd98f00b204e9800998ecf8427e\+0\+A\S+ 0:0:\\056\n')
711 def fuseRenameTestHelper(mounttmp):
712 class Test(unittest.TestCase):
714 os.mkdir(os.path.join(mounttmp, "testdir"))
716 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
717 f.write("Hello world!")
721 class FuseRenameTest(MountTestBase):
723 collection = arvados.collection.Collection(api_client=self.api)
724 collection.save_new()
726 m = self.make_mount(fuse.CollectionDirectory)
728 m.new_collection(collection.api_response(), collection)
729 self.assertTrue(m.writable())
731 self.pool.apply(fuseRenameTestHelper, (self.mounttmp,))
734 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
735 assertRegex(self, collection2["manifest_text"],
736 r'\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
738 d1 = llfuse.listdir(os.path.join(self.mounttmp))
739 self.assertEqual(["testdir"], d1)
740 d1 = llfuse.listdir(os.path.join(self.mounttmp, "testdir"))
741 self.assertEqual(["file1.txt"], d1)
743 os.rename(os.path.join(self.mounttmp, "testdir"), os.path.join(self.mounttmp, "testdir2"))
745 d1 = llfuse.listdir(os.path.join(self.mounttmp))
746 self.assertEqual(["testdir2"], sorted(d1))
747 d1 = llfuse.listdir(os.path.join(self.mounttmp, "testdir2"))
748 self.assertEqual(["file1.txt"], d1)
750 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
751 assertRegex(self, collection2["manifest_text"],
752 r'\./testdir2 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
755 class FuseUpdateFromEventTest(MountTestBase):
757 collection = arvados.collection.Collection(api_client=self.api)
758 collection.save_new()
760 m = self.make_mount(fuse.CollectionDirectory)
762 m.new_collection(collection.api_response(), collection)
764 self.operations.listen_for_events()
766 d1 = llfuse.listdir(os.path.join(self.mounttmp))
767 self.assertEqual([], sorted(d1))
769 with arvados.collection.Collection(collection.manifest_locator(), api_client=self.api) as collection2:
770 with collection2.open("file1.txt", "w") as f:
773 for attempt in AssertWithTimeout(10):
774 attempt(self.assertEqual, ["file1.txt"], llfuse.listdir(os.path.join(self.mounttmp)))
777 class FuseDeleteProjectEventTest(MountTestBase):
780 aproject = self.api.groups().create(body={
782 "group_class": "project"
785 bproject = self.api.groups().create(body={
787 "group_class": "project",
788 "owner_uuid": aproject["uuid"]
791 self.make_mount(fuse.ProjectDirectory,
792 project_object=self.api.users().current().execute())
794 self.operations.listen_for_events()
796 d1 = llfuse.listdir(os.path.join(self.mounttmp, "aproject"))
797 self.assertEqual(["bproject"], sorted(d1))
799 self.api.groups().delete(uuid=bproject["uuid"]).execute()
801 for attempt in AssertWithTimeout(10):
802 attempt(self.assertEqual, [], llfuse.listdir(os.path.join(self.mounttmp, "aproject")))
805 def fuseFileConflictTestHelper(mounttmp, uuid, keeptmp, settings):
806 class Test(unittest.TestCase):
808 os.environ['KEEP_LOCAL_STORE'] = keeptmp
810 with open(os.path.join(mounttmp, "file1.txt"), "w") as f:
811 with arvados.collection.Collection(uuid, api_client=arvados.api_from_config('v1', apiconfig=settings)) as collection2:
812 with collection2.open("file1.txt", "w") as f2:
816 d1 = sorted(llfuse.listdir(os.path.join(mounttmp)))
817 self.assertEqual(len(d1), 2)
819 with open(os.path.join(mounttmp, "file1.txt"), "r") as f:
820 self.assertEqual(f.read(), "bar")
822 assertRegex(self, d1[1],
823 r'file1\.txt~\d\d\d\d\d\d\d\d-\d\d\d\d\d\d~conflict~')
825 with open(os.path.join(mounttmp, d1[1]), "r") as f:
826 self.assertEqual(f.read(), "foo")
830 class FuseFileConflictTest(MountTestBase):
832 collection = arvados.collection.Collection(api_client=self.api)
833 collection.save_new()
835 m = self.make_mount(fuse.CollectionDirectory)
837 m.new_collection(collection.api_response(), collection)
839 d1 = llfuse.listdir(os.path.join(self.mounttmp))
840 self.assertEqual([], sorted(d1))
842 # See note in MountTestBase.setUp
843 self.pool.apply(fuseFileConflictTestHelper, (self.mounttmp, collection.manifest_locator(), self.keeptmp, arvados.config.settings()))
846 def fuseUnlinkOpenFileTest(mounttmp):
847 class Test(unittest.TestCase):
849 with open(os.path.join(mounttmp, "file1.txt"), "w+") as f:
852 d1 = llfuse.listdir(os.path.join(mounttmp))
853 self.assertEqual(["file1.txt"], sorted(d1))
855 os.remove(os.path.join(mounttmp, "file1.txt"))
857 d1 = llfuse.listdir(os.path.join(mounttmp))
858 self.assertEqual([], sorted(d1))
861 self.assertEqual(f.read(), "foo")
865 self.assertEqual(f.read(), "foobar")
869 class FuseUnlinkOpenFileTest(MountTestBase):
871 collection = arvados.collection.Collection(api_client=self.api)
872 collection.save_new()
874 m = self.make_mount(fuse.CollectionDirectory)
876 m.new_collection(collection.api_response(), collection)
878 # See note in MountTestBase.setUp
879 self.pool.apply(fuseUnlinkOpenFileTest, (self.mounttmp,))
881 self.assertEqual(collection.manifest_text(), "")
884 def fuseMvFileBetweenCollectionsTest1(mounttmp, uuid1, uuid2):
885 class Test(unittest.TestCase):
887 with open(os.path.join(mounttmp, uuid1, "file1.txt"), "w") as f:
888 f.write("Hello world!")
890 d1 = os.listdir(os.path.join(mounttmp, uuid1))
891 self.assertEqual(["file1.txt"], sorted(d1))
892 d1 = os.listdir(os.path.join(mounttmp, uuid2))
893 self.assertEqual([], sorted(d1))
897 def fuseMvFileBetweenCollectionsTest2(mounttmp, uuid1, uuid2):
898 class Test(unittest.TestCase):
900 os.rename(os.path.join(mounttmp, uuid1, "file1.txt"), os.path.join(mounttmp, uuid2, "file2.txt"))
902 d1 = os.listdir(os.path.join(mounttmp, uuid1))
903 self.assertEqual([], sorted(d1))
904 d1 = os.listdir(os.path.join(mounttmp, uuid2))
905 self.assertEqual(["file2.txt"], sorted(d1))
909 class FuseMvFileBetweenCollectionsTest(MountTestBase):
911 collection1 = arvados.collection.Collection(api_client=self.api)
912 collection1.save_new()
914 collection2 = arvados.collection.Collection(api_client=self.api)
915 collection2.save_new()
917 m = self.make_mount(fuse.MagicDirectory)
919 # See note in MountTestBase.setUp
920 self.pool.apply(fuseMvFileBetweenCollectionsTest1, (self.mounttmp,
921 collection1.manifest_locator(),
922 collection2.manifest_locator()))
927 assertRegex(self, collection1.manifest_text(), r"\. 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$")
928 self.assertEqual(collection2.manifest_text(), "")
930 self.pool.apply(fuseMvFileBetweenCollectionsTest2, (self.mounttmp,
931 collection1.manifest_locator(),
932 collection2.manifest_locator()))
937 self.assertEqual(collection1.manifest_text(), "")
938 assertRegex(self, collection2.manifest_text(), r"\. 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file2\.txt$")
940 collection1.stop_threads()
941 collection2.stop_threads()
944 def fuseMvDirBetweenCollectionsTest1(mounttmp, uuid1, uuid2):
945 class Test(unittest.TestCase):
947 os.mkdir(os.path.join(mounttmp, uuid1, "testdir"))
948 with open(os.path.join(mounttmp, uuid1, "testdir", "file1.txt"), "w") as f:
949 f.write("Hello world!")
951 d1 = os.listdir(os.path.join(mounttmp, uuid1))
952 self.assertEqual(["testdir"], sorted(d1))
953 d1 = os.listdir(os.path.join(mounttmp, uuid1, "testdir"))
954 self.assertEqual(["file1.txt"], sorted(d1))
956 d1 = os.listdir(os.path.join(mounttmp, uuid2))
957 self.assertEqual([], sorted(d1))
962 def fuseMvDirBetweenCollectionsTest2(mounttmp, uuid1, uuid2):
963 class Test(unittest.TestCase):
965 os.rename(os.path.join(mounttmp, uuid1, "testdir"), os.path.join(mounttmp, uuid2, "testdir2"))
967 d1 = os.listdir(os.path.join(mounttmp, uuid1))
968 self.assertEqual([], sorted(d1))
970 d1 = os.listdir(os.path.join(mounttmp, uuid2))
971 self.assertEqual(["testdir2"], sorted(d1))
972 d1 = os.listdir(os.path.join(mounttmp, uuid2, "testdir2"))
973 self.assertEqual(["file1.txt"], sorted(d1))
975 with open(os.path.join(mounttmp, uuid2, "testdir2", "file1.txt"), "r") as f:
976 self.assertEqual(f.read(), "Hello world!")
980 class FuseMvDirBetweenCollectionsTest(MountTestBase):
982 collection1 = arvados.collection.Collection(api_client=self.api)
983 collection1.save_new()
985 collection2 = arvados.collection.Collection(api_client=self.api)
986 collection2.save_new()
988 m = self.make_mount(fuse.MagicDirectory)
990 # See note in MountTestBase.setUp
991 self.pool.apply(fuseMvDirBetweenCollectionsTest1, (self.mounttmp,
992 collection1.manifest_locator(),
993 collection2.manifest_locator()))
998 assertRegex(self, collection1.manifest_text(), r"\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$")
999 self.assertEqual(collection2.manifest_text(), "")
1001 self.pool.apply(fuseMvDirBetweenCollectionsTest2, (self.mounttmp,
1002 collection1.manifest_locator(),
1003 collection2.manifest_locator()))
1005 collection1.update()
1006 collection2.update()
1008 self.assertEqual(collection1.manifest_text(), "")
1009 assertRegex(self, collection2.manifest_text(), r"\./testdir2 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$")
1011 collection1.stop_threads()
1012 collection2.stop_threads()
1014 def fuseProjectMkdirTestHelper1(mounttmp):
1015 class Test(unittest.TestCase):
1017 os.mkdir(os.path.join(mounttmp, "testcollection"))
1018 with self.assertRaises(OSError):
1019 os.mkdir(os.path.join(mounttmp, "testcollection"))
1022 def fuseProjectMkdirTestHelper2(mounttmp):
1023 class Test(unittest.TestCase):
1025 with open(os.path.join(mounttmp, "testcollection", "file1.txt"), "w") as f:
1026 f.write("Hello world!")
1027 with self.assertRaises(OSError):
1028 os.rmdir(os.path.join(mounttmp, "testcollection"))
1029 os.remove(os.path.join(mounttmp, "testcollection", "file1.txt"))
1030 with self.assertRaises(OSError):
1031 os.remove(os.path.join(mounttmp, "testcollection"))
1032 os.rmdir(os.path.join(mounttmp, "testcollection"))
1035 class FuseProjectMkdirRmdirTest(MountTestBase):
1037 self.make_mount(fuse.ProjectDirectory,
1038 project_object=self.api.users().current().execute())
1040 d1 = llfuse.listdir(self.mounttmp)
1041 self.assertNotIn('testcollection', d1)
1043 self.pool.apply(fuseProjectMkdirTestHelper1, (self.mounttmp,))
1045 d1 = llfuse.listdir(self.mounttmp)
1046 self.assertIn('testcollection', d1)
1048 self.pool.apply(fuseProjectMkdirTestHelper2, (self.mounttmp,))
1050 d1 = llfuse.listdir(self.mounttmp)
1051 self.assertNotIn('testcollection', d1)
1054 def fuseProjectMvTestHelper1(mounttmp):
1055 class Test(unittest.TestCase):
1057 d1 = llfuse.listdir(mounttmp)
1058 self.assertNotIn('testcollection', d1)
1060 os.mkdir(os.path.join(mounttmp, "testcollection"))
1062 d1 = llfuse.listdir(mounttmp)
1063 self.assertIn('testcollection', d1)
1065 with self.assertRaises(OSError):
1066 os.rename(os.path.join(mounttmp, "testcollection"), os.path.join(mounttmp, 'Unrestricted public data'))
1068 os.rename(os.path.join(mounttmp, "testcollection"), os.path.join(mounttmp, 'Unrestricted public data', 'testcollection'))
1070 d1 = llfuse.listdir(mounttmp)
1071 self.assertNotIn('testcollection', d1)
1073 d1 = llfuse.listdir(os.path.join(mounttmp, 'Unrestricted public data'))
1074 self.assertIn('testcollection', d1)
1078 class FuseProjectMvTest(MountTestBase):
1080 self.make_mount(fuse.ProjectDirectory,
1081 project_object=self.api.users().current().execute())
1083 self.pool.apply(fuseProjectMvTestHelper1, (self.mounttmp,))
1086 def fuseFsyncTestHelper(mounttmp, k):
1087 class Test(unittest.TestCase):
1089 fd = os.open(os.path.join(mounttmp, k), os.O_RDONLY)
1095 class FuseFsyncTest(FuseMagicTest):
1097 self.make_mount(fuse.MagicDirectory)
1098 self.pool.apply(fuseFsyncTestHelper, (self.mounttmp, self.testcollection))
1101 class MagicDirApiError(FuseMagicTest):
1103 api = mock.MagicMock()
1104 api.keep.block_cache = mock.MagicMock(cache_max=1)
1105 super(MagicDirApiError, self).setUp(api=api)
1106 api.collections().get().execute.side_effect = iter([
1107 Exception('API fail'),
1109 "manifest_text": self.test_manifest,
1110 "portable_data_hash": self.test_manifest_pdh,
1113 api.keep.get.side_effect = Exception('Keep fail')
1116 with mock.patch('arvados_fuse.fresh.FreshBase._poll_time', new_callable=mock.PropertyMock, return_value=60) as mock_poll_time:
1117 self.make_mount(fuse.MagicDirectory)
1119 self.operations.inodes.inode_cache.cap = 1
1120 self.operations.inodes.inode_cache.min_entries = 2
1122 with self.assertRaises(OSError):
1123 llfuse.listdir(os.path.join(self.mounttmp, self.testcollection))
1125 llfuse.listdir(os.path.join(self.mounttmp, self.testcollection))
1128 class SanitizeFilenameTest(MountTestBase):
1129 def test_sanitize_filename(self):
1130 pdir = fuse.ProjectDirectory(
1131 1, fuse.Inodes(None), self.api, 0, False, None,
1132 project_object=self.api.users().current().execute(),
1152 for f in acceptable:
1153 self.assertEqual(f, pdir.sanitize_filename(f))
1154 for f in unacceptable:
1155 self.assertNotEqual(f, pdir.sanitize_filename(f))
1156 # The sanitized filename should be the same length, though.
1157 self.assertEqual(len(f), len(pdir.sanitize_filename(f)))
1159 self.assertEqual("_", pdir.sanitize_filename(""))
1160 self.assertEqual("_", pdir.sanitize_filename("."))
1161 self.assertEqual("__", pdir.sanitize_filename(".."))
1164 class FuseMagicTestPDHOnly(MountTestBase):
1165 def setUp(self, api=None):
1166 super(FuseMagicTestPDHOnly, self).setUp(api=api)
1168 cw = arvados.CollectionWriter()
1170 cw.start_new_file('thing1.txt')
1173 self.testcollection = cw.finish()
1174 self.test_manifest = cw.manifest_text()
1175 created = self.api.collections().create(body={"manifest_text":self.test_manifest}).execute()
1176 self.testcollectionuuid = str(created['uuid'])
1178 def verify_pdh_only(self, pdh_only=False, skip_pdh_only=False):
1179 if skip_pdh_only is True:
1180 self.make_mount(fuse.MagicDirectory) # in this case, the default by_id applies
1182 self.make_mount(fuse.MagicDirectory, pdh_only=pdh_only)
1184 mount_ls = llfuse.listdir(self.mounttmp)
1185 self.assertIn('README', mount_ls)
1186 self.assertFalse(any(arvados.util.keep_locator_pattern.match(fn) or
1187 arvados.util.uuid_pattern.match(fn)
1188 for fn in mount_ls),
1189 "new FUSE MagicDirectory lists Collection")
1191 # look up using pdh should succeed in all cases
1192 self.assertDirContents(self.testcollection, ['thing1.txt'])
1193 self.assertDirContents(os.path.join('by_id', self.testcollection),
1195 mount_ls = llfuse.listdir(self.mounttmp)
1196 self.assertIn('README', mount_ls)
1197 self.assertIn(self.testcollection, mount_ls)
1198 self.assertIn(self.testcollection,
1199 llfuse.listdir(os.path.join(self.mounttmp, 'by_id')))
1202 files[os.path.join(self.mounttmp, self.testcollection, 'thing1.txt')] = 'data 1'
1204 for k, v in viewitems(files):
1205 with open(os.path.join(self.mounttmp, k), 'rb') as f:
1206 self.assertEqual(v, f.read().decode())
1208 # look up using uuid should fail when pdh_only is set
1209 if pdh_only is True:
1210 with self.assertRaises(OSError):
1211 self.assertDirContents(os.path.join('by_id', self.testcollectionuuid),
1214 self.assertDirContents(os.path.join('by_id', self.testcollectionuuid),
1217 def test_with_pdh_only_true(self):
1218 self.verify_pdh_only(pdh_only=True)
1220 def test_with_pdh_only_false(self):
1221 self.verify_pdh_only(pdh_only=False)
1223 def test_with_default_by_id(self):
1224 self.verify_pdh_only(skip_pdh_only=True)
1227 class SlashSubstitutionTest(IntegrationTest):
1230 '--mount-home', 'zzz',
1235 super(SlashSubstitutionTest, self).setUp()
1237 self.api = arvados.safeapi.ThreadSafeApiCache(
1238 arvados.config.settings(),
1241 self.testcoll = self.api.collections().create(body={"name": "foo/bar/baz"}).execute()
1242 self.testcolleasy = self.api.collections().create(body={"name": "foo-bar-baz"}).execute()
1243 self.fusename = 'foo[SLASH]bar[SLASH]baz'
1245 @IntegrationTest.mount(argv=mnt_args)
1246 def test_slash_substitution_before_listing(self):
1247 self.pool_test(os.path.join(self.mnt, 'zzz'), self.fusename)
1248 self.checkContents()
1250 def _test_slash_substitution_before_listing(self, tmpdir, fusename):
1251 with open(os.path.join(tmpdir, 'foo-bar-baz', 'waz'), 'w') as f:
1253 with open(os.path.join(tmpdir, fusename, 'waz'), 'w') as f:
1256 @IntegrationTest.mount(argv=mnt_args)
1257 @mock.patch('arvados.util.get_config_once')
1258 def test_slash_substitution_after_listing(self, get_config_once):
1259 get_config_once.return_value = {"Collections": {"ForwardSlashNameSubstitution": "[SLASH]"}}
1260 self.pool_test(os.path.join(self.mnt, 'zzz'), self.fusename)
1261 self.checkContents()
1263 def _test_slash_substitution_after_listing(self, tmpdir, fusename):
1264 with open(os.path.join(tmpdir, 'foo-bar-baz', 'waz'), 'w') as f:
1267 with open(os.path.join(tmpdir, fusename, 'waz'), 'w') as f:
1270 def checkContents(self):
1271 self.assertRegexpMatches(self.api.collections().get(uuid=self.testcoll['uuid']).execute()['manifest_text'], ' acbd18db') # md5(foo)
1272 self.assertRegexpMatches(self.api.collections().get(uuid=self.testcolleasy['uuid']).execute()['manifest_text'], ' f561aaf6') # md5(xxx)
1274 @IntegrationTest.mount(argv=mnt_args)
1275 @mock.patch('arvados.util.get_config_once')
1276 def test_slash_substitution_conflict(self, get_config_once):
1277 self.testcollconflict = self.api.collections().create(body={"name": self.fusename}).execute()
1278 get_config_once.return_value = {"Collections": {"ForwardSlashNameSubstitution": "[SLASH]"}}
1279 self.pool_test(os.path.join(self.mnt, 'zzz'), self.fusename)
1280 self.assertRegexpMatches(self.api.collections().get(uuid=self.testcollconflict['uuid']).execute()['manifest_text'], ' acbd18db') # md5(foo)
1281 # foo/bar/baz collection unchanged, because it is masked by foo[SLASH]bar[SLASH]baz
1282 self.assertEqual(self.api.collections().get(uuid=self.testcoll['uuid']).execute()['manifest_text'], '')
1284 def _test_slash_substitution_conflict(self, tmpdir, fusename):
1285 with open(os.path.join(tmpdir, fusename, 'waz'), 'w') as f:
1288 class StorageClassesTest(IntegrationTest):
1291 '--mount-home', 'homedir',
1295 super(StorageClassesTest, self).setUp()
1296 self.api = arvados.safeapi.ThreadSafeApiCache(
1297 arvados.config.settings(),
1301 @IntegrationTest.mount(argv=mnt_args)
1302 def test_collection_default_storage_classes(self):
1303 coll_path = os.path.join(self.mnt, 'homedir', 'a_collection')
1304 self.api.collections().create(body={'name':'a_collection'}).execute()
1305 self.pool_test(coll_path)
1307 def _test_collection_default_storage_classes(self, coll):
1308 self.assertEqual(storage_classes_desired(coll), ['default'])
1310 @IntegrationTest.mount(argv=mnt_args+['--storage-classes', 'foo'])
1311 def test_collection_custom_storage_classes(self):
1312 coll_path = os.path.join(self.mnt, 'homedir', 'new_coll')
1314 self.pool_test(coll_path)
1316 def _test_collection_custom_storage_classes(self, coll):
1317 self.assertEqual(storage_classes_desired(coll), ['foo'])
1319 def _readonlyCollectionTestHelper(mounttmp):
1320 f = open(os.path.join(mounttmp, 'thing1.txt'), 'rt')
1321 # Testing that close() doesn't raise an error.
1324 class ReadonlyCollectionTest(MountTestBase):
1326 super(ReadonlyCollectionTest, self).setUp()
1327 cw = arvados.collection.Collection()
1328 with cw.open('thing1.txt', 'wt') as f:
1330 cw.save_new(owner_uuid=run_test_server.fixture("groups")["aproject"]["uuid"])
1331 self.testcollection = cw.api_response()
1334 settings = arvados.config.settings().copy()
1335 settings["ARVADOS_API_TOKEN"] = run_test_server.fixture("api_client_authorizations")["project_viewer"]["api_token"]
1336 self.api = arvados.safeapi.ThreadSafeApiCache(settings, version='v1')
1337 self.make_mount(fuse.CollectionDirectory, collection_record=self.testcollection, enable_write=False)
1339 self.pool.apply(_readonlyCollectionTestHelper, (self.mounttmp,))
1342 @parameterized.parameterized_class([
1343 {'root_class': fusedir.ProjectDirectory, 'root_kwargs': {
1344 'project_object': run_test_server.fixture('users')['admin'],
1346 {'root_class': fusedir.ProjectDirectory, 'root_kwargs': {
1347 'project_object': run_test_server.fixture('groups')['public'],
1350 class UnsupportedCreateTest(MountTestBase):
1356 if 'prefs' in self.root_kwargs.get('project_object', ()):
1357 self.root_kwargs['project_object']['prefs'] = {}
1358 self.make_mount(self.root_class, **self.root_kwargs)
1359 # Make sure the directory knows about its top-level ents.
1360 os.listdir(self.mounttmp)
1362 def test_create(self):
1363 test_path = Path(self.mounttmp, 'test_create')
1364 with self.assertRaises(OSError) as exc_check:
1365 with test_path.open('w'):
1367 self.assertEqual(exc_check.exception.errno, errno.ENOTSUP)
1370 # FIXME: IMO, for consistency with the "create inside a project" case,
1371 # these operations should also return ENOTSUP instead of EPERM.
1372 # Right now they're returning EPERM because the clasess' writable() method
1373 # usually returns False, and the Operations class transforms that accordingly.
1374 # However, for cases where the mount will never be writable, I think ENOTSUP
1375 # is a clearer error: it lets the user know they can't fix the problem by
1376 # adding permissions in Arvados, etc.
1377 @parameterized.parameterized_class([
1378 {'root_class': fusedir.MagicDirectory,
1379 'preset_dir': 'by_id',
1380 'preset_file': 'README',
1383 {'root_class': fusedir.SharedDirectory,
1385 'exclude': run_test_server.fixture('users')['admin']['uuid'],
1387 'preset_dir': 'Active User',
1390 {'root_class': fusedir.TagDirectory,
1392 'tag': run_test_server.fixture('links')['foo_collection_tag']['name'],
1394 'preset_dir': run_test_server.fixture('collections')['foo_collection_in_aproject']['uuid'],
1397 {'root_class': fusedir.TagsDirectory,
1398 'preset_dir': run_test_server.fixture('links')['foo_collection_tag']['name'],
1401 class UnsupportedOperationsTest(UnsupportedCreateTest):
1405 def test_create(self):
1406 test_path = Path(self.mounttmp, 'test_create')
1407 with self.assertRaises(OSError) as exc_check:
1408 with test_path.open('w'):
1410 self.assertEqual(exc_check.exception.errno, errno.EPERM)
1412 def test_mkdir(self):
1413 test_path = Path(self.mounttmp, 'test_mkdir')
1414 with self.assertRaises(OSError) as exc_check:
1416 self.assertEqual(exc_check.exception.errno, errno.EPERM)
1418 def test_rename(self):
1419 src_name = self.preset_dir or self.preset_file
1420 if src_name is None:
1422 test_src = Path(self.mounttmp, src_name)
1423 test_dst = test_src.with_name('test_dst')
1424 with self.assertRaises(OSError) as exc_check:
1425 test_src.rename(test_dst)
1426 self.assertEqual(exc_check.exception.errno, errno.EPERM)
1428 def test_rmdir(self):
1429 if self.preset_dir is None:
1431 test_path = Path(self.mounttmp, self.preset_dir)
1432 with self.assertRaises(OSError) as exc_check:
1434 self.assertEqual(exc_check.exception.errno, errno.EPERM)
1436 def test_unlink(self):
1437 if self.preset_file is None:
1439 test_path = Path(self.mounttmp, self.preset_file)
1440 with self.assertRaises(OSError) as exc_check:
1442 self.assertEqual(exc_check.exception.errno, errno.EPERM)