1 # Copyright (C) The Arvados Authors. All rights reserved.
3 # SPDX-License-Identifier: AGPL-3.0
10 from unittest import mock
12 class InodeTests(unittest.TestCase):
14 # The following tests call next(inodes._counter) because inode 1
15 # (the root directory) gets special treatment.
17 def test_inodes_basic(self):
18 cache = arvados_fuse.InodeCache(1000, 4)
19 inodes = arvados_fuse.Inodes(cache)
22 # Check that ent1 gets added to inodes
23 ent1 = mock.MagicMock()
24 ent1.in_use.return_value = False
25 ent1.has_ref.return_value = False
26 ent1.persisted.return_value = True
27 ent1.objsize.return_value = 500
28 inodes.add_entry(ent1)
29 self.assertIn(ent1.inode, inodes)
30 self.assertIs(inodes[ent1.inode], ent1)
31 self.assertEqual(500, cache.total())
33 def test_inodes_not_persisted(self):
34 cache = arvados_fuse.InodeCache(1000, 4)
35 inodes = arvados_fuse.Inodes(cache)
38 ent1 = mock.MagicMock()
39 ent1.in_use.return_value = False
40 ent1.has_ref.return_value = False
41 ent1.persisted.return_value = True
42 ent1.objsize.return_value = 500
43 inodes.add_entry(ent1)
45 # ent2 is not persisted, so it doesn't
46 # affect the cache total
47 ent2 = mock.MagicMock()
48 ent2.in_use.return_value = False
49 ent2.has_ref.return_value = False
50 ent2.persisted.return_value = False
51 ent2.objsize.return_value = 600
52 inodes.add_entry(ent2)
53 self.assertEqual(500, cache.total())
55 def test_inode_cleared(self):
56 cache = arvados_fuse.InodeCache(1000, 4)
57 inodes = arvados_fuse.Inodes(cache)
60 # Check that ent1 gets added to inodes
61 ent1 = mock.MagicMock()
62 ent1.in_use.return_value = False
63 ent1.has_ref.return_value = False
64 ent1.persisted.return_value = True
65 ent1.objsize.return_value = 500
66 inodes.add_entry(ent1)
68 # ent3 is persisted, adding it should cause ent1 to get cleared
69 ent3 = mock.MagicMock()
70 ent3.in_use.return_value = False
71 ent3.has_ref.return_value = False
72 ent3.persisted.return_value = True
73 ent3.objsize.return_value = 600
75 self.assertFalse(ent1.clear.called)
76 inodes.add_entry(ent3)
78 # Won't clear anything because min_entries = 4
79 self.assertEqual(2, len(cache._cache_entries))
80 self.assertFalse(ent1.clear.called)
81 self.assertEqual(1100, cache.total())
85 ent1.parent_inode = None
87 inodes.wait_remove_queue_empty()
88 self.assertEqual(600, cache.total())
89 self.assertTrue(ent1.clear.called)
91 # Touching ent1 should cause ent3 to get cleared
92 ent3.parent_inode = None
93 self.assertFalse(ent3.clear.called)
94 inodes.inode_cache.update_cache_size(ent1)
96 inodes.wait_remove_queue_empty()
97 self.assertTrue(ent3.clear.called)
98 self.assertEqual(500, cache.total())
100 def test_clear_in_use(self):
101 cache = arvados_fuse.InodeCache(1000, 4)
102 inodes = arvados_fuse.Inodes(cache)
103 next(inodes._counter)
105 ent1 = mock.MagicMock()
106 ent1.in_use.return_value = True
107 ent1.has_ref.return_value = False
108 ent1.persisted.return_value = True
109 ent1.objsize.return_value = 500
110 inodes.add_entry(ent1)
112 ent3 = mock.MagicMock()
113 ent3.in_use.return_value = False
114 ent3.has_ref.return_value = True
115 ent3.persisted.return_value = True
116 ent3.objsize.return_value = 600
117 inodes.add_entry(ent3)
119 cache.min_entries = 1
121 # ent1, ent3 in use, has ref, can't be cleared
122 ent1.clear.called = False
123 ent3.clear.called = False
124 self.assertFalse(ent1.clear.called)
125 self.assertFalse(ent3.clear.called)
127 inodes.wait_remove_queue_empty()
128 self.assertFalse(ent1.clear.called)
129 self.assertFalse(ent3.clear.called)
130 # kernel invalidate gets called anyway
131 self.assertTrue(ent3.kernel_invalidate.called)
132 self.assertEqual(1100, cache.total())
134 # ent1 still in use, ent3 doesn't have ref,
135 # so ent3 gets cleared
136 ent3.has_ref.return_value = False
137 ent1.clear.called = False
138 ent3.clear.called = False
139 ent3.parent_inode = None
141 inodes.wait_remove_queue_empty()
142 self.assertFalse(ent1.clear.called)
143 self.assertTrue(ent3.clear.called)
144 self.assertEqual(500, cache.total())
146 def test_delete(self):
147 cache = arvados_fuse.InodeCache(1000, 0)
148 inodes = arvados_fuse.Inodes(cache)
149 next(inodes._counter)
151 ent1 = mock.MagicMock()
152 ent1.in_use.return_value = False
153 ent1.has_ref.return_value = False
154 ent1.persisted.return_value = True
155 ent1.objsize.return_value = 500
156 inodes.add_entry(ent1)
158 ent3 = mock.MagicMock()
159 ent3.in_use.return_value = False
160 ent3.has_ref.return_value = False
161 ent3.persisted.return_value = True
162 ent3.objsize.return_value = 600
165 self.assertEqual(500, cache.total())
168 inodes.del_entry(ent1)
169 inodes.wait_remove_queue_empty()
170 self.assertEqual(0, cache.total())
172 inodes.add_entry(ent3)
173 inodes.wait_remove_queue_empty()
174 self.assertEqual(600, cache.total())