3 import arvados_fuse.command
12 import run_test_server
18 """If argparse or arvados_fuse tries to exit, fail the test instead"""
19 class SystemExitCaught(StandardError):
21 @functools.wraps(func)
22 def wrapper(*args, **kwargs):
24 return func(*args, **kwargs)
26 raise SystemExitCaught
29 @contextlib.contextmanager
31 orig, sys.stderr = sys.stderr, open(os.devnull, 'w')
38 class MountArgsTest(unittest.TestCase):
40 self.mntdir = tempfile.mkdtemp()
41 run_test_server.authorize_with('active')
46 def lookup(self, mnt, *path):
47 ent = mnt.operations.inodes[llfuse.ROOT_INODE]
52 @contextlib.contextmanager
53 def stderrMatches(self, stderr):
54 orig, sys.stderr = sys.stderr, stderr
60 def check_ent_type(self, cls, *path):
61 ent = self.lookup(self.mnt, *path)
62 self.assertEqual(ent.__class__, cls)
66 def test_default_all(self):
67 args = arvados_fuse.command.ArgumentParser().parse_args([
68 '--foreground', self.mntdir])
69 self.assertEqual(args.mode, None)
70 self.mnt = arvados_fuse.command.Mount(args)
71 e = self.check_ent_type(arvados_fuse.ProjectDirectory, 'home')
72 self.assertEqual(e.project_object['uuid'],
73 run_test_server.fixture('users')['active']['uuid'])
74 e = self.check_ent_type(arvados_fuse.MagicDirectory, 'by_id')
76 e = self.check_ent_type(arvados_fuse.StringFile, 'README')
77 readme = e.readfrom(0, -1)
78 self.assertRegexpMatches(readme, r'active-user@arvados\.local')
79 self.assertRegexpMatches(readme, r'\n$')
81 e = self.check_ent_type(arvados_fuse.StringFile, 'by_id', 'README')
82 txt = e.readfrom(0, -1)
83 self.assertRegexpMatches(txt, r'portable data hash')
84 self.assertRegexpMatches(txt, r'\n$')
88 args = arvados_fuse.command.ArgumentParser().parse_args([
90 '--foreground', self.mntdir])
91 self.assertEqual(args.mode, 'by_id')
92 self.mnt = arvados_fuse.command.Mount(args)
93 e = self.check_ent_type(arvados_fuse.MagicDirectory)
94 self.assertEqual(e.pdh_only, False)
95 self.assertEqual(True, self.mnt.listen_for_events)
98 def test_by_pdh(self):
99 args = arvados_fuse.command.ArgumentParser().parse_args([
101 '--foreground', self.mntdir])
102 self.assertEqual(args.mode, 'by_pdh')
103 self.mnt = arvados_fuse.command.Mount(args)
104 e = self.check_ent_type(arvados_fuse.MagicDirectory)
105 self.assertEqual(e.pdh_only, True)
106 self.assertEqual(False, self.mnt.listen_for_events)
109 def test_by_tag(self):
110 args = arvados_fuse.command.ArgumentParser().parse_args([
112 '--foreground', self.mntdir])
113 self.assertEqual(args.mode, 'by_tag')
114 self.mnt = arvados_fuse.command.Mount(args)
115 e = self.check_ent_type(arvados_fuse.TagsDirectory)
116 self.assertEqual(True, self.mnt.listen_for_events)
119 def test_collection(self, id_type='uuid'):
120 c = run_test_server.fixture('collections')['public_text_file']
122 args = arvados_fuse.command.ArgumentParser().parse_args([
124 '--foreground', self.mntdir])
125 self.mnt = arvados_fuse.command.Mount(args)
126 e = self.check_ent_type(arvados_fuse.CollectionDirectory)
127 self.assertEqual(e.collection_locator, cid)
128 self.assertEqual(id_type == 'uuid', self.mnt.listen_for_events)
130 def test_collection_pdh(self):
131 self.test_collection('portable_data_hash')
135 args = arvados_fuse.command.ArgumentParser().parse_args([
137 '--foreground', self.mntdir])
138 self.assertEqual(args.mode, 'home')
139 self.mnt = arvados_fuse.command.Mount(args)
140 e = self.check_ent_type(arvados_fuse.ProjectDirectory)
141 self.assertEqual(e.project_object['uuid'],
142 run_test_server.fixture('users')['active']['uuid'])
143 self.assertEqual(True, self.mnt.listen_for_events)
145 def test_mutually_exclusive_args(self):
146 cid = run_test_server.fixture('collections')['public_text_file']['uuid']
147 gid = run_test_server.fixture('groups')['aproject']['uuid']
149 ['--mount-tmp', 'foo', '--collection', cid],
150 ['--mount-tmp', 'foo', '--project', gid],
151 ['--collection', cid, '--project', gid],
152 ['--by-id', '--project', gid],
153 ['--mount-tmp', 'foo', '--by-id'],
156 with self.assertRaises(SystemExit):
157 args = arvados_fuse.command.ArgumentParser().parse_args(
158 badargs + ['--foreground', self.mntdir])
159 arvados_fuse.command.Mount(args)
161 def test_project(self):
162 uuid = run_test_server.fixture('groups')['aproject']['uuid']
163 args = arvados_fuse.command.ArgumentParser().parse_args([
165 '--foreground', self.mntdir])
166 self.mnt = arvados_fuse.command.Mount(args)
167 e = self.check_ent_type(arvados_fuse.ProjectDirectory)
168 self.assertEqual(e.project_object['uuid'], uuid)
171 def test_shared(self):
172 args = arvados_fuse.command.ArgumentParser().parse_args([
174 '--foreground', self.mntdir])
175 self.assertEqual(args.mode, 'shared')
176 self.mnt = arvados_fuse.command.Mount(args)
177 e = self.check_ent_type(arvados_fuse.SharedDirectory)
178 self.assertEqual(e.current_user['uuid'],
179 run_test_server.fixture('users')['active']['uuid'])
180 self.assertEqual(True, self.mnt.listen_for_events)
182 def test_version_argument(self):
183 orig, sys.stderr = sys.stderr, io.BytesIO()
184 with self.assertRaises(SystemExit):
185 args = arvados_fuse.command.ArgumentParser().parse_args(['--version'])
186 self.assertRegexpMatches(sys.stderr.getvalue(), "[0-9]+\.[0-9]+\.[0-9]+")
190 @mock.patch('arvados.events.subscribe')
191 def test_disable_event_listening(self, mock_subscribe):
192 args = arvados_fuse.command.ArgumentParser().parse_args([
193 '--disable-event-listening',
195 '--foreground', self.mntdir])
196 self.mnt = arvados_fuse.command.Mount(args)
197 self.assertEqual(True, self.mnt.listen_for_events)
198 self.assertEqual(True, self.mnt.args.disable_event_listening)
201 self.assertEqual(0, mock_subscribe.call_count)
204 @mock.patch('arvados.events.subscribe')
205 def test_custom(self, mock_subscribe):
206 args = arvados_fuse.command.ArgumentParser().parse_args([
207 '--mount-tmp', 'foo',
208 '--mount-tmp', 'bar',
209 '--mount-home', 'my_home',
210 '--foreground', self.mntdir])
211 self.assertEqual(args.mode, None)
212 self.mnt = arvados_fuse.command.Mount(args)
213 self.check_ent_type(arvados_fuse.Directory)
214 self.check_ent_type(arvados_fuse.TmpCollectionDirectory, 'foo')
215 self.check_ent_type(arvados_fuse.TmpCollectionDirectory, 'bar')
216 e = self.check_ent_type(arvados_fuse.ProjectDirectory, 'my_home')
217 self.assertEqual(e.project_object['uuid'],
218 run_test_server.fixture('users')['active']['uuid'])
219 self.assertEqual(True, self.mnt.listen_for_events)
222 self.assertEqual(1, mock_subscribe.call_count)
225 @mock.patch('arvados.events.subscribe')
226 def test_custom_no_listen(self, mock_subscribe):
227 args = arvados_fuse.command.ArgumentParser().parse_args([
228 '--mount-by-pdh', 'pdh',
229 '--mount-tmp', 'foo',
230 '--mount-tmp', 'bar',
231 '--foreground', self.mntdir])
232 self.mnt = arvados_fuse.command.Mount(args)
233 self.assertEqual(False, self.mnt.listen_for_events)
236 self.assertEqual(0, mock_subscribe.call_count)
238 def test_custom_unsupported_layouts(self):
239 for name in ['.', '..', '', 'foo/bar', '/foo']:
241 with self.assertRaises(SystemExit):
242 args = arvados_fuse.command.ArgumentParser().parse_args([
244 '--foreground', self.mntdir])
245 arvados_fuse.command.Mount(args)
247 class MountErrorTest(unittest.TestCase):
249 self.mntdir = tempfile.mkdtemp()
250 run_test_server.run()
251 run_test_server.authorize_with("active")
252 self.logger = logging.getLogger("null")
253 self.logger.setLevel(logging.CRITICAL+1)
256 if os.path.exists(self.mntdir):
257 # If the directory was not unmounted, this will raise an exception.
258 os.rmdir(self.mntdir)
259 run_test_server.reset()
261 def test_no_token(self):
262 del arvados.config._settings["ARVADOS_API_TOKEN"]
263 arvados.config._settings = {}
264 with self.assertRaises(SystemExit) as ex:
265 args = arvados_fuse.command.ArgumentParser().parse_args([self.mntdir])
266 arvados_fuse.command.Mount(args, logger=self.logger).run()
267 self.assertEqual(1, ex.exception.code)
269 def test_no_host(self):
270 del arvados.config._settings["ARVADOS_API_HOST"]
271 with self.assertRaises(SystemExit) as ex:
272 args = arvados_fuse.command.ArgumentParser().parse_args([self.mntdir])
273 arvados_fuse.command.Mount(args, logger=self.logger).run()
274 self.assertEqual(1, ex.exception.code)
276 def test_bogus_host(self):
277 arvados.config._settings["ARVADOS_API_HOST"] = "100::"
278 with self.assertRaises(SystemExit) as ex:
279 args = arvados_fuse.command.ArgumentParser().parse_args([self.mntdir])
280 arvados_fuse.command.Mount(args, logger=self.logger).run()
281 self.assertEqual(1, ex.exception.code)
283 def test_bogus_token(self):
284 arvados.config._settings["ARVADOS_API_TOKEN"] = "zzzzzzzzzzzzz"
285 with self.assertRaises(SystemExit) as ex:
286 args = arvados_fuse.command.ArgumentParser().parse_args([self.mntdir])
287 arvados_fuse.command.Mount(args, logger=self.logger).run()
288 self.assertEqual(1, ex.exception.code)
290 def test_bogus_mount_dir(self):
291 # All FUSE errors in llfuse.init() are raised as RuntimeError
292 # An easy error to trigger is to supply a nonexistent mount point,
295 # Other possible errors that also raise RuntimeError (but are much
296 # harder to test automatically because they depend on operating
297 # system configuration):
299 # The user doesn't have permission to use FUSE
300 # The user specified --allow-other but user_allow_other is not set
302 os.rmdir(self.mntdir)
303 with self.assertRaises(SystemExit) as ex:
304 args = arvados_fuse.command.ArgumentParser().parse_args([self.mntdir])
305 arvados_fuse.command.Mount(args, logger=self.logger).run()
306 self.assertEqual(1, ex.exception.code)
308 def test_unreadable_collection(self):
309 with self.assertRaises(SystemExit) as ex:
310 args = arvados_fuse.command.ArgumentParser().parse_args([
311 "--collection", "zzzzz-4zz18-zzzzzzzzzzzzzzz", self.mntdir])
312 arvados_fuse.command.Mount(args, logger=self.logger).run()
313 self.assertEqual(1, ex.exception.code)
315 def test_unreadable_project(self):
316 with self.assertRaises(SystemExit) as ex:
317 args = arvados_fuse.command.ArgumentParser().parse_args([
318 "--project", "zzzzz-j7d0g-zzzzzzzzzzzzzzz", self.mntdir])
319 arvados_fuse.command.Mount(args, logger=self.logger).run()
320 self.assertEqual(1, ex.exception.code)