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  }