github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbfs/libkbfs/block_disk_store_test.go (about) 1 // Copyright 2016 Keybase Inc. All rights reserved. 2 // Use of this source code is governed by a BSD 3 // license that can be found in the LICENSE file. 4 5 package libkbfs 6 7 import ( 8 "context" 9 "os" 10 "path/filepath" 11 "testing" 12 13 "github.com/keybase/client/go/kbfs/ioutil" 14 "github.com/keybase/client/go/kbfs/kbfsblock" 15 "github.com/keybase/client/go/kbfs/kbfscodec" 16 "github.com/keybase/client/go/kbfs/kbfscrypto" 17 "github.com/keybase/client/go/protocol/keybase1" 18 "github.com/stretchr/testify/assert" 19 "github.com/stretchr/testify/require" 20 ) 21 22 func setupBlockDiskStoreTest(t *testing.T) (tempdir string, s *blockDiskStore) { 23 codec := kbfscodec.NewMsgpack() 24 25 tempdir, err := ioutil.TempDir(os.TempDir(), "block_disk_store") 26 require.NoError(t, err) 27 28 s = makeBlockDiskStore(codec, tempdir) 29 return tempdir, s 30 } 31 32 func teardownBlockDiskStoreTest(t *testing.T, tempdir string) { 33 err := ioutil.RemoveAll(tempdir) 34 assert.NoError(t, err) 35 } 36 37 func putBlockDisk( 38 ctx context.Context, t *testing.T, s *blockDiskStore, data []byte) ( 39 kbfsblock.ID, kbfsblock.Context, kbfscrypto.BlockCryptKeyServerHalf) { 40 bID, err := kbfsblock.MakePermanentID( 41 data, kbfscrypto.EncryptionSecretboxWithKeyNonce) 42 require.NoError(t, err) 43 44 uid1 := keybase1.MakeTestUID(1) 45 bCtx := kbfsblock.MakeFirstContext( 46 uid1.AsUserOrTeam(), keybase1.BlockType_DATA) 47 serverHalf, err := kbfscrypto.MakeRandomBlockCryptKeyServerHalf() 48 require.NoError(t, err) 49 50 didPut, err := s.put(ctx, true, bID, bCtx, data, serverHalf) 51 require.NoError(t, err) 52 err = s.addReference(ctx, bID, bCtx, "tag") 53 require.NoError(t, err) 54 require.True(t, didPut) 55 56 return bID, bCtx, serverHalf 57 } 58 59 func addBlockDiskRef( 60 ctx context.Context, t *testing.T, s *blockDiskStore, 61 bID kbfsblock.ID) kbfsblock.Context { 62 nonce, err := kbfsblock.MakeRefNonce() 63 require.NoError(t, err) 64 65 uid1 := keybase1.MakeTestUID(1) 66 uid2 := keybase1.MakeTestUID(2) 67 bCtx2 := kbfsblock.MakeContext( 68 uid1.AsUserOrTeam(), uid2.AsUserOrTeam(), nonce, 69 keybase1.BlockType_DATA) 70 err = s.addReference(ctx, bID, bCtx2, "") 71 require.NoError(t, err) 72 return bCtx2 73 } 74 75 func getAndCheckBlockDiskData( 76 ctx context.Context, t *testing.T, s *blockDiskStore, 77 bID kbfsblock.ID, bCtx kbfsblock.Context, expectedData []byte, 78 expectedServerHalf kbfscrypto.BlockCryptKeyServerHalf) { 79 data, serverHalf, err := s.getDataWithContext(ctx, bID, bCtx) 80 require.NoError(t, err) 81 require.Equal(t, expectedData, data) 82 require.Equal(t, expectedServerHalf, serverHalf) 83 } 84 85 func TestBlockDiskStoreBasic(t *testing.T) { 86 tempdir, s := setupBlockDiskStoreTest(t) 87 defer teardownBlockDiskStoreTest(t, tempdir) 88 ctx := context.Background() 89 90 // Put the block. 91 data := []byte{1, 2, 3, 4} 92 bID, bCtx, serverHalf := putBlockDisk(ctx, t, s, data) 93 94 // Make sure we get the same block back. 95 getAndCheckBlockDiskData(ctx, t, s, bID, bCtx, data, serverHalf) 96 97 // Add a reference. 98 bCtx2 := addBlockDiskRef(ctx, t, s, bID) 99 100 // Make sure we get the same block via that reference. 101 getAndCheckBlockDiskData(ctx, t, s, bID, bCtx2, data, serverHalf) 102 103 // Shutdown and restart. 104 s = makeBlockDiskStore(s.codec, tempdir) 105 106 // Make sure we get the same block for both refs. 107 108 getAndCheckBlockDiskData(ctx, t, s, bID, bCtx, data, serverHalf) 109 getAndCheckBlockDiskData(ctx, t, s, bID, bCtx2, data, serverHalf) 110 } 111 112 func TestBlockDiskStoreAddReference(t *testing.T) { 113 tempdir, s := setupBlockDiskStoreTest(t) 114 defer teardownBlockDiskStoreTest(t, tempdir) 115 ctx := context.Background() 116 117 data := []byte{1, 2, 3, 4} 118 bID, err := kbfsblock.MakePermanentID( 119 data, kbfscrypto.EncryptionSecretboxWithKeyNonce) 120 require.NoError(t, err) 121 122 // Add a reference, which should succeed. 123 bCtx := addBlockDiskRef(ctx, t, s, bID) 124 125 // Of course, the block get should still fail. 126 _, _, err = s.getDataWithContext(ctx, bID, bCtx) 127 require.Equal(t, blockNonExistentError{bID}, err) 128 } 129 130 func TestBlockDiskStoreArchiveReferences(t *testing.T) { 131 tempdir, s := setupBlockDiskStoreTest(t) 132 defer teardownBlockDiskStoreTest(t, tempdir) 133 ctx := context.Background() 134 135 // Put the block. 136 data := []byte{1, 2, 3, 4} 137 bID, bCtx, serverHalf := putBlockDisk(ctx, t, s, data) 138 139 // Add a reference. 140 bCtx2 := addBlockDiskRef(ctx, t, s, bID) 141 142 // Archive references. 143 err := s.archiveReferences( 144 ctx, kbfsblock.ContextMap{bID: {bCtx, bCtx2}}, "") 145 require.NoError(t, err) 146 147 // Get block should still succeed. 148 getAndCheckBlockDiskData(ctx, t, s, bID, bCtx, data, serverHalf) 149 } 150 151 func TestBlockDiskStoreArchiveNonExistentReference(t *testing.T) { 152 tempdir, s := setupBlockDiskStoreTest(t) 153 defer teardownBlockDiskStoreTest(t, tempdir) 154 ctx := context.Background() 155 156 uid1 := keybase1.MakeTestUID(1) 157 158 bCtx := kbfsblock.MakeFirstContext( 159 uid1.AsUserOrTeam(), keybase1.BlockType_DATA) 160 161 data := []byte{1, 2, 3, 4} 162 bID, err := kbfsblock.MakePermanentID( 163 data, kbfscrypto.EncryptionSecretboxWithKeyNonce) 164 require.NoError(t, err) 165 166 // Archive references. 167 err = s.archiveReferences(ctx, kbfsblock.ContextMap{bID: {bCtx}}, "") 168 require.NoError(t, err) 169 } 170 171 func TestBlockDiskStoreRemoveReferences(t *testing.T) { 172 tempdir, s := setupBlockDiskStoreTest(t) 173 defer teardownBlockDiskStoreTest(t, tempdir) 174 ctx := context.Background() 175 176 // Put the block. 177 data := []byte{1, 2, 3, 4} 178 bID, bCtx, serverHalf := putBlockDisk(ctx, t, s, data) 179 180 // Add a reference. 181 bCtx2 := addBlockDiskRef(ctx, t, s, bID) 182 183 // Remove references. 184 liveCount, err := s.removeReferences( 185 ctx, bID, []kbfsblock.Context{bCtx, bCtx2}, "") 186 require.NoError(t, err) 187 require.Equal(t, 0, liveCount) 188 189 // Make sure the block data is inaccessible. 190 _, _, err = s.getDataWithContext(ctx, bID, bCtx) 191 require.Equal(t, blockNonExistentError{bID}, err) 192 193 // But the actual data should remain. 194 buf, half, err := s.getData(ctx, bID) 195 require.NoError(t, err) 196 require.Equal(t, data, buf) 197 require.Equal(t, serverHalf, half) 198 } 199 200 func TestBlockDiskStoreRemove(t *testing.T) { 201 tempdir, s := setupBlockDiskStoreTest(t) 202 defer teardownBlockDiskStoreTest(t, tempdir) 203 ctx := context.Background() 204 205 // Put the block. 206 data := []byte{1, 2, 3, 4} 207 bID, bCtx, _ := putBlockDisk(ctx, t, s, data) 208 209 // Should not be removable. 210 err := s.remove(ctx, bID) 211 require.Error(t, err, "Trying to remove data") 212 213 // Remove reference. 214 liveCount, err := s.removeReferences( 215 ctx, bID, []kbfsblock.Context{bCtx}, "") 216 require.NoError(t, err) 217 require.Equal(t, 0, liveCount) 218 219 // Should now be removable. 220 err = s.remove(ctx, bID) 221 require.NoError(t, err) 222 223 _, _, err = s.getData(ctx, bID) 224 require.Equal(t, blockNonExistentError{bID}, err) 225 226 err = filepath.Walk(s.dir, 227 func(path string, info os.FileInfo, _ error) error { 228 // We should only find the blocks directory here. 229 if path != s.dir { 230 t.Errorf("Found unexpected block path: %s", path) 231 } 232 return nil 233 }) 234 require.NoError(t, err) 235 }