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 }