Merge branch 'master' into 12018-sync-groups-tool
[arvados.git] / services / fuse / tests / test_inodes.py
1 # Copyright (C) The Arvados Authors. All rights reserved.
2 #
3 # SPDX-License-Identifier: AGPL-3.0
4
5 import arvados_fuse
6 import mock
7 import unittest
8 import llfuse
9 import logging
10
11 class InodeTests(unittest.TestCase):
12     def test_inodes_basic(self):
13         cache = arvados_fuse.InodeCache(1000, 4)
14         inodes = arvados_fuse.Inodes(cache)
15
16         # Check that ent1 gets added to inodes
17         ent1 = mock.MagicMock()
18         ent1.in_use.return_value = False
19         ent1.has_ref.return_value = False
20         ent1.persisted.return_value = True
21         ent1.objsize.return_value = 500
22         inodes.add_entry(ent1)
23         self.assertIn(ent1.inode, inodes)
24         self.assertIs(inodes[ent1.inode], ent1)
25         self.assertEqual(500, cache.total())
26
27     def test_inodes_not_persisted(self):
28         cache = arvados_fuse.InodeCache(1000, 4)
29         inodes = arvados_fuse.Inodes(cache)
30
31         ent1 = mock.MagicMock()
32         ent1.in_use.return_value = False
33         ent1.has_ref.return_value = False
34         ent1.persisted.return_value = True
35         ent1.objsize.return_value = 500
36         inodes.add_entry(ent1)
37
38         # ent2 is not persisted, so it doesn't
39         # affect the cache total
40         ent2 = mock.MagicMock()
41         ent2.in_use.return_value = False
42         ent2.has_ref.return_value = False
43         ent2.persisted.return_value = False
44         ent2.objsize.return_value = 600
45         inodes.add_entry(ent2)
46         self.assertEqual(500, cache.total())
47
48     def test_inode_cleared(self):
49         cache = arvados_fuse.InodeCache(1000, 4)
50         inodes = arvados_fuse.Inodes(cache)
51
52         # Check that ent1 gets added to inodes
53         ent1 = mock.MagicMock()
54         ent1.in_use.return_value = False
55         ent1.has_ref.return_value = False
56         ent1.persisted.return_value = True
57         ent1.objsize.return_value = 500
58         inodes.add_entry(ent1)
59
60         # ent3 is persisted, adding it should cause ent1 to get cleared
61         ent3 = mock.MagicMock()
62         ent3.in_use.return_value = False
63         ent3.has_ref.return_value = False
64         ent3.persisted.return_value = True
65         ent3.objsize.return_value = 600
66
67         self.assertFalse(ent1.clear.called)
68         inodes.add_entry(ent3)
69
70         # Won't clear anything because min_entries = 4
71         self.assertEqual(2, len(cache._entries))
72         self.assertFalse(ent1.clear.called)
73         self.assertEqual(1100, cache.total())
74
75         # Change min_entries
76         cache.min_entries = 1
77         cache.cap_cache()
78         self.assertEqual(600, cache.total())
79         self.assertTrue(ent1.clear.called)
80
81         # Touching ent1 should cause ent3 to get cleared
82         self.assertFalse(ent3.clear.called)
83         cache.touch(ent1)
84         self.assertTrue(ent3.clear.called)
85         self.assertEqual(500, cache.total())
86
87     def test_clear_in_use(self):
88         cache = arvados_fuse.InodeCache(1000, 4)
89         inodes = arvados_fuse.Inodes(cache)
90
91         ent1 = mock.MagicMock()
92         ent1.in_use.return_value = True
93         ent1.has_ref.return_value = False
94         ent1.persisted.return_value = True
95         ent1.objsize.return_value = 500
96         inodes.add_entry(ent1)
97
98         ent3 = mock.MagicMock()
99         ent3.in_use.return_value = False
100         ent3.has_ref.return_value = True
101         ent3.persisted.return_value = True
102         ent3.objsize.return_value = 600
103         inodes.add_entry(ent3)
104
105         cache.min_entries = 1
106
107         # ent1, ent3 in use, has ref, can't be cleared
108         ent1.clear.called = False
109         ent3.clear.called = False
110         self.assertFalse(ent1.clear.called)
111         self.assertFalse(ent3.clear.called)
112         cache.touch(ent3)
113         self.assertFalse(ent1.clear.called)
114         self.assertFalse(ent3.clear.called)
115         self.assertTrue(ent3.kernel_invalidate.called)
116         self.assertEqual(1100, cache.total())
117
118         # ent1 still in use, ent3 doesn't have ref,
119         # so ent3 gets cleared
120         ent3.has_ref.return_value = False
121         ent1.clear.called = False
122         ent3.clear.called = False
123         cache.touch(ent3)
124         self.assertFalse(ent1.clear.called)
125         self.assertTrue(ent3.clear.called)
126         self.assertEqual(500, cache.total())
127
128     def test_delete(self):
129         cache = arvados_fuse.InodeCache(1000, 4)
130         inodes = arvados_fuse.Inodes(cache)
131
132         ent1 = mock.MagicMock()
133         ent1.in_use.return_value = False
134         ent1.has_ref.return_value = False
135         ent1.persisted.return_value = True
136         ent1.objsize.return_value = 500
137         inodes.add_entry(ent1)
138
139         ent3 = mock.MagicMock()
140         ent3.in_use.return_value = False
141         ent3.has_ref.return_value = False
142         ent3.persisted.return_value = True
143         ent3.objsize.return_value = 600
144
145         # Delete ent1
146         self.assertEqual(500, cache.total())
147         ent1.ref_count = 0
148         with llfuse.lock:
149             inodes.del_entry(ent1)
150         self.assertEqual(0, cache.total())
151         cache.touch(ent3)
152         self.assertEqual(600, cache.total())