3 import arvados_fuse as fuse
16 import multiprocessing
17 import run_test_server
21 from mount_test_base import MountTestBase
23 logger = logging.getLogger('arvados.arv-mount')
26 class FuseMountTest(MountTestBase):
28 super(FuseMountTest, self).setUp()
30 cw = arvados.CollectionWriter()
32 cw.start_new_file('thing1.txt')
34 cw.start_new_file('thing2.txt')
37 cw.start_new_stream('dir1')
38 cw.start_new_file('thing3.txt')
40 cw.start_new_file('thing4.txt')
43 cw.start_new_stream('dir2')
44 cw.start_new_file('thing5.txt')
46 cw.start_new_file('thing6.txt')
49 cw.start_new_stream('dir2/dir3')
50 cw.start_new_file('thing7.txt')
53 cw.start_new_file('thing8.txt')
56 cw.start_new_stream('edgecases')
57 for f in ":/.../-/*/\x01\\/ ".split("/"):
61 for f in ":/.../-/*/\x01\\/ ".split("/"):
62 cw.start_new_stream('edgecases/dirs/' + f)
63 cw.start_new_file('x/x')
66 self.testcollection = cw.finish()
67 self.api.collections().create(body={"manifest_text":cw.manifest_text()}).execute()
70 self.make_mount(fuse.CollectionDirectory, collection_record=self.testcollection)
72 self.assertDirContents(None, ['thing1.txt', 'thing2.txt',
73 'edgecases', 'dir1', 'dir2'])
74 self.assertDirContents('dir1', ['thing3.txt', 'thing4.txt'])
75 self.assertDirContents('dir2', ['thing5.txt', 'thing6.txt', 'dir3'])
76 self.assertDirContents('dir2/dir3', ['thing7.txt', 'thing8.txt'])
77 self.assertDirContents('edgecases',
78 "dirs/:/.../-/*/\x01\\/ ".split("/"))
79 self.assertDirContents('edgecases/dirs',
80 ":/.../-/*/\x01\\/ ".split("/"))
82 files = {'thing1.txt': 'data 1',
83 'thing2.txt': 'data 2',
84 'dir1/thing3.txt': 'data 3',
85 'dir1/thing4.txt': 'data 4',
86 'dir2/thing5.txt': 'data 5',
87 'dir2/thing6.txt': 'data 6',
88 'dir2/dir3/thing7.txt': 'data 7',
89 'dir2/dir3/thing8.txt': 'data 8'}
91 for k, v in files.items():
92 with open(os.path.join(self.mounttmp, k)) as f:
93 self.assertEqual(v, f.read())
96 class FuseNoAPITest(MountTestBase):
98 super(FuseNoAPITest, self).setUp()
99 keep = arvados.keep.KeepClient(local_store=self.keeptmp)
100 self.file_data = "API-free text\n"
101 self.file_loc = keep.put(self.file_data)
102 self.coll_loc = keep.put(". {} 0:{}:api-free.txt\n".format(
103 self.file_loc, len(self.file_data)))
106 self.make_mount(fuse.MagicDirectory)
107 self.assertDirContents(self.coll_loc, ['api-free.txt'])
108 with open(os.path.join(
109 self.mounttmp, self.coll_loc, 'api-free.txt')) as keep_file:
110 actual = keep_file.read(-1)
111 self.assertEqual(self.file_data, actual)
114 class FuseMagicTest(MountTestBase):
115 def setUp(self, api=None):
116 super(FuseMagicTest, self).setUp(api=api)
118 cw = arvados.CollectionWriter()
120 cw.start_new_file('thing1.txt')
123 self.testcollection = cw.finish()
124 self.test_manifest = cw.manifest_text()
125 self.api.collections().create(body={"manifest_text":self.test_manifest}).execute()
128 self.make_mount(fuse.MagicDirectory)
130 mount_ls = llfuse.listdir(self.mounttmp)
131 self.assertIn('README', mount_ls)
132 self.assertFalse(any(arvados.util.keep_locator_pattern.match(fn) or
133 arvados.util.uuid_pattern.match(fn)
135 "new FUSE MagicDirectory lists Collection")
136 self.assertDirContents(self.testcollection, ['thing1.txt'])
137 self.assertDirContents(os.path.join('by_id', self.testcollection),
139 mount_ls = llfuse.listdir(self.mounttmp)
140 self.assertIn('README', mount_ls)
141 self.assertIn(self.testcollection, mount_ls)
142 self.assertIn(self.testcollection,
143 llfuse.listdir(os.path.join(self.mounttmp, 'by_id')))
146 files[os.path.join(self.mounttmp, self.testcollection, 'thing1.txt')] = 'data 1'
148 for k, v in files.items():
149 with open(os.path.join(self.mounttmp, k)) as f:
150 self.assertEqual(v, f.read())
153 class FuseTagsTest(MountTestBase):
155 self.make_mount(fuse.TagsDirectory)
157 d1 = llfuse.listdir(self.mounttmp)
159 self.assertEqual(['foo_tag'], d1)
161 d2 = llfuse.listdir(os.path.join(self.mounttmp, 'foo_tag'))
163 self.assertEqual(['zzzzz-4zz18-fy296fx3hot09f7'], d2)
165 d3 = llfuse.listdir(os.path.join(self.mounttmp, 'foo_tag', 'zzzzz-4zz18-fy296fx3hot09f7'))
167 self.assertEqual(['foo'], d3)
170 class FuseTagsUpdateTest(MountTestBase):
171 def tag_collection(self, coll_uuid, tag_name):
172 return self.api.links().create(
173 body={'link': {'head_uuid': coll_uuid,
179 self.make_mount(fuse.TagsDirectory, poll_time=1)
181 self.assertIn('foo_tag', llfuse.listdir(self.mounttmp))
183 bar_uuid = run_test_server.fixture('collections')['bar_file']['uuid']
184 self.tag_collection(bar_uuid, 'fuse_test_tag')
186 self.assertIn('fuse_test_tag', llfuse.listdir(self.mounttmp))
187 self.assertDirContents('fuse_test_tag', [bar_uuid])
189 baz_uuid = run_test_server.fixture('collections')['baz_file']['uuid']
190 l = self.tag_collection(baz_uuid, 'fuse_test_tag')
192 self.assertDirContents('fuse_test_tag', [bar_uuid, baz_uuid])
194 self.api.links().delete(uuid=l['uuid']).execute()
196 self.assertDirContents('fuse_test_tag', [bar_uuid])
199 class FuseSharedTest(MountTestBase):
201 self.make_mount(fuse.SharedDirectory,
202 exclude=self.api.users().current().execute()['uuid'])
204 # shared_dirs is a list of the directories exposed
205 # by fuse.SharedDirectory (i.e. any object visible
206 # to the current user)
207 shared_dirs = llfuse.listdir(self.mounttmp)
209 self.assertIn('FUSE User', shared_dirs)
211 # fuse_user_objs is a list of the objects owned by the FUSE
212 # test user (which present as files in the 'FUSE User'
214 fuse_user_objs = llfuse.listdir(os.path.join(self.mounttmp, 'FUSE User'))
215 fuse_user_objs.sort()
216 self.assertEqual(['FUSE Test Project', # project owned by user
217 'collection #1 owned by FUSE', # collection owned by user
218 'collection #2 owned by FUSE', # collection owned by user
219 'pipeline instance owned by FUSE.pipelineInstance', # pipeline instance owned by user
222 # test_proj_files is a list of the files in the FUSE Test Project.
223 test_proj_files = llfuse.listdir(os.path.join(self.mounttmp, 'FUSE User', 'FUSE Test Project'))
224 test_proj_files.sort()
225 self.assertEqual(['collection in FUSE project',
226 'pipeline instance in FUSE project.pipelineInstance',
227 'pipeline template in FUSE project.pipelineTemplate'
230 # Double check that we can open and read objects in this folder as a file,
231 # and that its contents are what we expect.
232 pipeline_template_path = os.path.join(
236 'pipeline template in FUSE project.pipelineTemplate')
237 with open(pipeline_template_path) as f:
239 self.assertEqual("pipeline template in FUSE project", j['name'])
241 # check mtime on template
242 st = os.stat(pipeline_template_path)
243 self.assertEqual(st.st_mtime, 1397493304)
245 # check mtime on collection
246 st = os.stat(os.path.join(
249 'collection #1 owned by FUSE'))
250 self.assertEqual(st.st_mtime, 1391448174)
253 class FuseHomeTest(MountTestBase):
255 self.make_mount(fuse.ProjectDirectory,
256 project_object=self.api.users().current().execute())
258 d1 = llfuse.listdir(self.mounttmp)
259 self.assertIn('Unrestricted public data', d1)
261 d2 = llfuse.listdir(os.path.join(self.mounttmp, 'Unrestricted public data'))
262 public_project = run_test_server.fixture('groups')[
263 'anonymously_accessible_project']
266 for name, item in run_test_server.fixture('collections').iteritems():
267 if 'name' not in item:
269 elif item['owner_uuid'] == public_project['uuid']:
270 self.assertIn(item['name'], d2)
273 # Artificial assumption here: there is no public
274 # collection fixture with the same name as a
275 # non-public collection.
276 self.assertNotIn(item['name'], d2)
278 self.assertNotEqual(0, found_in)
279 self.assertNotEqual(0, found_not_in)
281 d3 = llfuse.listdir(os.path.join(self.mounttmp, 'Unrestricted public data', 'GNU General Public License, version 3'))
282 self.assertEqual(["GNU_General_Public_License,_version_3.pdf"], d3)
285 def fuseModifyFileTestHelperReadStartContents(mounttmp):
286 class Test(unittest.TestCase):
288 d1 = llfuse.listdir(mounttmp)
289 self.assertEqual(["file1.txt"], d1)
290 with open(os.path.join(mounttmp, "file1.txt")) as f:
291 self.assertEqual("blub", f.read())
294 def fuseModifyFileTestHelperReadEndContents(mounttmp):
295 class Test(unittest.TestCase):
297 d1 = llfuse.listdir(mounttmp)
298 self.assertEqual(["file1.txt"], d1)
299 with open(os.path.join(mounttmp, "file1.txt")) as f:
300 self.assertEqual("plnp", f.read())
303 class FuseModifyFileTest(MountTestBase):
305 collection = arvados.collection.Collection(api_client=self.api)
306 with collection.open("file1.txt", "w") as f:
309 collection.save_new()
311 m = self.make_mount(fuse.CollectionDirectory)
313 m.new_collection(collection.api_response(), collection)
315 self.pool.apply(fuseModifyFileTestHelperReadStartContents, (self.mounttmp,))
317 with collection.open("file1.txt", "w") as f:
320 self.pool.apply(fuseModifyFileTestHelperReadEndContents, (self.mounttmp,))
323 class FuseAddFileToCollectionTest(MountTestBase):
325 collection = arvados.collection.Collection(api_client=self.api)
326 with collection.open("file1.txt", "w") as f:
329 collection.save_new()
331 m = self.make_mount(fuse.CollectionDirectory)
333 m.new_collection(collection.api_response(), collection)
335 d1 = llfuse.listdir(self.mounttmp)
336 self.assertEqual(["file1.txt"], d1)
338 with collection.open("file2.txt", "w") as f:
341 d1 = llfuse.listdir(self.mounttmp)
342 self.assertEqual(["file1.txt", "file2.txt"], sorted(d1))
345 class FuseRemoveFileFromCollectionTest(MountTestBase):
347 collection = arvados.collection.Collection(api_client=self.api)
348 with collection.open("file1.txt", "w") as f:
351 with collection.open("file2.txt", "w") as f:
354 collection.save_new()
356 m = self.make_mount(fuse.CollectionDirectory)
358 m.new_collection(collection.api_response(), collection)
360 d1 = llfuse.listdir(self.mounttmp)
361 self.assertEqual(["file1.txt", "file2.txt"], sorted(d1))
363 collection.remove("file2.txt")
365 d1 = llfuse.listdir(self.mounttmp)
366 self.assertEqual(["file1.txt"], d1)
369 def fuseCreateFileTestHelper(mounttmp):
370 class Test(unittest.TestCase):
372 with open(os.path.join(mounttmp, "file1.txt"), "w") as f:
376 class FuseCreateFileTest(MountTestBase):
378 collection = arvados.collection.Collection(api_client=self.api)
379 collection.save_new()
381 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
382 self.assertEqual(collection2["manifest_text"], "")
384 collection.save_new()
386 m = self.make_mount(fuse.CollectionDirectory)
388 m.new_collection(collection.api_response(), collection)
389 self.assertTrue(m.writable())
391 self.assertNotIn("file1.txt", collection)
393 self.pool.apply(fuseCreateFileTestHelper, (self.mounttmp,))
395 self.assertIn("file1.txt", collection)
397 d1 = llfuse.listdir(self.mounttmp)
398 self.assertEqual(["file1.txt"], d1)
400 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
401 self.assertRegexpMatches(collection2["manifest_text"],
402 r'\. d41d8cd98f00b204e9800998ecf8427e\+0\+A\S+ 0:0:file1\.txt$')
405 def fuseWriteFileTestHelperWriteFile(mounttmp):
406 class Test(unittest.TestCase):
408 with open(os.path.join(mounttmp, "file1.txt"), "w") as f:
409 f.write("Hello world!")
412 def fuseWriteFileTestHelperReadFile(mounttmp):
413 class Test(unittest.TestCase):
415 with open(os.path.join(mounttmp, "file1.txt"), "r") as f:
416 self.assertEqual(f.read(), "Hello world!")
419 class FuseWriteFileTest(MountTestBase):
421 collection = arvados.collection.Collection(api_client=self.api)
422 collection.save_new()
424 m = self.make_mount(fuse.CollectionDirectory)
426 m.new_collection(collection.api_response(), collection)
427 self.assertTrue(m.writable())
429 self.assertNotIn("file1.txt", collection)
431 self.assertEqual(0, self.operations.write_counter.get())
432 self.pool.apply(fuseWriteFileTestHelperWriteFile, (self.mounttmp,))
433 self.assertEqual(12, self.operations.write_counter.get())
435 with collection.open("file1.txt") as f:
436 self.assertEqual(f.read(), "Hello world!")
438 self.assertEqual(0, self.operations.read_counter.get())
439 self.pool.apply(fuseWriteFileTestHelperReadFile, (self.mounttmp,))
440 self.assertEqual(12, self.operations.read_counter.get())
442 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
443 self.assertRegexpMatches(collection2["manifest_text"],
444 r'\. 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
447 def fuseUpdateFileTestHelper(mounttmp):
448 class Test(unittest.TestCase):
450 with open(os.path.join(mounttmp, "file1.txt"), "w") as f:
451 f.write("Hello world!")
453 with open(os.path.join(mounttmp, "file1.txt"), "r+") as f:
455 self.assertEqual(fr, "Hello world!")
457 f.write("Hola mundo!")
460 self.assertEqual(fr, "Hola mundo!!")
462 with open(os.path.join(mounttmp, "file1.txt"), "r") as f:
463 self.assertEqual(f.read(), "Hola mundo!!")
467 class FuseUpdateFileTest(MountTestBase):
469 collection = arvados.collection.Collection(api_client=self.api)
470 collection.save_new()
472 m = self.make_mount(fuse.CollectionDirectory)
474 m.new_collection(collection.api_response(), collection)
475 self.assertTrue(m.writable())
477 # See note in MountTestBase.setUp
478 self.pool.apply(fuseUpdateFileTestHelper, (self.mounttmp,))
480 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
481 self.assertRegexpMatches(collection2["manifest_text"],
482 r'\. daaef200ebb921e011e3ae922dd3266b\+11\+A\S+ 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:11:file1\.txt 22:1:file1\.txt$')
485 def fuseMkdirTestHelper(mounttmp):
486 class Test(unittest.TestCase):
488 with self.assertRaises(IOError):
489 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
490 f.write("Hello world!")
492 os.mkdir(os.path.join(mounttmp, "testdir"))
494 with self.assertRaises(OSError):
495 os.mkdir(os.path.join(mounttmp, "testdir"))
497 d1 = llfuse.listdir(mounttmp)
498 self.assertEqual(["testdir"], d1)
500 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
501 f.write("Hello world!")
503 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
504 self.assertEqual(["file1.txt"], d1)
508 class FuseMkdirTest(MountTestBase):
510 collection = arvados.collection.Collection(api_client=self.api)
511 collection.save_new()
513 m = self.make_mount(fuse.CollectionDirectory)
515 m.new_collection(collection.api_response(), collection)
516 self.assertTrue(m.writable())
518 self.pool.apply(fuseMkdirTestHelper, (self.mounttmp,))
520 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
521 self.assertRegexpMatches(collection2["manifest_text"],
522 r'\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
525 def fuseRmTestHelperWriteFile(mounttmp):
526 class Test(unittest.TestCase):
528 os.mkdir(os.path.join(mounttmp, "testdir"))
530 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
531 f.write("Hello world!")
535 def fuseRmTestHelperDeleteFile(mounttmp):
536 class Test(unittest.TestCase):
538 # Can't delete because it's not empty
539 with self.assertRaises(OSError):
540 os.rmdir(os.path.join(mounttmp, "testdir"))
542 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
543 self.assertEqual(["file1.txt"], d1)
546 os.remove(os.path.join(mounttmp, "testdir", "file1.txt"))
548 # Make sure it's empty
549 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
550 self.assertEqual([], d1)
552 # Try to delete it again
553 with self.assertRaises(OSError):
554 os.remove(os.path.join(mounttmp, "testdir", "file1.txt"))
558 def fuseRmTestHelperRmdir(mounttmp):
559 class Test(unittest.TestCase):
561 # Should be able to delete now that it is empty
562 os.rmdir(os.path.join(mounttmp, "testdir"))
564 # Make sure it's empty
565 d1 = llfuse.listdir(os.path.join(mounttmp))
566 self.assertEqual([], d1)
568 # Try to delete it again
569 with self.assertRaises(OSError):
570 os.rmdir(os.path.join(mounttmp, "testdir"))
574 class FuseRmTest(MountTestBase):
576 collection = arvados.collection.Collection(api_client=self.api)
577 collection.save_new()
579 m = self.make_mount(fuse.CollectionDirectory)
581 m.new_collection(collection.api_response(), collection)
582 self.assertTrue(m.writable())
584 self.pool.apply(fuseRmTestHelperWriteFile, (self.mounttmp,))
587 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
588 self.assertRegexpMatches(collection2["manifest_text"],
589 r'\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
590 self.pool.apply(fuseRmTestHelperDeleteFile, (self.mounttmp,))
592 # Can't have empty directories :-( so manifest will be empty.
593 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
594 self.assertEqual(collection2["manifest_text"], "")
596 self.pool.apply(fuseRmTestHelperRmdir, (self.mounttmp,))
598 # manifest should be empty now.
599 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
600 self.assertEqual(collection2["manifest_text"], "")
603 def fuseMvFileTestHelperWriteFile(mounttmp):
604 class Test(unittest.TestCase):
606 os.mkdir(os.path.join(mounttmp, "testdir"))
608 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
609 f.write("Hello world!")
613 def fuseMvFileTestHelperMoveFile(mounttmp):
614 class Test(unittest.TestCase):
616 d1 = llfuse.listdir(os.path.join(mounttmp))
617 self.assertEqual(["testdir"], d1)
618 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
619 self.assertEqual(["file1.txt"], d1)
621 os.rename(os.path.join(mounttmp, "testdir", "file1.txt"), os.path.join(mounttmp, "file1.txt"))
623 d1 = llfuse.listdir(os.path.join(mounttmp))
624 self.assertEqual(["file1.txt", "testdir"], sorted(d1))
625 d1 = llfuse.listdir(os.path.join(mounttmp, "testdir"))
626 self.assertEqual([], d1)
630 class FuseMvFileTest(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(fuseMvFileTestHelperWriteFile, (self.mounttmp,))
643 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
644 self.assertRegexpMatches(collection2["manifest_text"],
645 r'\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
647 self.pool.apply(fuseMvFileTestHelperMoveFile, (self.mounttmp,))
649 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
650 self.assertRegexpMatches(collection2["manifest_text"],
651 r'\. 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
654 def fuseRenameTestHelper(mounttmp):
655 class Test(unittest.TestCase):
657 os.mkdir(os.path.join(mounttmp, "testdir"))
659 with open(os.path.join(mounttmp, "testdir", "file1.txt"), "w") as f:
660 f.write("Hello world!")
664 class FuseRenameTest(MountTestBase):
666 collection = arvados.collection.Collection(api_client=self.api)
667 collection.save_new()
669 m = self.make_mount(fuse.CollectionDirectory)
671 m.new_collection(collection.api_response(), collection)
672 self.assertTrue(m.writable())
674 self.pool.apply(fuseRenameTestHelper, (self.mounttmp,))
677 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
678 self.assertRegexpMatches(collection2["manifest_text"],
679 r'\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
681 d1 = llfuse.listdir(os.path.join(self.mounttmp))
682 self.assertEqual(["testdir"], d1)
683 d1 = llfuse.listdir(os.path.join(self.mounttmp, "testdir"))
684 self.assertEqual(["file1.txt"], d1)
686 os.rename(os.path.join(self.mounttmp, "testdir"), os.path.join(self.mounttmp, "testdir2"))
688 d1 = llfuse.listdir(os.path.join(self.mounttmp))
689 self.assertEqual(["testdir2"], sorted(d1))
690 d1 = llfuse.listdir(os.path.join(self.mounttmp, "testdir2"))
691 self.assertEqual(["file1.txt"], d1)
693 collection2 = self.api.collections().get(uuid=collection.manifest_locator()).execute()
694 self.assertRegexpMatches(collection2["manifest_text"],
695 r'\./testdir2 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$')
698 class FuseUpdateFromEventTest(MountTestBase):
700 collection = arvados.collection.Collection(api_client=self.api)
701 collection.save_new()
703 m = self.make_mount(fuse.CollectionDirectory)
705 m.new_collection(collection.api_response(), collection)
707 self.operations.listen_for_events()
709 d1 = llfuse.listdir(os.path.join(self.mounttmp))
710 self.assertEqual([], sorted(d1))
712 with arvados.collection.Collection(collection.manifest_locator(), api_client=self.api) as collection2:
713 with collection2.open("file1.txt", "w") as f:
718 # should show up via event bus notify
720 d1 = llfuse.listdir(os.path.join(self.mounttmp))
721 self.assertEqual(["file1.txt"], sorted(d1))
724 def fuseFileConflictTestHelper(mounttmp):
725 class Test(unittest.TestCase):
727 with open(os.path.join(mounttmp, "file1.txt"), "w") as f:
730 d1 = sorted(llfuse.listdir(os.path.join(mounttmp)))
731 self.assertEqual(len(d1), 2)
733 with open(os.path.join(mounttmp, "file1.txt"), "r") as f:
734 self.assertEqual(f.read(), "bar")
736 self.assertRegexpMatches(d1[1],
737 r'file1\.txt~\d\d\d\d\d\d\d\d-\d\d\d\d\d\d~conflict~')
739 with open(os.path.join(mounttmp, d1[1]), "r") as f:
740 self.assertEqual(f.read(), "foo")
744 class FuseFileConflictTest(MountTestBase):
746 collection = arvados.collection.Collection(api_client=self.api)
747 collection.save_new()
749 m = self.make_mount(fuse.CollectionDirectory)
751 m.new_collection(collection.api_response(), collection)
753 d1 = llfuse.listdir(os.path.join(self.mounttmp))
754 self.assertEqual([], sorted(d1))
756 with arvados.collection.Collection(collection.manifest_locator(), api_client=self.api) as collection2:
757 with collection2.open("file1.txt", "w") as f:
760 # See note in MountTestBase.setUp
761 self.pool.apply(fuseFileConflictTestHelper, (self.mounttmp,))
764 def fuseUnlinkOpenFileTest(mounttmp):
765 class Test(unittest.TestCase):
767 with open(os.path.join(mounttmp, "file1.txt"), "w+") as f:
770 d1 = llfuse.listdir(os.path.join(mounttmp))
771 self.assertEqual(["file1.txt"], sorted(d1))
773 os.remove(os.path.join(mounttmp, "file1.txt"))
775 d1 = llfuse.listdir(os.path.join(mounttmp))
776 self.assertEqual([], sorted(d1))
779 self.assertEqual(f.read(), "foo")
783 self.assertEqual(f.read(), "foobar")
787 class FuseUnlinkOpenFileTest(MountTestBase):
789 collection = arvados.collection.Collection(api_client=self.api)
790 collection.save_new()
792 m = self.make_mount(fuse.CollectionDirectory)
794 m.new_collection(collection.api_response(), collection)
796 # See note in MountTestBase.setUp
797 self.pool.apply(fuseUnlinkOpenFileTest, (self.mounttmp,))
799 self.assertEqual(collection.manifest_text(), "")
802 def fuseMvFileBetweenCollectionsTest1(mounttmp, uuid1, uuid2):
803 class Test(unittest.TestCase):
805 with open(os.path.join(mounttmp, uuid1, "file1.txt"), "w") as f:
806 f.write("Hello world!")
808 d1 = os.listdir(os.path.join(mounttmp, uuid1))
809 self.assertEqual(["file1.txt"], sorted(d1))
810 d1 = os.listdir(os.path.join(mounttmp, uuid2))
811 self.assertEqual([], sorted(d1))
815 def fuseMvFileBetweenCollectionsTest2(mounttmp, uuid1, uuid2):
816 class Test(unittest.TestCase):
818 os.rename(os.path.join(mounttmp, uuid1, "file1.txt"), os.path.join(mounttmp, uuid2, "file2.txt"))
820 d1 = os.listdir(os.path.join(mounttmp, uuid1))
821 self.assertEqual([], sorted(d1))
822 d1 = os.listdir(os.path.join(mounttmp, uuid2))
823 self.assertEqual(["file2.txt"], sorted(d1))
827 class FuseMvFileBetweenCollectionsTest(MountTestBase):
829 collection1 = arvados.collection.Collection(api_client=self.api)
830 collection1.save_new()
832 collection2 = arvados.collection.Collection(api_client=self.api)
833 collection2.save_new()
835 m = self.make_mount(fuse.MagicDirectory)
837 # See note in MountTestBase.setUp
838 self.pool.apply(fuseMvFileBetweenCollectionsTest1, (self.mounttmp,
839 collection1.manifest_locator(),
840 collection2.manifest_locator()))
845 self.assertRegexpMatches(collection1.manifest_text(), r"\. 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$")
846 self.assertEqual(collection2.manifest_text(), "")
848 self.pool.apply(fuseMvFileBetweenCollectionsTest2, (self.mounttmp,
849 collection1.manifest_locator(),
850 collection2.manifest_locator()))
855 self.assertEqual(collection1.manifest_text(), "")
856 self.assertRegexpMatches(collection2.manifest_text(), r"\. 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file2\.txt$")
858 collection1.stop_threads()
859 collection2.stop_threads()
862 def fuseMvDirBetweenCollectionsTest1(mounttmp, uuid1, uuid2):
863 class Test(unittest.TestCase):
865 os.mkdir(os.path.join(mounttmp, uuid1, "testdir"))
866 with open(os.path.join(mounttmp, uuid1, "testdir", "file1.txt"), "w") as f:
867 f.write("Hello world!")
869 d1 = os.listdir(os.path.join(mounttmp, uuid1))
870 self.assertEqual(["testdir"], sorted(d1))
871 d1 = os.listdir(os.path.join(mounttmp, uuid1, "testdir"))
872 self.assertEqual(["file1.txt"], sorted(d1))
874 d1 = os.listdir(os.path.join(mounttmp, uuid2))
875 self.assertEqual([], sorted(d1))
880 def fuseMvDirBetweenCollectionsTest2(mounttmp, uuid1, uuid2):
881 class Test(unittest.TestCase):
883 os.rename(os.path.join(mounttmp, uuid1, "testdir"), os.path.join(mounttmp, uuid2, "testdir2"))
885 d1 = os.listdir(os.path.join(mounttmp, uuid1))
886 self.assertEqual([], sorted(d1))
888 d1 = os.listdir(os.path.join(mounttmp, uuid2))
889 self.assertEqual(["testdir2"], sorted(d1))
890 d1 = os.listdir(os.path.join(mounttmp, uuid2, "testdir2"))
891 self.assertEqual(["file1.txt"], sorted(d1))
893 with open(os.path.join(mounttmp, uuid2, "testdir2", "file1.txt"), "r") as f:
894 self.assertEqual(f.read(), "Hello world!")
898 class FuseMvDirBetweenCollectionsTest(MountTestBase):
900 collection1 = arvados.collection.Collection(api_client=self.api)
901 collection1.save_new()
903 collection2 = arvados.collection.Collection(api_client=self.api)
904 collection2.save_new()
906 m = self.make_mount(fuse.MagicDirectory)
908 # See note in MountTestBase.setUp
909 self.pool.apply(fuseMvDirBetweenCollectionsTest1, (self.mounttmp,
910 collection1.manifest_locator(),
911 collection2.manifest_locator()))
916 self.assertRegexpMatches(collection1.manifest_text(), r"\./testdir 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$")
917 self.assertEqual(collection2.manifest_text(), "")
919 self.pool.apply(fuseMvDirBetweenCollectionsTest2, (self.mounttmp,
920 collection1.manifest_locator(),
921 collection2.manifest_locator()))
926 self.assertEqual(collection1.manifest_text(), "")
927 self.assertRegexpMatches(collection2.manifest_text(), r"\./testdir2 86fb269d190d2c85f6e0468ceca42a20\+12\+A\S+ 0:12:file1\.txt$")
929 collection1.stop_threads()
930 collection2.stop_threads()
932 def fuseProjectMkdirTestHelper1(mounttmp):
933 class Test(unittest.TestCase):
935 os.mkdir(os.path.join(mounttmp, "testcollection"))
936 with self.assertRaises(OSError):
937 os.mkdir(os.path.join(mounttmp, "testcollection"))
940 def fuseProjectMkdirTestHelper2(mounttmp):
941 class Test(unittest.TestCase):
943 with open(os.path.join(mounttmp, "testcollection", "file1.txt"), "w") as f:
944 f.write("Hello world!")
945 with self.assertRaises(OSError):
946 os.rmdir(os.path.join(mounttmp, "testcollection"))
947 os.remove(os.path.join(mounttmp, "testcollection", "file1.txt"))
948 with self.assertRaises(OSError):
949 os.remove(os.path.join(mounttmp, "testcollection"))
950 os.rmdir(os.path.join(mounttmp, "testcollection"))
953 class FuseProjectMkdirRmdirTest(MountTestBase):
955 self.make_mount(fuse.ProjectDirectory,
956 project_object=self.api.users().current().execute())
958 d1 = llfuse.listdir(self.mounttmp)
959 self.assertNotIn('testcollection', d1)
961 self.pool.apply(fuseProjectMkdirTestHelper1, (self.mounttmp,))
963 d1 = llfuse.listdir(self.mounttmp)
964 self.assertIn('testcollection', d1)
966 self.pool.apply(fuseProjectMkdirTestHelper2, (self.mounttmp,))
968 d1 = llfuse.listdir(self.mounttmp)
969 self.assertNotIn('testcollection', d1)
972 def fuseProjectMvTestHelper1(mounttmp):
973 class Test(unittest.TestCase):
975 d1 = llfuse.listdir(mounttmp)
976 self.assertNotIn('testcollection', d1)
978 os.mkdir(os.path.join(mounttmp, "testcollection"))
980 d1 = llfuse.listdir(mounttmp)
981 self.assertIn('testcollection', d1)
983 with self.assertRaises(OSError):
984 os.rename(os.path.join(mounttmp, "testcollection"), os.path.join(mounttmp, 'Unrestricted public data'))
986 os.rename(os.path.join(mounttmp, "testcollection"), os.path.join(mounttmp, 'Unrestricted public data', 'testcollection'))
988 d1 = llfuse.listdir(mounttmp)
989 self.assertNotIn('testcollection', d1)
991 d1 = llfuse.listdir(os.path.join(mounttmp, 'Unrestricted public data'))
992 self.assertIn('testcollection', d1)
996 class FuseProjectMvTest(MountTestBase):
998 self.make_mount(fuse.ProjectDirectory,
999 project_object=self.api.users().current().execute())
1001 self.pool.apply(fuseProjectMvTestHelper1, (self.mounttmp,))
1004 def fuseFsyncTestHelper(mounttmp, k):
1005 class Test(unittest.TestCase):
1007 fd = os.open(os.path.join(mounttmp, k), os.O_RDONLY)
1013 class FuseFsyncTest(FuseMagicTest):
1015 self.make_mount(fuse.MagicDirectory)
1016 self.pool.apply(fuseFsyncTestHelper, (self.mounttmp, self.testcollection))
1019 class MagicDirApiError(FuseMagicTest):
1021 api = mock.MagicMock()
1022 super(MagicDirApiError, self).setUp(api=api)
1023 api.collections().get().execute.side_effect = iter([Exception('API fail'), {"manifest_text": self.test_manifest}])
1024 api.keep.get.side_effect = Exception('Keep fail')
1027 self.make_mount(fuse.MagicDirectory)
1029 self.operations.inodes.inode_cache.cap = 1
1030 self.operations.inodes.inode_cache.min_entries = 2
1032 with self.assertRaises(OSError):
1033 llfuse.listdir(os.path.join(self.mounttmp, self.testcollection))
1035 llfuse.listdir(os.path.join(self.mounttmp, self.testcollection))
1038 class FuseUnitTest(unittest.TestCase):
1039 def test_sanitize_filename(self):
1058 for f in acceptable:
1059 self.assertEqual(f, fuse.sanitize_filename(f))
1060 for f in unacceptable:
1061 self.assertNotEqual(f, fuse.sanitize_filename(f))
1062 # The sanitized filename should be the same length, though.
1063 self.assertEqual(len(f), len(fuse.sanitize_filename(f)))
1065 self.assertEqual("_", fuse.sanitize_filename(""))
1066 self.assertEqual("_", fuse.sanitize_filename("."))
1067 self.assertEqual("__", fuse.sanitize_filename(".."))
1070 class FuseMagicTestPDHOnly(MountTestBase):
1071 def setUp(self, api=None):
1072 super(FuseMagicTestPDHOnly, self).setUp(api=api)
1074 cw = arvados.CollectionWriter()
1076 cw.start_new_file('thing1.txt')
1079 self.testcollection = cw.finish()
1080 self.test_manifest = cw.manifest_text()
1081 created = self.api.collections().create(body={"manifest_text":self.test_manifest}).execute()
1082 self.testcollectionuuid = str(created['uuid'])
1084 def verify_pdh_only(self, pdh_only=False, skip_pdh_only=False):
1085 if skip_pdh_only is True:
1086 self.make_mount(fuse.MagicDirectory) # in this case, the default by_id applies
1088 self.make_mount(fuse.MagicDirectory, pdh_only=pdh_only)
1090 mount_ls = llfuse.listdir(self.mounttmp)
1091 self.assertIn('README', mount_ls)
1092 self.assertFalse(any(arvados.util.keep_locator_pattern.match(fn) or
1093 arvados.util.uuid_pattern.match(fn)
1094 for fn in mount_ls),
1095 "new FUSE MagicDirectory lists Collection")
1097 # look up using pdh should succeed in all cases
1098 self.assertDirContents(self.testcollection, ['thing1.txt'])
1099 self.assertDirContents(os.path.join('by_id', self.testcollection),
1101 mount_ls = llfuse.listdir(self.mounttmp)
1102 self.assertIn('README', mount_ls)
1103 self.assertIn(self.testcollection, mount_ls)
1104 self.assertIn(self.testcollection,
1105 llfuse.listdir(os.path.join(self.mounttmp, 'by_id')))
1108 files[os.path.join(self.mounttmp, self.testcollection, 'thing1.txt')] = 'data 1'
1110 for k, v in files.items():
1111 with open(os.path.join(self.mounttmp, k)) as f:
1112 self.assertEqual(v, f.read())
1114 # look up using uuid should fail when pdh_only is set
1115 if pdh_only is True:
1116 with self.assertRaises(OSError):
1117 self.assertDirContents(os.path.join('by_id', self.testcollectionuuid),
1120 self.assertDirContents(os.path.join('by_id', self.testcollectionuuid),
1123 def test_with_pdh_only_true(self):
1124 self.verify_pdh_only(pdh_only=True)
1126 def test_with_pdh_only_false(self):
1127 self.verify_pdh_only(pdh_only=False)
1129 def test_with_default_by_id(self):
1130 self.verify_pdh_only(skip_pdh_only=True)
1132 def _test_refresh_old_manifest(zzz):
1133 fnm = 'zzzzz-8i9sb-0vsrcqi7whchuil.log.txt'
1134 os.listdir(os.path.join(zzz))
1136 with open(os.path.join(zzz, fnm)) as f:
1139 class TokenExpiryTest(MountTestBase):
1141 super(TokenExpiryTest, self).setUp(local_store=False)
1143 @mock.patch('arvados.keep.KeepClient.get')
1144 def runTest(self, mocked_get):
1145 logging.getLogger('arvados.arvados_fuse').setLevel(logging.DEBUG)
1146 self.api._rootDesc = {"blobSignatureTtl": 2}
1147 mnt = self.make_mount(fuse.CollectionDirectory, collection_record='zzzzz-4zz18-op4e2lbej01tcvu')
1148 mocked_get.return_value = 'fake data'
1150 old_exp = int(time.time()) + 86400*14
1151 self.pool.apply(_test_refresh_old_manifest, (self.mounttmp,))
1152 want_exp = int(time.time()) + 86400*14
1154 got_loc = mocked_get.call_args[0][0]
1156 re.search(r'\+A[0-9a-f]+@([0-9a-f]+)', got_loc).group(1),
1158 self.assertGreaterEqual(
1159 got_exp, want_exp-1,
1160 msg='now+2w = {:x}, but fuse fetched locator {} (old_exp {:x})'.format(
1161 want_exp, got_loc, old_exp))
1162 self.assertLessEqual(
1164 msg='server is not using the expected 2w TTL; test is ineffective')