github.com/jbendotnet/noms@v0.0.0-20190904222105-c43e4293ea92/go/nbs/fd_cache_test.go (about)

     1  // Copyright 2017 Attic Labs, Inc. All rights reserved.
     2  // Licensed under the Apache License, version 2.0:
     3  // http://www.apache.org/licenses/LICENSE-2.0
     4  
     5  package nbs
     6  
     7  import (
     8  	"fmt"
     9  	"io/ioutil"
    10  	"os"
    11  	"path/filepath"
    12  	"sort"
    13  	"sync"
    14  	"testing"
    15  
    16  	"github.com/stretchr/testify/assert"
    17  )
    18  
    19  func TestFDCache(t *testing.T) {
    20  	dir := makeTempDir(t)
    21  	defer os.RemoveAll(dir)
    22  
    23  	paths := [3]string{}
    24  	for i := range paths {
    25  		name := fmt.Sprintf("file%d", i)
    26  		paths[i] = filepath.Join(dir, name)
    27  		err := ioutil.WriteFile(paths[i], []byte(name), 0644)
    28  		assert.NoError(t, err)
    29  	}
    30  
    31  	refNoError := func(fc *fdCache, p string, assert *assert.Assertions) *os.File {
    32  		f, err := fc.RefFile(p)
    33  		assert.NoError(err)
    34  		assert.NotNil(f)
    35  		return f
    36  	}
    37  
    38  	t.Run("ConcurrentOpen", func(t *testing.T) {
    39  		assert := assert.New(t)
    40  		concurrency := 3
    41  		fc := newFDCache(3)
    42  		defer fc.Drop()
    43  
    44  		trigger := make(chan struct{})
    45  		wg := sync.WaitGroup{}
    46  		for i := 0; i < concurrency; i++ {
    47  			wg.Add(1)
    48  			go func() {
    49  				defer wg.Done()
    50  				<-trigger
    51  				fc.RefFile(paths[0])
    52  			}()
    53  		}
    54  		close(trigger)
    55  		wg.Wait()
    56  
    57  		present := fc.reportEntries()
    58  		if assert.Len(present, 1) {
    59  			ce := fc.cache[present[0]]
    60  			assert.EqualValues(concurrency, ce.refCount)
    61  		}
    62  	})
    63  
    64  	t.Run("NoEvictions", func(t *testing.T) {
    65  		assert := assert.New(t)
    66  		fc := newFDCache(2)
    67  		defer fc.Drop()
    68  		f := refNoError(fc, paths[0], assert)
    69  
    70  		f2 := refNoError(fc, paths[1], assert)
    71  		assert.NotEqual(f, f2)
    72  
    73  		dup := refNoError(fc, paths[0], assert)
    74  		assert.Equal(f, dup)
    75  	})
    76  
    77  	t.Run("Evictions", func(t *testing.T) {
    78  		assert := assert.New(t)
    79  		fc := newFDCache(1)
    80  		defer fc.Drop()
    81  
    82  		f0 := refNoError(fc, paths[0], assert)
    83  		f1 := refNoError(fc, paths[1], assert)
    84  		assert.NotEqual(f0, f1)
    85  
    86  		// f0 wasn't evicted, because that doesn't happen until UnrefFile()
    87  		dup := refNoError(fc, paths[0], assert)
    88  		assert.Equal(f0, dup)
    89  
    90  		expected := sort.StringSlice(paths[:2])
    91  		sort.Sort(expected)
    92  		assert.EqualValues(expected, fc.reportEntries())
    93  
    94  		// Unreffing f1 now should evict it
    95  		fc.UnrefFile(paths[1])
    96  		assert.EqualValues(paths[:1], fc.reportEntries())
    97  
    98  		// Bring f1 back so we can test multiple evictions in a row
    99  		f1 = refNoError(fc, paths[1], assert)
   100  		assert.NotEqual(f0, f1)
   101  
   102  		// After adding f3, we should be able to evict both f0 and f1
   103  		f2 := refNoError(fc, paths[2], assert)
   104  		assert.NotEqual(f0, f2)
   105  		assert.NotEqual(f1, f2)
   106  
   107  		fc.UnrefFile(paths[0])
   108  		fc.UnrefFile(paths[0])
   109  		fc.UnrefFile(paths[1])
   110  
   111  		assert.EqualValues(paths[2:], fc.reportEntries())
   112  	})
   113  }