github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbfs/libkbfs/md_journal_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  	"errors"
     9  	"fmt"
    10  	"os"
    11  	"path/filepath"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/keybase/client/go/kbfs/data"
    16  	"github.com/keybase/client/go/kbfs/idutil"
    17  	idutiltest "github.com/keybase/client/go/kbfs/idutil/test"
    18  	"github.com/keybase/client/go/kbfs/ioutil"
    19  	"github.com/keybase/client/go/kbfs/kbfscodec"
    20  	"github.com/keybase/client/go/kbfs/kbfscrypto"
    21  	"github.com/keybase/client/go/kbfs/kbfsmd"
    22  	"github.com/keybase/client/go/kbfs/libkey"
    23  	"github.com/keybase/client/go/kbfs/tlf"
    24  	"github.com/keybase/client/go/kbfs/tlfhandle"
    25  	"github.com/keybase/client/go/logger"
    26  	"github.com/keybase/client/go/protocol/keybase1"
    27  	"github.com/stretchr/testify/assert"
    28  	"github.com/stretchr/testify/require"
    29  	"golang.org/x/net/context"
    30  )
    31  
    32  type singleEncryptionKeyGetter struct {
    33  	k kbfscrypto.TLFCryptKey
    34  }
    35  
    36  func (g singleEncryptionKeyGetter) GetTLFCryptKeyForEncryption(
    37  	ctx context.Context, kmd libkey.KeyMetadata) (kbfscrypto.TLFCryptKey, error) {
    38  	return g.k, nil
    39  }
    40  
    41  func (g singleEncryptionKeyGetter) GetTLFCryptKeyForMDDecryption(
    42  	ctx context.Context, kmdToDecrypt, kmdWithKeys libkey.KeyMetadata) (
    43  	kbfscrypto.TLFCryptKey, error) {
    44  	return g.k, nil
    45  }
    46  
    47  func (g singleEncryptionKeyGetter) GetFirstTLFCryptKey(
    48  	ctx context.Context, kmd libkey.KeyMetadata) (
    49  	kbfscrypto.TLFCryptKey, error) {
    50  	return g.k, nil
    51  }
    52  
    53  func setupMDJournalTest(t testing.TB, ver kbfsmd.MetadataVer) (
    54  	codec kbfscodec.Codec, crypto CryptoCommon, tlfID tlf.ID,
    55  	signer kbfscrypto.Signer, ekg singleEncryptionKeyGetter,
    56  	bsplit data.BlockSplitter, tempdir string, j *mdJournal) {
    57  	codec = kbfscodec.NewMsgpack()
    58  	crypto = MakeCryptoCommon(codec, makeBlockCryptV1())
    59  
    60  	uid := keybase1.MakeTestUID(1)
    61  	tlfID = tlf.FakeID(1, tlf.Private)
    62  
    63  	signingKey := kbfscrypto.MakeFakeSigningKeyOrBust("fake seed")
    64  	signer = kbfscrypto.SigningKeySigner{Key: signingKey}
    65  	verifyingKey := signingKey.GetVerifyingKey()
    66  	ekg = singleEncryptionKeyGetter{
    67  		kbfscrypto.MakeTLFCryptKey([32]byte{0x1}),
    68  	}
    69  
    70  	tempdir, err := ioutil.TempDir(os.TempDir(), "md_journal")
    71  	require.NoError(t, err)
    72  
    73  	// Clean up the tempdir if the rest of the setup fails.
    74  	setupSucceeded := false
    75  	defer func() {
    76  		if !setupSucceeded {
    77  			err := ioutil.RemoveAll(tempdir)
    78  			assert.NoError(t, err)
    79  		}
    80  	}()
    81  
    82  	log := logger.NewTestLogger(t)
    83  	ctx := context.Background()
    84  	j, err = makeMDJournal(
    85  		ctx, uid, verifyingKey, codec, crypto, data.WallClock{}, nil,
    86  		&testSyncedTlfGetterSetter{}, tlfID, ver, tempdir, log, tlf.NullID)
    87  	require.NoError(t, err)
    88  
    89  	bsplit, err = data.NewBlockSplitterSimpleExact(
    90  		64*1024, int(64*1024/data.BPSize), 8*1024)
    91  	require.NoError(t, err)
    92  
    93  	return codec, crypto, tlfID, signer, ekg, bsplit, tempdir, j
    94  }
    95  
    96  func teardownMDJournalTest(t testing.TB, tempdir string) {
    97  	err := ioutil.RemoveAll(tempdir)
    98  	assert.NoError(t, err)
    99  }
   100  
   101  func makeMDForTest(t testing.TB, ver kbfsmd.MetadataVer, tlfID tlf.ID,
   102  	revision kbfsmd.Revision, uid keybase1.UID,
   103  	signer kbfscrypto.Signer, prevRoot kbfsmd.ID) *RootMetadata {
   104  	nug := idutiltest.NormalizedUsernameGetter{
   105  		uid.AsUserOrTeam(): "fake_username",
   106  	}
   107  	bh, err := tlf.MakeHandle(
   108  		[]keybase1.UserOrTeamID{uid.AsUserOrTeam()}, nil, nil, nil, nil)
   109  	require.NoError(t, err)
   110  	h, err := tlfhandle.MakeHandle(
   111  		context.Background(), bh, bh.Type(), nil, nug, nil,
   112  		keybase1.OfflineAvailability_NONE)
   113  	require.NoError(t, err)
   114  	md, err := makeInitialRootMetadata(ver, tlfID, h)
   115  	require.NoError(t, err)
   116  	md.SetRevision(revision)
   117  	md.fakeInitialRekey()
   118  	md.SetPrevRoot(prevRoot)
   119  	md.SetDiskUsage(500)
   120  	return md
   121  }
   122  
   123  type constMerkleRootGetter struct{}
   124  
   125  var _ idutil.MerkleRootGetter = constMerkleRootGetter{}
   126  
   127  func (cmrg constMerkleRootGetter) GetCurrentMerkleRoot(
   128  	ctx context.Context) (keybase1.MerkleRootV2, time.Time, error) {
   129  	return keybase1.MerkleRootV2{}, time.Time{}, nil
   130  }
   131  
   132  func (cmrg constMerkleRootGetter) VerifyMerkleRoot(
   133  	_ context.Context, _ keybase1.MerkleRootV2, _ keybase1.KBFSRoot) error {
   134  	return nil
   135  }
   136  
   137  func putMDRangeHelper(t testing.TB, ver kbfsmd.MetadataVer, tlfID tlf.ID,
   138  	signer kbfscrypto.Signer, firstRevision kbfsmd.Revision,
   139  	firstPrevRoot kbfsmd.ID, mdCount int, uid keybase1.UID,
   140  	putMD func(context.Context, *RootMetadata) (kbfsmd.ID, error)) (
   141  	[]*RootMetadata, kbfsmd.ID) {
   142  	require.True(t, mdCount > 0)
   143  	ctx := context.Background()
   144  	var mds []*RootMetadata
   145  	md := makeMDForTest(
   146  		t, ver, tlfID, firstRevision, uid, signer, firstPrevRoot)
   147  	mdID, err := putMD(ctx, md)
   148  	require.NoError(t, err)
   149  	mds = append(mds, md)
   150  	codec := kbfscodec.NewMsgpack()
   151  	prevRoot := mdID
   152  	for i := 1; i < mdCount; i++ {
   153  		md, err = md.MakeSuccessor(ctx, ver, codec,
   154  			nil, constMerkleRootGetter{}, nil, nil, prevRoot, true)
   155  		require.NoError(t, err)
   156  		mdID, err := putMD(ctx, md)
   157  		require.NoError(t, err)
   158  		mds = append(mds, md)
   159  		prevRoot = mdID
   160  	}
   161  	return mds, prevRoot
   162  }
   163  
   164  func putMDRange(t testing.TB, ver kbfsmd.MetadataVer, tlfID tlf.ID,
   165  	signer kbfscrypto.Signer, ekg encryptionKeyGetter,
   166  	bsplit data.BlockSplitter, firstRevision kbfsmd.Revision,
   167  	firstPrevRoot kbfsmd.ID, mdCount int, j *mdJournal) ([]*RootMetadata, kbfsmd.ID) {
   168  	return putMDRangeHelper(t, ver, tlfID, signer, firstRevision,
   169  		firstPrevRoot, mdCount, j.uid,
   170  		func(ctx context.Context, md *RootMetadata) (kbfsmd.ID, error) {
   171  			mdID, _, err := j.put(ctx, signer, ekg, bsplit, md, false)
   172  			return mdID, err
   173  		})
   174  }
   175  
   176  func checkBRMD(t *testing.T, uid keybase1.UID, key kbfscrypto.VerifyingKey,
   177  	codec kbfscodec.Codec, brmd kbfsmd.RootMetadata,
   178  	extra kbfsmd.ExtraMetadata, expectedRevision kbfsmd.Revision,
   179  	expectedPrevRoot kbfsmd.ID, expectedMergeStatus kbfsmd.MergeStatus,
   180  	expectedBranchID kbfsmd.BranchID) {
   181  	require.Equal(t, expectedRevision, brmd.RevisionNumber())
   182  	require.Equal(t, expectedPrevRoot, brmd.GetPrevRoot())
   183  	require.Equal(t, expectedMergeStatus, brmd.MergedStatus())
   184  	err := brmd.IsValidAndSigned(
   185  		context.Background(), codec, nil, extra, key,
   186  		keybase1.OfflineAvailability_NONE)
   187  	require.NoError(t, err)
   188  	err = brmd.IsLastModifiedBy(uid, key)
   189  	require.NoError(t, err)
   190  
   191  	require.Equal(t, expectedMergeStatus == kbfsmd.Merged,
   192  		expectedBranchID == kbfsmd.NullBranchID)
   193  	require.Equal(t, expectedBranchID, brmd.BID())
   194  }
   195  
   196  func checkIBRMDRange(t *testing.T, uid keybase1.UID,
   197  	key kbfscrypto.VerifyingKey, codec kbfscodec.Codec,
   198  	ibrmds []ImmutableBareRootMetadata, firstRevision kbfsmd.Revision,
   199  	firstPrevRoot kbfsmd.ID, mStatus kbfsmd.MergeStatus, bid kbfsmd.BranchID) {
   200  	checkBRMD(t, uid, key, codec, ibrmds[0], ibrmds[0].extra,
   201  		firstRevision, firstPrevRoot, mStatus, bid)
   202  
   203  	for i := 1; i < len(ibrmds); i++ {
   204  		prevID := ibrmds[i-1].mdID
   205  		checkBRMD(t, uid, key, codec, ibrmds[i],
   206  			ibrmds[i].extra, firstRevision+kbfsmd.Revision(i),
   207  			prevID, mStatus, bid)
   208  		err := ibrmds[i-1].CheckValidSuccessor(prevID, ibrmds[i])
   209  		require.NoError(t, err)
   210  	}
   211  }
   212  
   213  // noLogTB is an implementation of testing.TB that squelches all logs
   214  // (for benchmarks).
   215  type noLogTB struct {
   216  	testing.TB
   217  }
   218  
   219  func (tb noLogTB) Log(args ...interface{}) {}
   220  
   221  func (tb noLogTB) Logf(format string, args ...interface{}) {}
   222  
   223  func BenchmarkMDJournalBasic(b *testing.B) {
   224  	runBenchmarkOverMetadataVers(b, benchmarkMDJournalBasic)
   225  }
   226  
   227  func benchmarkMDJournalBasicBody(b *testing.B, ver kbfsmd.MetadataVer, mdCount int) {
   228  	b.StopTimer()
   229  
   230  	_, _, id, signer, ekg, bsplit, tempdir, j :=
   231  		setupMDJournalTest(noLogTB{b}, ver)
   232  	defer teardownMDJournalTest(b, tempdir)
   233  
   234  	putMDRangeHelper(b, ver, id, signer, kbfsmd.Revision(10),
   235  		kbfsmd.FakeID(1), mdCount, j.uid,
   236  		func(ctx context.Context, md *RootMetadata) (kbfsmd.ID, error) {
   237  			b.StartTimer()
   238  			defer b.StopTimer()
   239  			mdID, _, err := j.put(ctx, signer, ekg, bsplit, md, false)
   240  			return mdID, err
   241  		})
   242  }
   243  
   244  func benchmarkMDJournalBasic(b *testing.B, ver kbfsmd.MetadataVer) {
   245  	for _, mdCount := range []int{1, 10, 100, 1000, 10000} {
   246  		mdCount := mdCount // capture range variable.
   247  		name := fmt.Sprintf("mdCount=%d", mdCount)
   248  		b.Run(name, func(b *testing.B) {
   249  			b.StopTimer()
   250  			b.ResetTimer()
   251  			for i := 0; i < b.N; i++ {
   252  				benchmarkMDJournalBasicBody(b, ver, mdCount)
   253  			}
   254  		})
   255  	}
   256  }
   257  
   258  func testMDJournalBasic(t *testing.T, ver kbfsmd.MetadataVer) {
   259  	codec, _, id, signer, ekg, bsplit, tempdir, j :=
   260  		setupMDJournalTest(t, ver)
   261  	defer teardownMDJournalTest(t, tempdir)
   262  
   263  	// Should start off as empty.
   264  
   265  	ctx := context.Background()
   266  	head, err := j.getHead(ctx, kbfsmd.NullBranchID)
   267  	require.NoError(t, err)
   268  	require.Equal(t, ImmutableBareRootMetadata{}, head)
   269  	require.Equal(t, uint64(0), j.length())
   270  
   271  	// Push some new metadata blocks.
   272  
   273  	firstRevision := kbfsmd.Revision(10)
   274  	firstPrevRoot := kbfsmd.FakeID(1)
   275  	mdCount := 10
   276  	mds, _ := putMDRange(t, ver, id, signer, ekg, bsplit,
   277  		firstRevision, firstPrevRoot, mdCount, j)
   278  
   279  	require.Equal(t, mdCount, len(mds))
   280  	require.Equal(t, uint64(mdCount), j.length())
   281  
   282  	// Should now be non-empty.
   283  	ibrmds, err := j.getRange(
   284  		ctx, kbfsmd.NullBranchID, 1, firstRevision+kbfsmd.Revision(2*mdCount))
   285  	require.NoError(t, err)
   286  	require.Equal(t, mdCount, len(ibrmds))
   287  
   288  	checkIBRMDRange(t, j.uid, j.key, codec,
   289  		ibrmds, firstRevision, firstPrevRoot, kbfsmd.Merged, kbfsmd.NullBranchID)
   290  
   291  	head, err = j.getHead(ctx, kbfsmd.NullBranchID)
   292  	require.NoError(t, err)
   293  	require.Equal(t, ibrmds[len(ibrmds)-1], head)
   294  
   295  	for i := 0; i < mdCount; i++ {
   296  		require.Equal(t, mds[i].bareMd, ibrmds[i].RootMetadata, "i=%d", i)
   297  		require.Equal(t, mds[i].extra, ibrmds[i].extra, "i=%d", i)
   298  	}
   299  }
   300  
   301  func testMDJournalGetNextEntry(t *testing.T, ver kbfsmd.MetadataVer) {
   302  	_, _, id, signer, ekg, bsplit, tempdir, j := setupMDJournalTest(t, ver)
   303  	defer teardownMDJournalTest(t, tempdir)
   304  
   305  	ctx := context.Background()
   306  	md := makeMDForTest(t, ver, id, kbfsmd.Revision(10), j.uid, signer, kbfsmd.FakeID(1))
   307  	_, journalID, err := j.put(ctx, signer, ekg, bsplit, md, false)
   308  	require.NoError(t, err)
   309  
   310  	mdID, rmds, _, err := j.getNextEntryToFlush(ctx, md.Revision(), signer)
   311  	require.NoError(t, err)
   312  	require.Equal(t, kbfsmd.ID{}, mdID)
   313  	require.Nil(t, rmds)
   314  
   315  	mdID, rmds, _, err = j.getNextEntryToFlush(ctx, md.Revision()+1, signer)
   316  	require.NoError(t, err)
   317  	require.Equal(t, journalID, mdID)
   318  	require.Equal(t, md.bareMd, rmds.MD)
   319  
   320  	mdID, rmds, _, err = j.getNextEntryToFlush(
   321  		ctx, md.Revision()+100, signer)
   322  	require.NoError(t, err)
   323  	require.Equal(t, journalID, mdID)
   324  	require.Equal(t, md.bareMd, rmds.MD)
   325  }
   326  
   327  // Putting the same md twice should return the same MD ID.  Regression
   328  // for KBFS-1955.
   329  func testMDJournalPutEntryTwice(t *testing.T, ver kbfsmd.MetadataVer) {
   330  	_, _, id, signer, ekg, bsplit, tempdir, j := setupMDJournalTest(t, ver)
   331  	defer teardownMDJournalTest(t, tempdir)
   332  
   333  	ctx := context.Background()
   334  	md := makeMDForTest(t, ver, id, kbfsmd.Revision(10), j.uid, signer,
   335  		kbfsmd.FakeID(1))
   336  	id1, _, err := j.put(ctx, signer, ekg, bsplit, md, false)
   337  	require.NoError(t, err)
   338  
   339  	id2, err := j.putMD(md.bareMd)
   340  	require.NoError(t, err)
   341  
   342  	require.Equal(t, id1, id2)
   343  }
   344  
   345  func testMDJournalPutCase1Empty(t *testing.T, ver kbfsmd.MetadataVer) {
   346  	_, _, id, signer, ekg, bsplit, tempdir, j := setupMDJournalTest(t, ver)
   347  	defer teardownMDJournalTest(t, tempdir)
   348  
   349  	ctx := context.Background()
   350  	md := makeMDForTest(t, ver, id, kbfsmd.Revision(10), j.uid, signer, kbfsmd.FakeID(1))
   351  	_, _, err := j.put(ctx, signer, ekg, bsplit, md, false)
   352  	require.NoError(t, err)
   353  
   354  	head, err := j.getHead(ctx, kbfsmd.NullBranchID)
   355  	require.NoError(t, err)
   356  	require.Equal(t, md.bareMd, head.RootMetadata)
   357  	require.Equal(t, md.extra, head.extra)
   358  }
   359  
   360  func testMDJournalPutCase1Conflict(t *testing.T, ver kbfsmd.MetadataVer) {
   361  	_, _, id, signer, ekg, bsplit, tempdir, j := setupMDJournalTest(t, ver)
   362  	defer teardownMDJournalTest(t, tempdir)
   363  
   364  	ctx := context.Background()
   365  	md := makeMDForTest(t, ver, id, kbfsmd.Revision(10), j.uid, signer, kbfsmd.FakeID(1))
   366  	_, _, err := j.put(ctx, signer, ekg, bsplit, md, false)
   367  	require.NoError(t, err)
   368  
   369  	err = j.convertToBranch(
   370  		ctx, kbfsmd.PendingLocalSquashBranchID, signer, kbfscodec.NewMsgpack(),
   371  		id, NewMDCacheStandard(10))
   372  	require.NoError(t, err)
   373  
   374  	_, _, err = j.put(ctx, signer, ekg, bsplit, md, false)
   375  	require.Equal(t, MDJournalConflictError{}, err)
   376  }
   377  
   378  // The append portion of case 1 is covered by TestMDJournalBasic.
   379  
   380  func testMDJournalPutCase1ReplaceHead(t *testing.T, ver kbfsmd.MetadataVer) {
   381  	_, _, id, signer, ekg, bsplit, tempdir, j := setupMDJournalTest(t, ver)
   382  	defer teardownMDJournalTest(t, tempdir)
   383  
   384  	// Push some new metadata blocks.
   385  
   386  	firstRevision := kbfsmd.Revision(10)
   387  	firstPrevRoot := kbfsmd.FakeID(1)
   388  	mdCount := 3
   389  	_, prevRoot := putMDRange(t, ver, id, signer, ekg, bsplit,
   390  		firstRevision, firstPrevRoot, mdCount, j)
   391  
   392  	// Should just replace the head.
   393  
   394  	ctx := context.Background()
   395  
   396  	revision := firstRevision + kbfsmd.Revision(mdCount) - 1
   397  	md := makeMDForTest(t, ver, id, revision, j.uid, signer, prevRoot)
   398  	md.SetDiskUsage(501)
   399  	_, _, err := j.put(ctx, signer, ekg, bsplit, md, false)
   400  	require.NoError(t, err)
   401  
   402  	head, err := j.getHead(ctx, kbfsmd.NullBranchID)
   403  	require.NoError(t, err)
   404  	require.Equal(t, md.Revision(), head.RevisionNumber())
   405  	require.Equal(t, md.DiskUsage(), head.DiskUsage())
   406  	require.Equal(t, md.extra, head.extra)
   407  }
   408  
   409  func testMDJournalPutCase2NonEmptyReplace(t *testing.T, ver kbfsmd.MetadataVer) {
   410  	_, _, id, signer, ekg, bsplit, tempdir, j := setupMDJournalTest(t, ver)
   411  	defer teardownMDJournalTest(t, tempdir)
   412  
   413  	ctx := context.Background()
   414  	md := makeMDForTest(t, ver, id, kbfsmd.Revision(10), j.uid, signer, kbfsmd.FakeID(1))
   415  	_, _, err := j.put(ctx, signer, ekg, bsplit, md, false)
   416  	require.NoError(t, err)
   417  
   418  	err = j.convertToBranch(
   419  		ctx, kbfsmd.PendingLocalSquashBranchID, signer, kbfscodec.NewMsgpack(),
   420  		id, NewMDCacheStandard(10))
   421  	require.NoError(t, err)
   422  
   423  	md.SetUnmerged()
   424  	_, _, err = j.put(ctx, signer, ekg, bsplit, md, false)
   425  	require.NoError(t, err)
   426  }
   427  
   428  func testMDJournalPutCase2NonEmptyAppend(t *testing.T, ver kbfsmd.MetadataVer) {
   429  	_, _, id, signer, ekg, bsplit, tempdir, j := setupMDJournalTest(t, ver)
   430  	defer teardownMDJournalTest(t, tempdir)
   431  
   432  	ctx := context.Background()
   433  	md := makeMDForTest(t, ver, id, kbfsmd.Revision(10), j.uid, signer, kbfsmd.FakeID(1))
   434  	mdID, _, err := j.put(ctx, signer, ekg, bsplit, md, false)
   435  	require.NoError(t, err)
   436  
   437  	err = j.convertToBranch(
   438  		ctx, kbfsmd.PendingLocalSquashBranchID, signer, kbfscodec.NewMsgpack(),
   439  		id, NewMDCacheStandard(10))
   440  	require.NoError(t, err)
   441  
   442  	md2 := makeMDForTest(t, ver, id, kbfsmd.Revision(11), j.uid, signer, mdID)
   443  	md2.SetUnmerged()
   444  	_, _, err = j.put(ctx, signer, ekg, bsplit, md2, false)
   445  	require.NoError(t, err)
   446  }
   447  
   448  func testMDJournalPutCase2Empty(t *testing.T, ver kbfsmd.MetadataVer) {
   449  	_, _, id, signer, ekg, bsplit, tempdir, j := setupMDJournalTest(t, ver)
   450  	defer teardownMDJournalTest(t, tempdir)
   451  
   452  	ctx := context.Background()
   453  	md := makeMDForTest(t, ver, id, kbfsmd.Revision(10), j.uid, signer, kbfsmd.FakeID(1))
   454  	_, _, err := j.put(ctx, signer, ekg, bsplit, md, false)
   455  	require.NoError(t, err)
   456  
   457  	err = j.convertToBranch(
   458  		ctx, kbfsmd.PendingLocalSquashBranchID, signer, kbfscodec.NewMsgpack(),
   459  		id, NewMDCacheStandard(10))
   460  	require.NoError(t, err)
   461  
   462  	// Flush.
   463  	mdID, rmds, _, err := j.getNextEntryToFlush(
   464  		ctx, md.Revision()+1, signer)
   465  	require.NoError(t, err)
   466  	_, err = j.removeFlushedEntry(ctx, mdID, rmds)
   467  	require.NoError(t, err)
   468  
   469  	md2 := makeMDForTest(t, ver, id, kbfsmd.Revision(11), j.uid, signer, mdID)
   470  	md2.SetUnmerged()
   471  	_, _, err = j.put(ctx, signer, ekg, bsplit, md2, false)
   472  	require.NoError(t, err)
   473  }
   474  
   475  func testMDJournalPutCase3NonEmptyAppend(t *testing.T, ver kbfsmd.MetadataVer) {
   476  	_, _, id, signer, ekg, bsplit, tempdir, j := setupMDJournalTest(t, ver)
   477  	defer teardownMDJournalTest(t, tempdir)
   478  
   479  	ctx := context.Background()
   480  	md := makeMDForTest(t, ver, id, kbfsmd.Revision(10), j.uid, signer, kbfsmd.FakeID(1))
   481  	_, _, err := j.put(ctx, signer, ekg, bsplit, md, false)
   482  	require.NoError(t, err)
   483  
   484  	bid := kbfsmd.PendingLocalSquashBranchID
   485  	err = j.convertToBranch(
   486  		ctx, bid, signer, kbfscodec.NewMsgpack(),
   487  		id, NewMDCacheStandard(10))
   488  	require.NoError(t, err)
   489  
   490  	head, err := j.getHead(ctx, bid)
   491  	require.NoError(t, err)
   492  	require.NotEqual(t, ImmutableBareRootMetadata{}, head)
   493  
   494  	md2 := makeMDForTest(t, ver, id, kbfsmd.Revision(11), j.uid, signer, head.mdID)
   495  	md2.SetUnmerged()
   496  	md2.SetBranchID(head.BID())
   497  	_, _, err = j.put(ctx, signer, ekg, bsplit, md2, false)
   498  	require.NoError(t, err)
   499  }
   500  
   501  func testMDJournalPutCase3NonEmptyReplace(t *testing.T, ver kbfsmd.MetadataVer) {
   502  	_, _, id, signer, ekg, bsplit, tempdir, j := setupMDJournalTest(t, ver)
   503  	defer teardownMDJournalTest(t, tempdir)
   504  
   505  	ctx := context.Background()
   506  	md := makeMDForTest(t, ver, id, kbfsmd.Revision(10), j.uid, signer, kbfsmd.FakeID(1))
   507  	_, _, err := j.put(ctx, signer, ekg, bsplit, md, false)
   508  	require.NoError(t, err)
   509  
   510  	bid := kbfsmd.PendingLocalSquashBranchID
   511  	err = j.convertToBranch(
   512  		ctx, bid, signer, kbfscodec.NewMsgpack(),
   513  		id, NewMDCacheStandard(10))
   514  	require.NoError(t, err)
   515  
   516  	head, err := j.getHead(ctx, bid)
   517  	require.NoError(t, err)
   518  	require.NotEqual(t, ImmutableBareRootMetadata{}, head)
   519  
   520  	md.SetUnmerged()
   521  	md.SetBranchID(head.BID())
   522  	_, _, err = j.put(ctx, signer, ekg, bsplit, md, false)
   523  	require.NoError(t, err)
   524  }
   525  
   526  func testMDJournalPutCase3EmptyAppend(t *testing.T, ver kbfsmd.MetadataVer) {
   527  	_, _, id, signer, ekg, bsplit, tempdir, j := setupMDJournalTest(t, ver)
   528  	defer teardownMDJournalTest(t, tempdir)
   529  
   530  	ctx := context.Background()
   531  	md := makeMDForTest(t, ver, id, kbfsmd.Revision(10), j.uid, signer, kbfsmd.FakeID(1))
   532  	_, _, err := j.put(ctx, signer, ekg, bsplit, md, false)
   533  	require.NoError(t, err)
   534  
   535  	err = j.convertToBranch(
   536  		ctx, kbfsmd.PendingLocalSquashBranchID, signer, kbfscodec.NewMsgpack(),
   537  		id, NewMDCacheStandard(10))
   538  	require.NoError(t, err)
   539  
   540  	// Flush.
   541  	mdID, rmds, _, err := j.getNextEntryToFlush(
   542  		ctx, md.Revision()+1, signer)
   543  	require.NoError(t, err)
   544  	_, err = j.removeFlushedEntry(ctx, mdID, rmds)
   545  	require.NoError(t, err)
   546  
   547  	md2 := makeMDForTest(t, ver, id, kbfsmd.Revision(11), j.uid, signer, mdID)
   548  	md2.SetUnmerged()
   549  	md2.SetBranchID(j.branchID)
   550  	_, _, err = j.put(ctx, signer, ekg, bsplit, md2, false)
   551  	require.NoError(t, err)
   552  }
   553  
   554  func testMDJournalPutCase4(t *testing.T, ver kbfsmd.MetadataVer) {
   555  	_, _, id, signer, ekg, bsplit, tempdir, j := setupMDJournalTest(t, ver)
   556  	defer teardownMDJournalTest(t, tempdir)
   557  
   558  	ctx := context.Background()
   559  	md := makeMDForTest(t, ver, id, kbfsmd.Revision(10), j.uid, signer, kbfsmd.FakeID(1))
   560  	md.SetUnmerged()
   561  	md.SetBranchID(kbfsmd.FakeBranchID(1))
   562  	_, _, err := j.put(ctx, signer, ekg, bsplit, md, false)
   563  	require.NoError(t, err)
   564  }
   565  
   566  func testMDJournalGCd(t *testing.T, j *mdJournal) {
   567  	// None of these dirs should exist.
   568  	for _, dir := range j.mdJournalDirs() {
   569  		_, err := ioutil.Stat(dir)
   570  		require.True(t, ioutil.IsNotExist(err))
   571  	}
   572  }
   573  
   574  func flushAllMDs(
   575  	ctx context.Context, t *testing.T, signer kbfscrypto.Signer, j *mdJournal) {
   576  	end, err := j.end()
   577  	require.NoError(t, err)
   578  	for {
   579  		mdID, rmds, _, err := j.getNextEntryToFlush(ctx, end, signer)
   580  		require.NoError(t, err)
   581  		if mdID == (kbfsmd.ID{}) {
   582  			break
   583  		}
   584  		_, err = j.removeFlushedEntry(ctx, mdID, rmds)
   585  		require.NoError(t, err)
   586  	}
   587  	testMDJournalGCd(t, j)
   588  }
   589  
   590  func listDir(t *testing.T, dir string) []string {
   591  	fileInfos, err := ioutil.ReadDir(dir)
   592  	require.NoError(t, err)
   593  	var names []string
   594  	for _, fileInfo := range fileInfos {
   595  		names = append(names, fileInfo.Name())
   596  	}
   597  	return names
   598  }
   599  
   600  func getMDJournalNames(ver kbfsmd.MetadataVer) []string {
   601  	var expectedNames []string
   602  	if ver < kbfsmd.SegregatedKeyBundlesVer {
   603  		expectedNames = []string{"md_journal", "mds"}
   604  	} else {
   605  		expectedNames = []string{
   606  			"md_journal", "mds", "rkbv3", "wkbv3",
   607  		}
   608  	}
   609  	return expectedNames
   610  }
   611  
   612  func testMDJournalFlushAll(t *testing.T, ver kbfsmd.MetadataVer) {
   613  	_, _, id, signer, ekg, bsplit, tempdir, j := setupMDJournalTest(t, ver)
   614  	defer teardownMDJournalTest(t, tempdir)
   615  
   616  	firstRevision := kbfsmd.Revision(10)
   617  	firstPrevRoot := kbfsmd.FakeID(1)
   618  	mdCount := 10
   619  	putMDRange(t, ver, id, signer, ekg, bsplit,
   620  		firstRevision, firstPrevRoot, mdCount, j)
   621  
   622  	ctx := context.Background()
   623  
   624  	names := listDir(t, j.dir)
   625  	require.Equal(t, getMDJournalNames(ver), names)
   626  
   627  	err := ioutil.WriteFile(filepath.Join(j.dir, "extra_file"), nil, 0600)
   628  	require.NoError(t, err)
   629  
   630  	flushAllMDs(ctx, t, signer, j)
   631  
   632  	// The flush shouldn't remove the entire directory.
   633  	names = listDir(t, j.dir)
   634  	require.Equal(t, []string{"extra_file"}, names)
   635  }
   636  
   637  func testMDJournalBranchConversion(t *testing.T, ver kbfsmd.MetadataVer) {
   638  	codec, _, id, signer, ekg, bsplit, tempdir, j :=
   639  		setupMDJournalTest(t, ver)
   640  	defer teardownMDJournalTest(t, tempdir)
   641  
   642  	firstRevision := kbfsmd.Revision(10)
   643  	firstPrevRoot := kbfsmd.FakeID(1)
   644  	mdCount := 10
   645  	putMDRange(t, ver, id, signer, ekg, bsplit,
   646  		firstRevision, firstPrevRoot, mdCount, j)
   647  
   648  	ctx := context.Background()
   649  
   650  	// Put a single MD in the cache to make sure it gets converted.
   651  	mdcache := NewMDCacheStandard(10)
   652  	cachedMd := makeMDForTest(
   653  		t, ver, id, firstRevision, j.uid, signer, firstPrevRoot)
   654  	err := cachedMd.bareMd.SignWriterMetadataInternally(ctx, codec, signer)
   655  	require.NoError(t, err)
   656  	cachedMdID, _, _, _, err := j.getEarliestWithExtra(ctx, false)
   657  	require.NoError(t, err)
   658  	err = mdcache.Put(MakeImmutableRootMetadata(cachedMd,
   659  		j.key, cachedMdID, time.Now(), false))
   660  	require.NoError(t, err)
   661  
   662  	bid := kbfsmd.PendingLocalSquashBranchID
   663  	err = j.convertToBranch(ctx, bid, signer, kbfscodec.NewMsgpack(),
   664  		id, mdcache)
   665  	require.NoError(t, err)
   666  
   667  	// Branch conversion shouldn't leave old folders behind.
   668  	names := listDir(t, j.dir)
   669  	require.Equal(t, getMDJournalNames(ver), names)
   670  
   671  	ibrmds, err := j.getRange(
   672  		ctx, bid, 1, firstRevision+kbfsmd.Revision(2*mdCount))
   673  	require.NoError(t, err)
   674  	require.Equal(t, mdCount, len(ibrmds))
   675  
   676  	checkIBRMDRange(t, j.uid, j.key, codec,
   677  		ibrmds, firstRevision, firstPrevRoot, kbfsmd.Unmerged, ibrmds[0].BID())
   678  
   679  	require.Equal(t, uint64(10), j.length())
   680  
   681  	head, err := j.getHead(ctx, bid)
   682  	require.NoError(t, err)
   683  	require.Equal(t, ibrmds[len(ibrmds)-1], head)
   684  
   685  	flushAllMDs(ctx, t, signer, j)
   686  
   687  	// Has the cache entry been replaced?
   688  	newlyCachedMd, err := mdcache.Get(id, firstRevision, bid)
   689  	require.NoError(t, err)
   690  	require.Equal(t, newlyCachedMd.BID(), bid)
   691  	require.Equal(t, newlyCachedMd.MergedStatus(), kbfsmd.Unmerged)
   692  	_, err = mdcache.Get(id, firstRevision, kbfsmd.NullBranchID)
   693  	require.Error(t, err)
   694  }
   695  
   696  func testMDJournalResolveAndClear(t *testing.T, ver kbfsmd.MetadataVer, bid kbfsmd.BranchID) {
   697  	_, _, id, signer, ekg, bsplit, tempdir, j :=
   698  		setupMDJournalTest(t, ver)
   699  	defer teardownMDJournalTest(t, tempdir)
   700  
   701  	firstRevision := kbfsmd.Revision(10)
   702  	firstPrevRoot := kbfsmd.FakeID(1)
   703  	mdCount := 10
   704  	putMDRange(t, ver, id, signer, ekg, bsplit,
   705  		firstRevision, firstPrevRoot, mdCount, j)
   706  
   707  	journalID, err := j.getOrCreateJournalID()
   708  	require.NoError(t, err)
   709  	require.True(t, journalID.IsValid())
   710  
   711  	ctx := context.Background()
   712  
   713  	mdcache := NewMDCacheStandard(10)
   714  	err = j.convertToBranch(
   715  		ctx, bid, signer, kbfscodec.NewMsgpack(), id, mdcache)
   716  	require.NoError(t, err)
   717  
   718  	resolveRev := firstRevision
   719  	md := makeMDForTest(t, ver, id, resolveRev, j.uid, signer, firstPrevRoot)
   720  	resolveMdID, resolveJournalID, err := j.resolveAndClear(
   721  		ctx, signer, ekg, bsplit, mdcache, bid, md)
   722  	require.NoError(t, err)
   723  
   724  	require.Equal(t, uint64(1), j.length())
   725  	head, err := j.getHead(ctx, kbfsmd.NullBranchID)
   726  	require.NoError(t, err)
   727  	require.Equal(t, md.Revision(), head.RevisionNumber())
   728  	require.True(t, resolveJournalID.IsValid())
   729  	require.NotEqual(t, resolveJournalID, journalID)
   730  
   731  	// Now put more MDs and resolve them again -- if this is a local
   732  	// squash, it should keep the original resolution as a separate
   733  	// entry.
   734  	putMDRange(t, ver, id, signer, ekg, bsplit,
   735  		resolveRev+1, resolveMdID, mdCount, j)
   736  	err = j.convertToBranch(ctx, bid, signer, kbfscodec.NewMsgpack(), id,
   737  		mdcache)
   738  	require.NoError(t, err)
   739  	numExpectedMDs := 1
   740  	prevRoot := firstPrevRoot
   741  	if bid == kbfsmd.PendingLocalSquashBranchID {
   742  		numExpectedMDs++
   743  		resolveRev++
   744  		prevRoot = resolveMdID
   745  	}
   746  	md = makeMDForTest(t, ver, id, resolveRev, j.uid, signer, prevRoot)
   747  	_, resolveJournalID2, err := j.resolveAndClear(
   748  		ctx, signer, ekg, bsplit, mdcache, bid, md)
   749  	require.NoError(t, err)
   750  	require.Equal(t, uint64(numExpectedMDs), j.length())
   751  	head, err = j.getHead(ctx, kbfsmd.NullBranchID)
   752  	require.NoError(t, err)
   753  	require.Equal(t, md.Revision(), head.RevisionNumber())
   754  	require.NotEqual(t, resolveJournalID2, resolveJournalID)
   755  
   756  	flushAllMDs(ctx, t, signer, j)
   757  }
   758  
   759  func testMDJournalResolveAndClearRemoteBranch(t *testing.T, ver kbfsmd.MetadataVer) {
   760  	codec := kbfscodec.NewMsgpack()
   761  	crypto := MakeCryptoCommon(codec, makeBlockCryptV1())
   762  	bid, err := crypto.MakeRandomBranchID()
   763  	require.NoError(t, err)
   764  	testMDJournalResolveAndClear(t, ver, bid)
   765  }
   766  
   767  func testMDJournalResolveAndClearLocalSquash(t *testing.T, ver kbfsmd.MetadataVer) {
   768  	testMDJournalResolveAndClear(t, ver, kbfsmd.PendingLocalSquashBranchID)
   769  }
   770  
   771  type limitedCryptoSigner struct {
   772  	kbfscrypto.Signer
   773  	remaining int
   774  }
   775  
   776  func (s *limitedCryptoSigner) Sign(ctx context.Context, msg []byte) (
   777  	kbfscrypto.SignatureInfo, error) {
   778  	if s.remaining <= 0 {
   779  		return kbfscrypto.SignatureInfo{}, errors.New("No more Sign calls left")
   780  	}
   781  	s.remaining--
   782  	return s.Signer.Sign(ctx, msg)
   783  }
   784  
   785  func TestMDJournalBranchConversionAtomic(t *testing.T) {
   786  	// Do this with kbfsmd.InitialExtraMetadataVer only, since any later
   787  	// version doesn't actually do any signing.
   788  	ver := kbfsmd.InitialExtraMetadataVer
   789  
   790  	codec, _, id, signer, ekg, bsplit, tempdir, j :=
   791  		setupMDJournalTest(t, ver)
   792  	defer teardownMDJournalTest(t, tempdir)
   793  
   794  	firstRevision := kbfsmd.Revision(10)
   795  	firstPrevRoot := kbfsmd.FakeID(1)
   796  	mdCount := 10
   797  	putMDRange(t, ver, id, signer, ekg, bsplit,
   798  		firstRevision, firstPrevRoot, mdCount, j)
   799  
   800  	limitedSigner := limitedCryptoSigner{signer, 5}
   801  
   802  	ctx := context.Background()
   803  
   804  	err := j.convertToBranch(
   805  		ctx, kbfsmd.PendingLocalSquashBranchID, &limitedSigner,
   806  		kbfscodec.NewMsgpack(), id, NewMDCacheStandard(10))
   807  	require.NotNil(t, err)
   808  
   809  	// All entries should remain unchanged, since the conversion
   810  	// encountered an error.
   811  
   812  	ibrmds, err := j.getRange(
   813  		ctx, kbfsmd.NullBranchID, 1, firstRevision+kbfsmd.Revision(2*mdCount))
   814  	require.NoError(t, err)
   815  	require.Equal(t, mdCount, len(ibrmds))
   816  
   817  	checkIBRMDRange(t, j.uid, j.key, codec,
   818  		ibrmds, firstRevision, firstPrevRoot, kbfsmd.Merged, kbfsmd.NullBranchID)
   819  
   820  	require.Equal(t, uint64(10), j.length())
   821  
   822  	head, err := j.getHead(ctx, kbfsmd.NullBranchID)
   823  	require.NoError(t, err)
   824  	require.Equal(t, ibrmds[len(ibrmds)-1], head)
   825  
   826  	// Flush all MDs so we can check garbage collection.
   827  	flushAllMDs(ctx, t, signer, j)
   828  }
   829  
   830  type mdIDJournalEntryExtra struct {
   831  	mdIDJournalEntry
   832  	Extra int
   833  }
   834  
   835  func testMDJournalBranchConversionPreservesUnknownFields(t *testing.T, ver kbfsmd.MetadataVer) {
   836  	codec, _, id, signer, ekg, bsplit, tempdir, j := setupMDJournalTest(t, ver)
   837  	defer teardownMDJournalTest(t, tempdir)
   838  
   839  	var expectedEntries []mdIDJournalEntry
   840  
   841  	firstRevision := kbfsmd.Revision(5)
   842  	mdCount := 5
   843  	prevRoot := kbfsmd.FakeID(1)
   844  	ctx := context.Background()
   845  	for i := 0; i < mdCount; i++ {
   846  		revision := firstRevision + kbfsmd.Revision(i)
   847  		md := makeMDForTest(t, ver, id, revision, j.uid, signer, prevRoot)
   848  		mdID, _, err := j.put(ctx, signer, ekg, bsplit, md, false)
   849  		require.NoError(t, err)
   850  
   851  		// Add extra fields to the journal entry.
   852  		entryFuture := mdIDJournalEntryExtra{
   853  			mdIDJournalEntry: mdIDJournalEntry{
   854  				ID: mdID,
   855  			},
   856  			Extra: i,
   857  		}
   858  		var entry mdIDJournalEntry
   859  		err = kbfscodec.Update(codec, &entry, entryFuture)
   860  		require.NoError(t, err)
   861  		o, err := revisionToOrdinal(revision)
   862  		require.NoError(t, err)
   863  		err = j.j.j.writeJournalEntry(o, entry)
   864  		require.NoError(t, err)
   865  
   866  		// Zero out the MdID, since branch conversion changes
   867  		// it.
   868  		entry.ID = kbfsmd.ID{}
   869  		expectedEntries = append(expectedEntries, entry)
   870  
   871  		prevRoot = mdID
   872  	}
   873  
   874  	err := j.convertToBranch(
   875  		ctx, kbfsmd.PendingLocalSquashBranchID, signer, kbfscodec.NewMsgpack(), id,
   876  		NewMDCacheStandard(10))
   877  	require.NoError(t, err)
   878  
   879  	// Check that the extra fields are preserved.
   880  	_, entries, err := j.j.getEntryRange(
   881  		firstRevision, firstRevision+kbfsmd.Revision(mdCount))
   882  	require.NoError(t, err)
   883  	// Zero out MdIDs for comparison.
   884  	for i, entry := range entries {
   885  		entry.ID = kbfsmd.ID{}
   886  		entries[i] = entry
   887  	}
   888  	require.Equal(t, expectedEntries, entries)
   889  
   890  	flushAllMDs(ctx, t, signer, j)
   891  }
   892  
   893  func testMDJournalClear(t *testing.T, ver kbfsmd.MetadataVer) {
   894  	_, _, id, signer, ekg, bsplit, tempdir, j := setupMDJournalTest(t, ver)
   895  	defer teardownMDJournalTest(t, tempdir)
   896  
   897  	firstRevision := kbfsmd.Revision(10)
   898  	firstPrevRoot := kbfsmd.FakeID(1)
   899  	mdCount := 10
   900  	putMDRange(t, ver, id, signer, ekg, bsplit,
   901  		firstRevision, firstPrevRoot, mdCount, j)
   902  
   903  	ctx := context.Background()
   904  
   905  	err := j.convertToBranch(
   906  		ctx, kbfsmd.PendingLocalSquashBranchID, signer, kbfscodec.NewMsgpack(), id,
   907  		NewMDCacheStandard(10))
   908  	require.NoError(t, err)
   909  	require.NotEqual(t, kbfsmd.NullBranchID, j.branchID)
   910  
   911  	bid := j.branchID
   912  
   913  	// Clearing the master branch shouldn't work.
   914  	err = j.clear(ctx, kbfsmd.NullBranchID)
   915  	require.Error(t, err)
   916  
   917  	// Clearing a different branch ID should do nothing.
   918  	err = j.clear(ctx, kbfsmd.FakeBranchID(1))
   919  	require.NoError(t, err)
   920  	require.Equal(t, bid, j.branchID)
   921  
   922  	head, err := j.getHead(ctx, bid)
   923  	require.NoError(t, err)
   924  	require.NotEqual(t, ImmutableBareRootMetadata{}, head)
   925  
   926  	// Clearing the correct branch ID should clear the entire
   927  	// journal, and reset the branch ID.
   928  	err = j.clear(ctx, bid)
   929  	require.NoError(t, err)
   930  	require.Equal(t, kbfsmd.NullBranchID, j.branchID)
   931  
   932  	head, err = j.getHead(ctx, bid)
   933  	require.NoError(t, err)
   934  	require.Equal(t, ImmutableBareRootMetadata{}, head)
   935  
   936  	head, err = j.getHead(ctx, kbfsmd.NullBranchID)
   937  	require.NoError(t, err)
   938  	require.Equal(t, ImmutableBareRootMetadata{}, head)
   939  
   940  	// Clearing twice should do nothing.
   941  	err = j.clear(ctx, bid)
   942  	require.NoError(t, err)
   943  	require.Equal(t, kbfsmd.NullBranchID, j.branchID)
   944  
   945  	head, err = j.getHead(ctx, bid)
   946  	require.NoError(t, err)
   947  	require.Equal(t, ImmutableBareRootMetadata{}, head)
   948  
   949  	// Put more MDs, flush them, and clear the branch ID of an empty
   950  	// journal.
   951  	putMDRange(t, ver, id, signer, ekg, bsplit,
   952  		firstRevision, firstPrevRoot, mdCount, j)
   953  	err = j.convertToBranch(
   954  		ctx, kbfsmd.PendingLocalSquashBranchID, signer, kbfscodec.NewMsgpack(), id,
   955  		NewMDCacheStandard(10))
   956  	require.NoError(t, err)
   957  	require.NotEqual(t, kbfsmd.NullBranchID, j.branchID)
   958  
   959  	bid = j.branchID
   960  	flushAllMDs(ctx, t, signer, j)
   961  	require.Equal(t, bid, j.branchID)
   962  	err = j.clear(ctx, bid)
   963  	require.NoError(t, err)
   964  	require.Equal(t, kbfsmd.NullBranchID, j.branchID)
   965  
   966  	flushAllMDs(ctx, t, signer, j)
   967  }
   968  
   969  func testMDJournalClearPendingWithMaster(t *testing.T, ver kbfsmd.MetadataVer) {
   970  	_, _, id, signer, ekg, bsplit, tempdir, j := setupMDJournalTest(t, ver)
   971  	defer teardownMDJournalTest(t, tempdir)
   972  
   973  	firstRevision := kbfsmd.Revision(10)
   974  	firstPrevRoot := kbfsmd.FakeID(1)
   975  	mdCount := 10
   976  
   977  	_, prevRoot := putMDRangeHelper(t, ver, id, signer, firstRevision,
   978  		firstPrevRoot, mdCount, j.uid,
   979  		func(ctx context.Context, md *RootMetadata) (kbfsmd.ID, error) {
   980  			mdID, _, err := j.put(ctx, signer, ekg, bsplit, md, true)
   981  			return mdID, err
   982  		})
   983  
   984  	putMDRange(t, ver, id, signer, ekg, bsplit,
   985  		firstRevision+kbfsmd.Revision(mdCount), prevRoot, mdCount, j)
   986  
   987  	ctx := context.Background()
   988  
   989  	err := j.convertToBranch(
   990  		ctx, kbfsmd.PendingLocalSquashBranchID, signer, kbfscodec.NewMsgpack(), id,
   991  		NewMDCacheStandard(10))
   992  	require.NoError(t, err)
   993  	require.NotEqual(t, kbfsmd.NullBranchID, j.branchID)
   994  
   995  	bid := j.branchID
   996  
   997  	// Clearing the correct branch ID should clear just the last
   998  	// half of the journal and reset the branch ID.
   999  	err = j.clear(ctx, bid)
  1000  	require.NoError(t, err)
  1001  	require.Equal(t, kbfsmd.NullBranchID, j.branchID)
  1002  
  1003  	require.Equal(t, uint64(mdCount), j.length())
  1004  
  1005  	head, err := j.getHead(ctx, bid)
  1006  	require.NoError(t, err)
  1007  	require.Equal(t, ImmutableBareRootMetadata{}, head)
  1008  
  1009  	head, err = j.getHead(ctx, kbfsmd.NullBranchID)
  1010  	require.NoError(t, err)
  1011  	require.NotEqual(t, ImmutableBareRootMetadata{}, head)
  1012  	require.Equal(t, firstRevision+kbfsmd.Revision(mdCount-1),
  1013  		head.RevisionNumber())
  1014  	require.Equal(t, kbfsmd.NullBranchID, head.BID())
  1015  }
  1016  
  1017  func testMDJournalRestart(t *testing.T, ver kbfsmd.MetadataVer) {
  1018  	codec, crypto, id, signer, ekg,
  1019  		bsplit, tempdir, j := setupMDJournalTest(t, ver)
  1020  	defer teardownMDJournalTest(t, tempdir)
  1021  
  1022  	// Push some new metadata blocks.
  1023  
  1024  	firstRevision := kbfsmd.Revision(10)
  1025  	firstPrevRoot := kbfsmd.FakeID(1)
  1026  	mdCount := 10
  1027  	putMDRange(t, ver, id, signer, ekg, bsplit,
  1028  		firstRevision, firstPrevRoot, mdCount, j)
  1029  
  1030  	// Restart journal.
  1031  	ctx := context.Background()
  1032  	j, err := makeMDJournal(ctx, j.uid, j.key, codec, crypto, j.clock,
  1033  		j.teamMemChecker, j.osg, j.tlfID, j.mdVer, j.dir, j.log,
  1034  		j.overrideTlfID)
  1035  	require.NoError(t, err)
  1036  
  1037  	require.Equal(t, uint64(mdCount), j.length())
  1038  
  1039  	ibrmds, err := j.getRange(
  1040  		ctx, kbfsmd.NullBranchID, 1, firstRevision+kbfsmd.Revision(2*mdCount))
  1041  	require.NoError(t, err)
  1042  	require.Equal(t, mdCount, len(ibrmds))
  1043  
  1044  	checkIBRMDRange(t, j.uid, j.key, codec,
  1045  		ibrmds, firstRevision, firstPrevRoot, kbfsmd.Merged, kbfsmd.NullBranchID)
  1046  
  1047  	flushAllMDs(context.Background(), t, signer, j)
  1048  }
  1049  
  1050  func testMDJournalRestartAfterBranchConversion(t *testing.T, ver kbfsmd.MetadataVer) {
  1051  	codec, crypto, id, signer, ekg, bsplit, tempdir, j :=
  1052  		setupMDJournalTest(t, ver)
  1053  	defer teardownMDJournalTest(t, tempdir)
  1054  
  1055  	// Push some new metadata blocks.
  1056  
  1057  	firstRevision := kbfsmd.Revision(10)
  1058  	firstPrevRoot := kbfsmd.FakeID(1)
  1059  	mdCount := 10
  1060  	putMDRange(t, ver, id, signer, ekg, bsplit,
  1061  		firstRevision, firstPrevRoot, mdCount, j)
  1062  
  1063  	// Convert to branch.
  1064  
  1065  	ctx := context.Background()
  1066  
  1067  	bid := kbfsmd.PendingLocalSquashBranchID
  1068  	err := j.convertToBranch(
  1069  		ctx, bid, signer, kbfscodec.NewMsgpack(),
  1070  		id, NewMDCacheStandard(10))
  1071  	require.NoError(t, err)
  1072  
  1073  	// Restart journal.
  1074  
  1075  	j, err = makeMDJournal(ctx, j.uid, j.key, codec, crypto, j.clock,
  1076  		j.teamMemChecker, j.osg, j.tlfID, j.mdVer, j.dir, j.log,
  1077  		j.overrideTlfID)
  1078  	require.NoError(t, err)
  1079  
  1080  	require.Equal(t, uint64(mdCount), j.length())
  1081  
  1082  	ibrmds, err := j.getRange(
  1083  		ctx, bid, 1, firstRevision+kbfsmd.Revision(2*mdCount))
  1084  	require.NoError(t, err)
  1085  	require.Equal(t, mdCount, len(ibrmds))
  1086  
  1087  	checkIBRMDRange(t, j.uid, j.key, codec,
  1088  		ibrmds, firstRevision, firstPrevRoot, kbfsmd.Unmerged, ibrmds[0].BID())
  1089  
  1090  	flushAllMDs(ctx, t, signer, j)
  1091  }
  1092  
  1093  func TestMDJournal(t *testing.T) {
  1094  	tests := []func(*testing.T, kbfsmd.MetadataVer){
  1095  		testMDJournalBasic,
  1096  		testMDJournalGetNextEntry,
  1097  		testMDJournalPutEntryTwice,
  1098  		testMDJournalPutCase1Empty,
  1099  		testMDJournalPutCase1Conflict,
  1100  		testMDJournalPutCase1ReplaceHead,
  1101  		testMDJournalPutCase2NonEmptyReplace,
  1102  		testMDJournalPutCase2NonEmptyAppend,
  1103  		testMDJournalPutCase2Empty,
  1104  		testMDJournalPutCase3NonEmptyAppend,
  1105  		testMDJournalPutCase3NonEmptyReplace,
  1106  		testMDJournalPutCase3EmptyAppend,
  1107  		testMDJournalPutCase4,
  1108  		testMDJournalFlushAll,
  1109  		testMDJournalBranchConversion,
  1110  		testMDJournalResolveAndClearRemoteBranch,
  1111  		testMDJournalResolveAndClearLocalSquash,
  1112  		testMDJournalBranchConversionPreservesUnknownFields,
  1113  		testMDJournalClear,
  1114  		testMDJournalClearPendingWithMaster,
  1115  		testMDJournalRestart,
  1116  		testMDJournalRestartAfterBranchConversion,
  1117  	}
  1118  	runTestsOverMetadataVers(t, "testMDJournal", tests)
  1119  }