github.com/tiagovtristao/plz@v13.4.0+incompatible/src/cache/async_cache_test.go (about) 1 package cache 2 3 import ( 4 "fmt" 5 "sync" 6 "testing" 7 "time" 8 9 "github.com/stretchr/testify/assert" 10 11 "github.com/thought-machine/please/src/core" 12 ) 13 14 func TestStore(t *testing.T) { 15 mCache, aCache := makeCaches() 16 target := makeTarget("//pkg1:test_store") 17 aCache.Store(target, nil) 18 aCache.Shutdown() 19 assert.False(t, mCache.inFlight[target]) 20 assert.True(t, mCache.completed[target]) 21 } 22 23 func TestStoreExtra(t *testing.T) { 24 mCache, aCache := makeCaches() 25 target := makeTarget("//pkg1:test_store_extra") 26 aCache.StoreExtra(target, nil, "some_other_file") 27 aCache.Shutdown() 28 assert.False(t, mCache.inFlight[target]) 29 assert.True(t, mCache.completed[target]) 30 } 31 32 func TestRetrieve(t *testing.T) { 33 mCache, aCache := makeCaches() 34 target := makeTarget("//pkg1:test_retrieve") 35 aCache.Retrieve(target, nil) 36 aCache.Shutdown() 37 assert.False(t, mCache.inFlight[target]) 38 assert.True(t, mCache.completed[target]) 39 } 40 41 func TestRetrieveExtra(t *testing.T) { 42 mCache, aCache := makeCaches() 43 target := makeTarget("//pkg1:test_retrieve_extra") 44 aCache.RetrieveExtra(target, nil, "some_other_file") 45 aCache.Shutdown() 46 assert.False(t, mCache.inFlight[target]) 47 assert.True(t, mCache.completed[target]) 48 } 49 50 func TestClean(t *testing.T) { 51 mCache, aCache := makeCaches() 52 target := makeTarget("//pkg1:test_clean") 53 aCache.Clean(target) 54 aCache.Shutdown() 55 assert.False(t, mCache.inFlight[target]) 56 assert.True(t, mCache.completed[target]) 57 } 58 59 func TestSimulateBuild(t *testing.T) { 60 // Attempt to simulate what a normal build would do and confirm that the actions come 61 // back out in the correct order. 62 // This is a little obsolete now, it was ultimately solved by adding extra arguments to Store 63 // instead of requiring extra calls to StoreExtra, but that means there isn't that much 64 // left to exercise in this test any more. 65 const n = 100 66 var wg sync.WaitGroup 67 wg.Add(n) 68 mCache, aCache := makeCaches() 69 for i := 0; i < n; i++ { 70 go func(i int) { 71 target := makeTarget(fmt.Sprintf("//test_pkg:target%03d", i)) 72 aCache.Store(target, nil, fmt.Sprintf("file%03d", i), fmt.Sprintf("file%03d_2", i)) 73 wg.Done() 74 }(i) 75 } 76 wg.Wait() 77 aCache.Shutdown() 78 assert.Equal(t, n, len(mCache.stored)) 79 for target, stored := range mCache.stored { 80 assert.Equal(t, []string{ 81 "", 82 "file" + target.Label.Name[len(target.Label.Name)-3:], 83 "file" + target.Label.Name[len(target.Label.Name)-3:] + "_2", 84 }, stored) 85 } 86 } 87 88 // Fake cache implementation to ensure our async cache behaves itself. 89 type mockCache struct { 90 sync.Mutex 91 inFlight map[*core.BuildTarget]bool 92 completed map[*core.BuildTarget]bool 93 stored map[*core.BuildTarget][]string 94 } 95 96 func (c *mockCache) Store(target *core.BuildTarget, key []byte, files ...string) { 97 c.Lock() 98 if c.inFlight[target] { 99 panic("Concurrent store on " + target.Label.String()) 100 } 101 c.inFlight[target] = true 102 c.Unlock() 103 time.Sleep(10 * time.Millisecond) // Fake a small delay to mimic the real thing 104 c.Lock() 105 c.inFlight[target] = false 106 c.completed[target] = true 107 c.stored[target] = append(c.stored[target], "") 108 c.stored[target] = append(c.stored[target], files...) 109 c.Unlock() 110 } 111 112 func (c *mockCache) StoreExtra(target *core.BuildTarget, key []byte, file string) { 113 c.Store(target, key, file) 114 } 115 116 func (c *mockCache) Retrieve(target *core.BuildTarget, key []byte) bool { 117 c.Lock() 118 c.completed[target] = true 119 c.Unlock() 120 return false 121 } 122 123 func (c *mockCache) RetrieveExtra(target *core.BuildTarget, key []byte, file string) bool { 124 return c.Retrieve(target, key) 125 } 126 127 func (c *mockCache) Clean(target *core.BuildTarget) { 128 c.Retrieve(target, nil) 129 } 130 131 func (c *mockCache) CleanAll() {} 132 133 func (*mockCache) Shutdown() {} 134 135 func makeTarget(label string) *core.BuildTarget { 136 return core.NewBuildTarget(core.ParseBuildLabel(label, "")) 137 } 138 139 func makeCaches() (*mockCache, core.Cache) { 140 mCache := &mockCache{ 141 inFlight: make(map[*core.BuildTarget]bool), 142 completed: make(map[*core.BuildTarget]bool), 143 stored: make(map[*core.BuildTarget][]string), 144 } 145 config := core.DefaultConfiguration() 146 config.Cache.Workers = 10 147 return mCache, newAsyncCache(mCache, config) 148 }