1 # Copyright (C) The Arvados Authors. All rights reserved.
3 # SPDX-License-Identifier: AGPL-3.0
11 class InodeTests(unittest.TestCase):
13 # The following tests call next(inodes._counter) because inode 1
14 # (the root directory) gets special treatment.
16 def test_inodes_basic(self):
17 cache = arvados_fuse.InodeCache(1000, 4)
18 inodes = arvados_fuse.Inodes(cache)
21 # Check that ent1 gets added to inodes
22 ent1 = mock.MagicMock()
23 ent1.in_use.return_value = False
24 ent1.has_ref.return_value = False
25 ent1.persisted.return_value = True
26 ent1.objsize.return_value = 500
27 inodes.add_entry(ent1)
28 self.assertIn(ent1.inode, inodes)
29 self.assertIs(inodes[ent1.inode], ent1)
30 self.assertEqual(500, cache.total())
32 def test_inodes_not_persisted(self):
33 cache = arvados_fuse.InodeCache(1000, 4)
34 inodes = arvados_fuse.Inodes(cache)
37 ent1 = mock.MagicMock()
38 ent1.in_use.return_value = False
39 ent1.has_ref.return_value = False
40 ent1.persisted.return_value = True
41 ent1.objsize.return_value = 500
42 inodes.add_entry(ent1)
44 # ent2 is not persisted, so it doesn't
45 # affect the cache total
46 ent2 = mock.MagicMock()
47 ent2.in_use.return_value = False
48 ent2.has_ref.return_value = False
49 ent2.persisted.return_value = False
50 ent2.objsize.return_value = 600
51 inodes.add_entry(ent2)
52 self.assertEqual(500, cache.total())
54 def test_inode_cleared(self):
55 cache = arvados_fuse.InodeCache(1000, 4)
56 inodes = arvados_fuse.Inodes(cache)
59 # Check that ent1 gets added to inodes
60 ent1 = mock.MagicMock()
61 ent1.in_use.return_value = False
62 ent1.has_ref.return_value = False
63 ent1.persisted.return_value = True
64 ent1.objsize.return_value = 500
65 inodes.add_entry(ent1)
67 # ent3 is persisted, adding it should cause ent1 to get cleared
68 ent3 = mock.MagicMock()
69 ent3.in_use.return_value = False
70 ent3.has_ref.return_value = False
71 ent3.persisted.return_value = True
72 ent3.objsize.return_value = 600
74 self.assertFalse(ent1.clear.called)
75 inodes.add_entry(ent3)
77 # Won't clear anything because min_entries = 4
78 self.assertEqual(2, len(cache._cache_entries))
79 self.assertFalse(ent1.clear.called)
80 self.assertEqual(1100, cache.total())
84 ent1.parent_inode = None
86 inodes.wait_remove_queue_empty()
87 self.assertEqual(600, cache.total())
88 self.assertTrue(ent1.clear.called)
90 # Touching ent1 should cause ent3 to get cleared
91 ent3.parent_inode = None
92 self.assertFalse(ent3.clear.called)
93 inodes.inode_cache.update_cache_size(ent1)
95 inodes.wait_remove_queue_empty()
96 self.assertTrue(ent3.clear.called)
97 self.assertEqual(500, cache.total())
99 def test_clear_in_use(self):
100 cache = arvados_fuse.InodeCache(1000, 4)
101 inodes = arvados_fuse.Inodes(cache)
102 next(inodes._counter)
104 ent1 = mock.MagicMock()
105 ent1.in_use.return_value = True
106 ent1.has_ref.return_value = False
107 ent1.persisted.return_value = True
108 ent1.objsize.return_value = 500
109 inodes.add_entry(ent1)
111 ent3 = mock.MagicMock()
112 ent3.in_use.return_value = False
113 ent3.has_ref.return_value = True
114 ent3.persisted.return_value = True
115 ent3.objsize.return_value = 600
116 inodes.add_entry(ent3)
118 cache.min_entries = 1
120 # ent1, ent3 in use, has ref, can't be cleared
121 ent1.clear.called = False
122 ent3.clear.called = False
123 self.assertFalse(ent1.clear.called)
124 self.assertFalse(ent3.clear.called)
126 inodes.wait_remove_queue_empty()
127 self.assertFalse(ent1.clear.called)
128 self.assertFalse(ent3.clear.called)
129 # kernel invalidate gets called anyway
130 self.assertTrue(ent3.kernel_invalidate.called)
131 self.assertEqual(1100, cache.total())
133 # ent1 still in use, ent3 doesn't have ref,
134 # so ent3 gets cleared
135 ent3.has_ref.return_value = False
136 ent1.clear.called = False
137 ent3.clear.called = False
138 ent3.parent_inode = None
140 inodes.wait_remove_queue_empty()
141 self.assertFalse(ent1.clear.called)
142 self.assertTrue(ent3.clear.called)
143 self.assertEqual(500, cache.total())
145 def test_delete(self):
146 cache = arvados_fuse.InodeCache(1000, 0)
147 inodes = arvados_fuse.Inodes(cache)
148 next(inodes._counter)
150 ent1 = mock.MagicMock()
151 ent1.in_use.return_value = False
152 ent1.has_ref.return_value = False
153 ent1.persisted.return_value = True
154 ent1.objsize.return_value = 500
155 inodes.add_entry(ent1)
157 ent3 = mock.MagicMock()
158 ent3.in_use.return_value = False
159 ent3.has_ref.return_value = False
160 ent3.persisted.return_value = True
161 ent3.objsize.return_value = 600
164 self.assertEqual(500, cache.total())
167 inodes.del_entry(ent1)
168 inodes.wait_remove_queue_empty()
169 self.assertEqual(0, cache.total())
171 inodes.add_entry(ent3)
172 inodes.wait_remove_queue_empty()
173 self.assertEqual(600, cache.total())