github.com/filecoin-project/lassie@v0.23.0/pkg/storage/storage_test.go (about) 1 package storage 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 "io" 8 "os" 9 "testing" 10 11 "github.com/filecoin-project/lassie/pkg/types" 12 "github.com/ipfs/go-cid" 13 "github.com/ipld/go-ipld-prime" 14 cidlink "github.com/ipld/go-ipld-prime/linking/cid" 15 "github.com/stretchr/testify/require" 16 ) 17 18 func TestTempCarStorage(t *testing.T) { 19 // Testing both DeferredCarStorage and CachingTempStore here with just some 20 // additional pieces of logic to make sure the teeing version is actually 21 // teeing. 22 for _, teeing := range []bool{true, false} { 23 teeing := teeing 24 t.Run(fmt.Sprintf("teeing=%t", teeing), func(t *testing.T) { 25 t.Parallel() 26 ctx := context.Background() 27 testCid1, testData1 := randBlock() 28 testCid2, testData2 := randBlock() 29 testCid3, _ := randBlock() 30 31 tempDir := t.TempDir() 32 33 teeCollect := make(map[cid.Cid][]byte, 0) 34 var cw types.ReadableWritableStorage 35 if teeing { 36 bwo := func(ipld.LinkContext) (io.Writer, ipld.BlockWriteCommitter, error) { 37 var buf bytes.Buffer 38 return &buf, func(lnk ipld.Link) error { 39 teeCollect[lnk.(cidlink.Link).Cid] = buf.Bytes() 40 return nil 41 }, nil 42 } 43 cw = NewCachingTempStore(bwo, NewDeferredStorageCar(tempDir, testCid1)) 44 } else { 45 cw = NewDeferredStorageCar(tempDir, testCid1) 46 } 47 48 ents, err := os.ReadDir(tempDir) 49 require.NoError(t, err) 50 require.Len(t, ents, 0) 51 52 has, err := cw.Has(ctx, testCid3.KeyString()) 53 require.NoError(t, err) 54 require.False(t, has) 55 _, err = cw.Get(ctx, testCid1.KeyString()) 56 require.Error(t, err) 57 enf, ok := err.(interface{ NotFound() bool }) 58 require.True(t, ok) 59 require.True(t, enf.NotFound()) 60 _, err = cw.GetStream(ctx, testCid1.KeyString()) 61 require.Error(t, err) 62 enf, ok = err.(interface{ NotFound() bool }) 63 require.True(t, ok) 64 require.True(t, enf.NotFound()) 65 66 require.NoError(t, cw.Put(ctx, testCid1.KeyString(), testData1)) 67 has, err = cw.Has(ctx, testCid1.KeyString()) 68 require.NoError(t, err) 69 require.True(t, has) 70 got, err := cw.Get(ctx, testCid1.KeyString()) 71 require.NoError(t, err) 72 require.Equal(t, testData1, got) 73 gotStream, err := cw.GetStream(ctx, testCid1.KeyString()) 74 require.NoError(t, err) 75 got, err = io.ReadAll(gotStream) 76 require.NoError(t, err) 77 require.Equal(t, testData1, got) 78 require.NoError(t, cw.Put(ctx, testCid2.KeyString(), testData2)) 79 has, err = cw.Has(ctx, testCid1.KeyString()) 80 require.NoError(t, err) 81 require.True(t, has) 82 has, err = cw.Has(ctx, testCid2.KeyString()) 83 require.NoError(t, err) 84 require.True(t, has) 85 got, err = cw.Get(ctx, testCid2.KeyString()) 86 require.NoError(t, err) 87 require.Equal(t, testData2, got) 88 gotStream, err = cw.GetStream(ctx, testCid2.KeyString()) 89 require.NoError(t, err) 90 got, err = io.ReadAll(gotStream) 91 require.NoError(t, err) 92 require.Equal(t, testData2, got) 93 has, err = cw.Has(ctx, testCid3.KeyString()) 94 require.NoError(t, err) 95 require.False(t, has) 96 _, err = cw.Get(ctx, testCid3.KeyString()) 97 require.Error(t, err) 98 enf, ok = err.(interface{ NotFound() bool }) 99 require.True(t, ok) 100 require.True(t, enf.NotFound()) 101 102 ents, err = os.ReadDir(tempDir) 103 require.NoError(t, err) 104 require.Len(t, ents, 1) 105 require.Contains(t, ents[0].Name(), "carstorage") 106 stat, err := os.Stat(tempDir + "/" + ents[0].Name()) 107 require.NoError(t, err) 108 require.True(t, stat.Size() > int64(len(testData1)+len(testData2))) 109 110 closer, ok := cw.(io.Closer) 111 require.True(t, ok) 112 require.NoError(t, closer.Close()) 113 114 // should be deleted 115 ents, err = os.ReadDir(tempDir) 116 require.NoError(t, err) 117 require.Len(t, ents, 0) 118 119 if teeing { 120 require.Len(t, teeCollect, 2) 121 require.Equal(t, testData1, teeCollect[testCid1]) 122 require.Equal(t, testData2, teeCollect[testCid2]) 123 } 124 }) 125 } 126 } 127 128 type blk struct { 129 cid cid.Cid 130 data []byte 131 } 132 133 func TestPreloadStore(t *testing.T) { 134 ctx := context.Background() 135 136 td := make([]blk, 0, 10) 137 for i := 0; i < 10; i++ { 138 c, d := randBlock() 139 td = append(td, blk{c, d}) 140 } 141 142 bwoCnt := 0 143 bwo := func(ipld.LinkContext) (io.Writer, ipld.BlockWriteCommitter, error) { 144 var buf bytes.Buffer 145 return &buf, func(lnk ipld.Link) error { 146 c := lnk.(cidlink.Link).Cid 147 if bwoCnt >= len(td) { 148 require.Fail(t, "too many calls to bwo") 149 } else { 150 require.Equal(t, td[bwoCnt].cid, c) 151 require.Equal(t, td[bwoCnt].data, buf.Bytes()) 152 } 153 bwoCnt++ 154 return nil 155 }, nil 156 } 157 mainStore := NewCachingTempStore(bwo, NewDeferredStorageCar(t.TempDir(), td[0].cid)) 158 t.Cleanup(func() { 159 require.NoError(t, mainStore.Close()) 160 }) 161 preload := mainStore.PreloadStore() 162 163 checkNotHas := func(blks []blk, stores ...types.ReadableWritableStorage) { 164 for _, d := range blks { 165 for _, s := range stores { 166 has, err := s.Has(ctx, d.cid.KeyString()) 167 require.NoError(t, err) 168 require.False(t, has) 169 _, err = s.Get(ctx, d.cid.KeyString()) 170 require.Error(t, err) 171 enf, ok := err.(interface{ NotFound() bool }) 172 require.True(t, ok) 173 require.True(t, enf.NotFound()) 174 _, err = s.GetStream(ctx, d.cid.KeyString()) 175 require.Error(t, err) 176 enf, ok = err.(interface{ NotFound() bool }) 177 require.True(t, ok) 178 require.True(t, enf.NotFound()) 179 } 180 } 181 } 182 183 checkHas := func(blks []blk, stores ...types.ReadableWritableStorage) { 184 for _, d := range blks { 185 for _, s := range stores { 186 has, err := s.Has(ctx, d.cid.KeyString()) 187 require.NoError(t, err) 188 require.True(t, has) 189 got, err := s.Get(ctx, d.cid.KeyString()) 190 require.NoError(t, err) 191 require.Equal(t, d.data, got) 192 gotStream, err := s.GetStream(ctx, d.cid.KeyString()) 193 require.NoError(t, err) 194 got, err = io.ReadAll(gotStream) 195 require.NoError(t, err) 196 require.Equal(t, d.data, got) 197 } 198 } 199 } 200 201 checkNotHas(td, mainStore, preload) 202 mainStore.Put(ctx, td[0].cid.KeyString(), td[0].data) 203 checkNotHas(td, preload) 204 checkNotHas(td[1:], mainStore) 205 checkHas(td[:1], mainStore) 206 for i := 5; i >= 1; i-- { // out of order, partial preload 207 preload.Put(ctx, td[i].cid.KeyString(), td[i].data) 208 } 209 checkNotHas(td[1:], mainStore) 210 checkNotHas(td[:1], preload) 211 checkHas(td[1:6], preload) 212 checkNotHas(td[6:], preload) 213 for _, d := range td[1:] { // in order, complete 214 mainStore.Put(ctx, d.cid.KeyString(), d.data) 215 } 216 checkHas(td, mainStore) 217 checkNotHas(td, preload) 218 }