github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fs/dirent_cache_test.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package fs 16 17 import ( 18 "testing" 19 ) 20 21 func TestDirentCache(t *testing.T) { 22 const maxSize = 5 23 24 c := NewDirentCache(maxSize) 25 26 // Size starts at 0. 27 if got, want := c.Size(), uint64(0); got != want { 28 t.Errorf("c.Size() got %v, want %v", got, want) 29 } 30 31 // Create a Dirent d. 32 d := NewNegativeDirent("") 33 34 // c does not contain d. 35 if got, want := c.contains(d), false; got != want { 36 t.Errorf("c.contains(d) got %v want %v", got, want) 37 } 38 39 // Add d to the cache. 40 c.Add(d) 41 42 // Size is now 1. 43 if got, want := c.Size(), uint64(1); got != want { 44 t.Errorf("c.Size() got %v, want %v", got, want) 45 } 46 47 // c contains d. 48 if got, want := c.contains(d), true; got != want { 49 t.Errorf("c.contains(d) got %v want %v", got, want) 50 } 51 52 // Add maxSize-1 more elements. d should be oldest element. 53 for i := 0; i < maxSize-1; i++ { 54 c.Add(NewNegativeDirent("")) 55 } 56 57 // Size is maxSize. 58 if got, want := c.Size(), uint64(maxSize); got != want { 59 t.Errorf("c.Size() got %v, want %v", got, want) 60 } 61 62 // c contains d. 63 if got, want := c.contains(d), true; got != want { 64 t.Errorf("c.contains(d) got %v want %v", got, want) 65 } 66 67 // "Bump" d to the front by re-adding it. 68 c.Add(d) 69 70 // Size is maxSize. 71 if got, want := c.Size(), uint64(maxSize); got != want { 72 t.Errorf("c.Size() got %v, want %v", got, want) 73 } 74 75 // c contains d. 76 if got, want := c.contains(d), true; got != want { 77 t.Errorf("c.contains(d) got %v want %v", got, want) 78 } 79 80 // Add maxSize-1 more elements. d should again be oldest element. 81 for i := 0; i < maxSize-1; i++ { 82 c.Add(NewNegativeDirent("")) 83 } 84 85 // Size is maxSize. 86 if got, want := c.Size(), uint64(maxSize); got != want { 87 t.Errorf("c.Size() got %v, want %v", got, want) 88 } 89 90 // c contains d. 91 if got, want := c.contains(d), true; got != want { 92 t.Errorf("c.contains(d) got %v want %v", got, want) 93 } 94 95 // Add one more element, which will bump d from the cache. 96 c.Add(NewNegativeDirent("")) 97 98 // Size is maxSize. 99 if got, want := c.Size(), uint64(maxSize); got != want { 100 t.Errorf("c.Size() got %v, want %v", got, want) 101 } 102 103 // c does not contain d. 104 if got, want := c.contains(d), false; got != want { 105 t.Errorf("c.contains(d) got %v want %v", got, want) 106 } 107 108 // Invalidating causes size to be 0 and list to be empty. 109 c.Invalidate() 110 if got, want := c.Size(), uint64(0); got != want { 111 t.Errorf("c.Size() got %v, want %v", got, want) 112 } 113 if got, want := c.list.Empty(), true; got != want { 114 t.Errorf("c.list.Empty() got %v, want %v", got, want) 115 } 116 117 // Fill cache with maxSize dirents. 118 for i := 0; i < maxSize; i++ { 119 c.Add(NewNegativeDirent("")) 120 } 121 } 122 123 func TestDirentCacheLimiter(t *testing.T) { 124 const ( 125 globalMaxSize = 5 126 maxSize = 3 127 ) 128 129 limit := NewDirentCacheLimiter(globalMaxSize) 130 c1 := NewDirentCache(maxSize) 131 c1.limit = limit 132 c2 := NewDirentCache(maxSize) 133 c2.limit = limit 134 135 // Create a Dirent d. 136 d := NewNegativeDirent("") 137 138 // Add d to the cache. 139 c1.Add(d) 140 if got, want := c1.Size(), uint64(1); got != want { 141 t.Errorf("c1.Size() got %v, want %v", got, want) 142 } 143 144 // Add maxSize-1 more elements. d should be oldest element. 145 for i := 0; i < maxSize-1; i++ { 146 c1.Add(NewNegativeDirent("")) 147 } 148 if got, want := c1.Size(), uint64(maxSize); got != want { 149 t.Errorf("c1.Size() got %v, want %v", got, want) 150 } 151 152 // Check that d is still there. 153 if got, want := c1.contains(d), true; got != want { 154 t.Errorf("c1.contains(d) got %v want %v", got, want) 155 } 156 157 // Fill up the other cache, it will start dropping old entries from the cache 158 // when the global limit is reached. 159 for i := 0; i < maxSize; i++ { 160 c2.Add(NewNegativeDirent("")) 161 } 162 163 // Check is what's remaining from global max. 164 if got, want := c2.Size(), globalMaxSize-maxSize; int(got) != want { 165 t.Errorf("c2.Size() got %v, want %v", got, want) 166 } 167 168 // Check that d was not dropped. 169 if got, want := c1.contains(d), true; got != want { 170 t.Errorf("c1.contains(d) got %v want %v", got, want) 171 } 172 173 // Add an entry that will eventually be dropped. Check is done later... 174 drop := NewNegativeDirent("") 175 c1.Add(drop) 176 177 // Check that d is bumped to front even when global limit is reached. 178 c1.Add(d) 179 if got, want := c1.contains(d), true; got != want { 180 t.Errorf("c1.contains(d) got %v want %v", got, want) 181 } 182 183 // Add 2 more element and check that: 184 // - d is still in the list: to verify that d was bumped 185 // - d2/d3 are in the list: older entries are dropped when global limit is 186 // reached. 187 // - drop is not in the list: indeed older elements are dropped. 188 d2 := NewNegativeDirent("") 189 c1.Add(d2) 190 d3 := NewNegativeDirent("") 191 c1.Add(d3) 192 if got, want := c1.contains(d), true; got != want { 193 t.Errorf("c1.contains(d) got %v want %v", got, want) 194 } 195 if got, want := c1.contains(d2), true; got != want { 196 t.Errorf("c1.contains(d2) got %v want %v", got, want) 197 } 198 if got, want := c1.contains(d3), true; got != want { 199 t.Errorf("c1.contains(d3) got %v want %v", got, want) 200 } 201 if got, want := c1.contains(drop), false; got != want { 202 t.Errorf("c1.contains(drop) got %v want %v", got, want) 203 } 204 205 // Drop all entries from one cache. The other will be allowed to grow. 206 c1.Invalidate() 207 c2.Add(NewNegativeDirent("")) 208 if got, want := c2.Size(), uint64(maxSize); got != want { 209 t.Errorf("c2.Size() got %v, want %v", got, want) 210 } 211 } 212 213 // TestNilDirentCache tests that a nil cache supports all cache operations, but 214 // treats them as noop. 215 func TestNilDirentCache(t *testing.T) { 216 // Create a nil cache. 217 var c *DirentCache 218 219 // Size is zero. 220 if got, want := c.Size(), uint64(0); got != want { 221 t.Errorf("c.Size() got %v, want %v", got, want) 222 } 223 224 // Call Add. 225 c.Add(NewNegativeDirent("")) 226 227 // Size is zero. 228 if got, want := c.Size(), uint64(0); got != want { 229 t.Errorf("c.Size() got %v, want %v", got, want) 230 } 231 232 // Call Remove. 233 c.Remove(NewNegativeDirent("")) 234 235 // Size is zero. 236 if got, want := c.Size(), uint64(0); got != want { 237 t.Errorf("c.Size() got %v, want %v", got, want) 238 } 239 240 // Call Invalidate. 241 c.Invalidate() 242 243 // Size is zero. 244 if got, want := c.Size(), uint64(0); got != want { 245 t.Errorf("c.Size() got %v, want %v", got, want) 246 } 247 }