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  }