1package fscache // import "github.com/docker/docker/builder/fscache" 2 3import ( 4 "context" 5 "io/ioutil" 6 "os" 7 "path/filepath" 8 "testing" 9 "time" 10 11 "github.com/moby/buildkit/session/filesync" 12 "gotest.tools/assert" 13 is "gotest.tools/assert/cmp" 14) 15 16func TestFSCache(t *testing.T) { 17 tmpDir, err := ioutil.TempDir("", "fscache") 18 assert.Check(t, err) 19 defer os.RemoveAll(tmpDir) 20 21 backend := NewNaiveCacheBackend(filepath.Join(tmpDir, "backend")) 22 23 opt := Opt{ 24 Root: tmpDir, 25 Backend: backend, 26 GCPolicy: GCPolicy{MaxSize: 15, MaxKeepDuration: time.Hour}, 27 } 28 29 fscache, err := NewFSCache(opt) 30 assert.Check(t, err) 31 32 defer fscache.Close() 33 34 err = fscache.RegisterTransport("test", &testTransport{}) 35 assert.Check(t, err) 36 37 src1, err := fscache.SyncFrom(context.TODO(), &testIdentifier{"foo", "data", "bar"}) 38 assert.Check(t, err) 39 40 dt, err := ioutil.ReadFile(filepath.Join(src1.Root().Path(), "foo")) 41 assert.Check(t, err) 42 assert.Check(t, is.Equal(string(dt), "data")) 43 44 // same id doesn't recalculate anything 45 src2, err := fscache.SyncFrom(context.TODO(), &testIdentifier{"foo", "data2", "bar"}) 46 assert.Check(t, err) 47 assert.Check(t, is.Equal(src1.Root().Path(), src2.Root().Path())) 48 49 dt, err = ioutil.ReadFile(filepath.Join(src1.Root().Path(), "foo")) 50 assert.Check(t, err) 51 assert.Check(t, is.Equal(string(dt), "data")) 52 assert.Check(t, src2.Close()) 53 54 src3, err := fscache.SyncFrom(context.TODO(), &testIdentifier{"foo2", "data2", "bar"}) 55 assert.Check(t, err) 56 assert.Check(t, src1.Root().Path() != src3.Root().Path()) 57 58 dt, err = ioutil.ReadFile(filepath.Join(src3.Root().Path(), "foo2")) 59 assert.Check(t, err) 60 assert.Check(t, is.Equal(string(dt), "data2")) 61 62 s, err := fscache.DiskUsage(context.TODO()) 63 assert.Check(t, err) 64 assert.Check(t, is.Equal(s, int64(0))) 65 66 assert.Check(t, src3.Close()) 67 68 s, err = fscache.DiskUsage(context.TODO()) 69 assert.Check(t, err) 70 assert.Check(t, is.Equal(s, int64(5))) 71 72 // new upload with the same shared key shoutl overwrite 73 src4, err := fscache.SyncFrom(context.TODO(), &testIdentifier{"foo3", "data3", "bar"}) 74 assert.Check(t, err) 75 assert.Check(t, src1.Root().Path() != src3.Root().Path()) 76 77 dt, err = ioutil.ReadFile(filepath.Join(src3.Root().Path(), "foo3")) 78 assert.Check(t, err) 79 assert.Check(t, is.Equal(string(dt), "data3")) 80 assert.Check(t, is.Equal(src4.Root().Path(), src3.Root().Path())) 81 assert.Check(t, src4.Close()) 82 83 s, err = fscache.DiskUsage(context.TODO()) 84 assert.Check(t, err) 85 assert.Check(t, is.Equal(s, int64(10))) 86 87 // this one goes over the GC limit 88 src5, err := fscache.SyncFrom(context.TODO(), &testIdentifier{"foo4", "datadata", "baz"}) 89 assert.Check(t, err) 90 assert.Check(t, src5.Close()) 91 92 // GC happens async 93 time.Sleep(100 * time.Millisecond) 94 95 // only last insertion after GC 96 s, err = fscache.DiskUsage(context.TODO()) 97 assert.Check(t, err) 98 assert.Check(t, is.Equal(s, int64(8))) 99 100 // prune deletes everything 101 released, err := fscache.Prune(context.TODO()) 102 assert.Check(t, err) 103 assert.Check(t, is.Equal(released, uint64(8))) 104 105 s, err = fscache.DiskUsage(context.TODO()) 106 assert.Check(t, err) 107 assert.Check(t, is.Equal(s, int64(0))) 108} 109 110type testTransport struct { 111} 112 113func (t *testTransport) Copy(ctx context.Context, id RemoteIdentifier, dest string, cs filesync.CacheUpdater) error { 114 testid := id.(*testIdentifier) 115 return ioutil.WriteFile(filepath.Join(dest, testid.filename), []byte(testid.data), 0600) 116} 117 118type testIdentifier struct { 119 filename string 120 data string 121 sharedKey string 122} 123 124func (t *testIdentifier) Key() string { 125 return t.filename 126} 127func (t *testIdentifier) SharedKey() string { 128 return t.sharedKey 129} 130func (t *testIdentifier) Transport() string { 131 return "test" 132} 133