github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbfs/libkbfs/journal_manager_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 "math" 9 "os" 10 "sync" 11 "testing" 12 "time" 13 14 "github.com/keybase/client/go/kbfs/ioutil" 15 "github.com/keybase/client/go/kbfs/kbfsblock" 16 "github.com/keybase/client/go/kbfs/kbfscrypto" 17 "github.com/keybase/client/go/kbfs/kbfsmd" 18 "github.com/keybase/client/go/kbfs/test/clocktest" 19 "github.com/keybase/client/go/kbfs/tlf" 20 "github.com/keybase/client/go/kbfs/tlfhandle" 21 kbname "github.com/keybase/client/go/kbun" 22 "github.com/keybase/client/go/protocol/keybase1" 23 "github.com/pkg/errors" 24 "github.com/stretchr/testify/assert" 25 "github.com/stretchr/testify/require" 26 "golang.org/x/net/context" 27 ) 28 29 func setupJournalManagerTest(t *testing.T) ( 30 tempdir string, ctx context.Context, cancel context.CancelFunc, 31 config *ConfigLocal, quotaUsage *EventuallyConsistentQuotaUsage, 32 jManager *JournalManager) { 33 tempdir, err := ioutil.TempDir(os.TempDir(), "journal_server") 34 require.NoError(t, err) 35 36 // Clean up the tempdir if the rest of the setup fails. 37 setupSucceeded := false 38 defer func() { 39 if !setupSucceeded { 40 err := ioutil.RemoveAll(tempdir) 41 assert.NoError(t, err) 42 } 43 }() 44 45 ctx, cancel = context.WithTimeout( 46 context.Background(), individualTestTimeout) 47 48 // Clean up the context if the rest of the setup fails. 49 defer func() { 50 if !setupSucceeded { 51 cancel() 52 } 53 }() 54 55 config = MakeTestConfigOrBust(t, "test_user1", "test_user2") 56 57 // Clean up the config if the rest of the setup fails. 58 defer func() { 59 if !setupSucceeded { 60 ctx := context.Background() 61 CheckConfigAndShutdown(ctx, t, config) 62 } 63 }() 64 65 err = config.EnableDiskLimiter(tempdir) 66 require.NoError(t, err) 67 err = config.EnableJournaling( 68 ctx, tempdir, TLFJournalBackgroundWorkEnabled) 69 require.NoError(t, err) 70 jManager, err = GetJournalManager(config) 71 require.NoError(t, err) 72 73 session, err := config.KBPKI().GetCurrentSession(ctx) 74 require.NoError(t, err) 75 quotaUsage = config.GetQuotaUsage(session.UID.AsUserOrTeam()) 76 77 setupSucceeded = true 78 return tempdir, ctx, cancel, config, quotaUsage, jManager 79 } 80 81 func teardownJournalManagerTest( 82 ctx context.Context, t *testing.T, tempdir string, 83 cancel context.CancelFunc, config Config) { 84 CheckConfigAndShutdown(ctx, t, config) 85 cancel() 86 err := ioutil.RemoveAll(tempdir) 87 assert.NoError(t, err) 88 } 89 90 type quotaBlockServer struct { 91 BlockServer 92 93 quotaInfoLock sync.Mutex 94 userQuotaInfo kbfsblock.QuotaInfo 95 teamQuotaInfo map[keybase1.TeamID]kbfsblock.QuotaInfo 96 } 97 98 func (qbs *quotaBlockServer) setUserQuotaInfo( 99 remoteUsageBytes, limitBytes, remoteGitUsageBytes, gitLimitBytes int64) { 100 qbs.quotaInfoLock.Lock() 101 defer qbs.quotaInfoLock.Unlock() 102 qbs.userQuotaInfo.Limit = limitBytes 103 qbs.userQuotaInfo.GitLimit = gitLimitBytes 104 qbs.userQuotaInfo.Total = &kbfsblock.UsageStat{ 105 Bytes: map[kbfsblock.UsageType]int64{ 106 kbfsblock.UsageWrite: remoteUsageBytes, 107 kbfsblock.UsageGitWrite: remoteGitUsageBytes, 108 }, 109 } 110 } 111 112 func (qbs *quotaBlockServer) setTeamQuotaInfo( 113 tid keybase1.TeamID, remoteUsageBytes, limitBytes int64) { 114 qbs.quotaInfoLock.Lock() 115 defer qbs.quotaInfoLock.Unlock() 116 if qbs.teamQuotaInfo == nil { 117 qbs.teamQuotaInfo = make(map[keybase1.TeamID]kbfsblock.QuotaInfo) 118 } 119 info := qbs.teamQuotaInfo[tid] 120 info.Limit = limitBytes 121 info.Total = &kbfsblock.UsageStat{ 122 Bytes: map[kbfsblock.UsageType]int64{ 123 kbfsblock.UsageWrite: remoteUsageBytes, 124 }, 125 } 126 qbs.teamQuotaInfo[tid] = info 127 } 128 129 func (qbs *quotaBlockServer) GetUserQuotaInfo(ctx context.Context) ( 130 info *kbfsblock.QuotaInfo, err error) { 131 qbs.quotaInfoLock.Lock() 132 defer qbs.quotaInfoLock.Unlock() 133 infoCopy := qbs.userQuotaInfo 134 return &infoCopy, nil 135 } 136 137 func (qbs *quotaBlockServer) GetTeamQuotaInfo( 138 ctx context.Context, tid keybase1.TeamID) ( 139 info *kbfsblock.QuotaInfo, err error) { 140 qbs.quotaInfoLock.Lock() 141 defer qbs.quotaInfoLock.Unlock() 142 infoCopy := qbs.teamQuotaInfo[tid] 143 return &infoCopy, nil 144 } 145 146 func TestJournalManagerOverQuotaError(t *testing.T) { 147 tempdir, ctx, cancel, config, quotaUsage, jManager := 148 setupJournalManagerTest(t) 149 defer teardownJournalManagerTest(ctx, t, tempdir, cancel, config) 150 151 name := kbname.NormalizedUsername("t1") 152 subname := kbname.NormalizedUsername("t1.sub") 153 teamInfos := AddEmptyTeamsForTestOrBust(t, config, name, subname) 154 teamID := teamInfos[0].TID 155 subteamID := teamInfos[1].TID 156 session, err := config.KBPKI().GetCurrentSession(ctx) 157 require.NoError(t, err) 158 AddTeamWriterForTestOrBust(t, config, teamID, session.UID) 159 AddTeamWriterForTestOrBust(t, config, subteamID, session.UID) 160 teamQuotaUsage := config.GetQuotaUsage(teamID.AsUserOrTeam()) 161 162 qbs := "aBlockServer{BlockServer: config.BlockServer()} 163 config.SetBlockServer(qbs) 164 165 clock := clocktest.NewTestClockNow() 166 config.SetClock(clock) 167 168 // Set initial quota usage and refresh quotaUsage's cache. 169 qbs.setUserQuotaInfo(1010, 1000, 2010, 2000) 170 _, _, _, _, err = quotaUsage.Get(ctx, 0, 0) 171 require.NoError(t, err) 172 173 // Set team quota to be under the limit for now. 174 qbs.setTeamQuotaInfo(teamID, 0, 1000) 175 _, _, _, _, err = teamQuotaUsage.Get(ctx, 0, 0) 176 require.NoError(t, err) 177 178 tlfID1 := tlf.FakeID(1, tlf.Private) 179 err = jManager.Enable(ctx, tlfID1, nil, TLFJournalBackgroundWorkPaused) 180 require.NoError(t, err) 181 tlfID2 := tlf.FakeID(2, tlf.SingleTeam) 182 h, err := tlfhandle.ParseHandle( 183 ctx, config.KBPKI(), config.MDOps(), nil, "t1", tlf.SingleTeam) 184 require.NoError(t, err) 185 err = jManager.Enable(ctx, tlfID2, h, TLFJournalBackgroundWorkPaused) 186 require.NoError(t, err) 187 tlfID3 := tlf.FakeID(2, tlf.SingleTeam) 188 h, err = tlfhandle.ParseHandle( 189 ctx, config.KBPKI(), config.MDOps(), nil, "t1.sub", tlf.SingleTeam) 190 require.NoError(t, err) 191 err = jManager.Enable(ctx, tlfID3, h, TLFJournalBackgroundWorkPaused) 192 require.NoError(t, err) 193 194 blockServer := config.BlockServer() 195 196 h, err = tlfhandle.ParseHandle( 197 ctx, config.KBPKI(), config.MDOps(), nil, "test_user1,test_user2", 198 tlf.Private) 199 require.NoError(t, err) 200 id1 := h.ResolvedWriters()[0] 201 202 // Put a block, which should return with a quota error. 203 204 bCtx := kbfsblock.MakeFirstContext(id1, keybase1.BlockType_DATA) 205 data := []byte{1, 2, 3, 4} 206 bID, err := kbfsblock.MakePermanentID( 207 data, kbfscrypto.EncryptionSecretboxWithKeyNonce) 208 require.NoError(t, err) 209 serverHalf, err := kbfscrypto.MakeRandomBlockCryptKeyServerHalf() 210 require.NoError(t, err) 211 err = blockServer.Put( 212 ctx, tlfID1, bID, bCtx, data, serverHalf, DiskBlockAnyCache) 213 expectedQuotaError := kbfsblock.ServerErrorOverQuota{ 214 Usage: 1014, 215 Limit: 1000, 216 Throttled: false, 217 } 218 require.Equal(t, expectedQuotaError, err) 219 220 // Teams shouldn't get an error. 221 err = blockServer.Put( 222 ctx, tlfID2, bID, bCtx, data, serverHalf, DiskBlockAnyCache) 223 require.NoError(t, err) 224 225 // Subteams shouldn't get an error. 226 err = blockServer.Put( 227 ctx, tlfID3, bID, bCtx, data, serverHalf, DiskBlockAnyCache) 228 require.NoError(t, err) 229 230 // Putting it again shouldn't encounter an error. 231 err = blockServer.Put( 232 ctx, tlfID1, bID, bCtx, data, serverHalf, DiskBlockAnyCache) 233 require.NoError(t, err) 234 235 // Advancing the time by overQuotaDuration should make it 236 // return another quota error. 237 clock.Add(time.Minute) 238 err = blockServer.Put( 239 ctx, tlfID1, bID, bCtx, data, serverHalf, DiskBlockAnyCache) 240 require.Equal(t, expectedQuotaError, err) 241 242 // Putting it again shouldn't encounter an error. 243 clock.Add(30 * time.Second) 244 err = blockServer.Put( 245 ctx, tlfID1, bID, bCtx, data, serverHalf, DiskBlockAnyCache) 246 require.NoError(t, err) 247 248 // Now up the team usage, so teams (and their subteams) should get 249 // an error. 250 qbs.setTeamQuotaInfo(teamID, 1010, 1000) 251 _, _, _, _, err = teamQuotaUsage.Get(ctx, 0, 0) 252 require.NoError(t, err) 253 clock.Add(time.Minute) 254 err = blockServer.Put( 255 ctx, tlfID2, bID, bCtx, data, serverHalf, DiskBlockAnyCache) 256 expectedQuotaError = kbfsblock.ServerErrorOverQuota{ 257 Usage: 1014, 258 Limit: 1000, 259 Throttled: false, 260 } 261 require.Equal(t, expectedQuotaError, err) 262 263 // Check that the subteam gets an error too. 264 clock.Add(time.Minute) 265 err = blockServer.Put( 266 ctx, tlfID3, bID, bCtx, data, serverHalf, DiskBlockAnyCache) 267 require.Equal(t, expectedQuotaError, err) 268 } 269 270 type tlfJournalConfigWithDiskLimitTimeout struct { 271 tlfJournalConfig 272 dlTimeout time.Duration 273 } 274 275 func (c tlfJournalConfigWithDiskLimitTimeout) diskLimitTimeout() time.Duration { 276 return c.dlTimeout 277 } 278 279 func TestJournalManagerOverDiskLimitError(t *testing.T) { 280 tempdir, ctx, cancel, config, quotaUsage, jManager := 281 setupJournalManagerTest(t) 282 defer teardownJournalManagerTest(ctx, t, tempdir, cancel, config) 283 284 qbs := "aBlockServer{BlockServer: config.BlockServer()} 285 config.SetBlockServer(qbs) 286 287 clock := clocktest.NewTestClockNow() 288 config.SetClock(clock) 289 290 // Set initial quota usage and refresh quotaUsage's cache. 291 qbs.setUserQuotaInfo(1010, 1000, 2010, 2000) 292 _, _, _, _, err := quotaUsage.Get(ctx, 0, 0) 293 require.NoError(t, err) 294 295 tlfID1 := tlf.FakeID(1, tlf.Private) 296 err = jManager.Enable(ctx, tlfID1, nil, TLFJournalBackgroundWorkPaused) 297 require.NoError(t, err) 298 299 session, err := config.KBPKI().GetCurrentSession(ctx) 300 require.NoError(t, err) 301 chargedTo := session.UID.AsUserOrTeam() 302 303 // Replace the tlfJournal config with one that has a really small 304 // delay. 305 tj, ok := jManager.getTLFJournal(tlfID1, nil) 306 require.True(t, ok) 307 tj.config = tlfJournalConfigWithDiskLimitTimeout{ 308 tlfJournalConfig: tj.config, 309 dlTimeout: 3 * time.Microsecond, 310 } 311 tj.diskLimiter.onJournalEnable( 312 ctx, math.MaxInt64, 0, math.MaxInt64-1, chargedTo) 313 314 blockServer := config.BlockServer() 315 316 h, err := tlfhandle.ParseHandle( 317 ctx, config.KBPKI(), config.MDOps(), nil, "test_user1,test_user2", 318 tlf.Private) 319 require.NoError(t, err) 320 id1 := h.ResolvedWriters()[0] 321 322 // Put a block, which should return with a disk limit error. 323 324 bCtx := kbfsblock.MakeFirstContext(id1, keybase1.BlockType_DATA) 325 data := []byte{1, 2, 3, 4} 326 bID, err := kbfsblock.MakePermanentID( 327 data, kbfscrypto.EncryptionSecretboxWithKeyNonce) 328 require.NoError(t, err) 329 serverHalf, err := kbfscrypto.MakeRandomBlockCryptKeyServerHalf() 330 require.NoError(t, err) 331 usageBytes, limitBytes, usageFiles, limitFiles := 332 tj.diskLimiter.getDiskLimitInfo() 333 putCtx := context.Background() // rely on default disk limit timeout 334 err = blockServer.Put( 335 putCtx, tlfID1, bID, bCtx, data, serverHalf, DiskBlockAnyCache) 336 337 compare := func(reportable bool, err error) { 338 expectedError := ErrDiskLimitTimeout{ 339 3 * time.Microsecond, int64(len(data)), 340 filesPerBlockMax, 0, 0, 341 usageBytes, usageFiles, limitBytes, limitFiles, nil, reportable, 342 } 343 e, ok := errors.Cause(err).(*ErrDiskLimitTimeout) 344 require.True(t, ok) 345 // Steal some fields that are hard to fake here (and aren't 346 // important in our comparisons below). 347 expectedError.availableBytes = e.availableBytes 348 expectedError.availableFiles = e.availableFiles 349 expectedError.err = e.err 350 require.Equal(t, expectedError, *e) 351 } 352 compare(true, err) 353 354 // Putting it again should encounter a regular deadline exceeded 355 // error. 356 err = blockServer.Put( 357 putCtx, tlfID1, bID, bCtx, data, serverHalf, DiskBlockAnyCache) 358 compare(false, err) 359 360 // Advancing the time by overDiskLimitDuration should make it 361 // return another quota error. 362 clock.Add(time.Minute) 363 err = blockServer.Put( 364 putCtx, tlfID1, bID, bCtx, data, serverHalf, DiskBlockAnyCache) 365 compare(true, err) 366 367 // Putting it again should encounter a deadline error again. 368 clock.Add(30 * time.Second) 369 err = blockServer.Put( 370 putCtx, tlfID1, bID, bCtx, data, serverHalf, DiskBlockAnyCache) 371 compare(false, err) 372 } 373 374 func TestJournalManagerRestart(t *testing.T) { 375 tempdir, ctx, cancel, config, _, jManager := setupJournalManagerTest(t) 376 defer teardownJournalManagerTest(ctx, t, tempdir, cancel, config) 377 378 // Use a shutdown-only BlockServer so that it errors if the 379 // journal tries to access it. 380 jManager.delegateBlockServer = shutdownOnlyBlockServer{} 381 382 tlfID := tlf.FakeID(2, tlf.Private) 383 err := jManager.Enable(ctx, tlfID, nil, TLFJournalBackgroundWorkPaused) 384 require.NoError(t, err) 385 386 blockServer := config.BlockServer() 387 mdOps := config.MDOps() 388 389 h, err := tlfhandle.ParseHandle( 390 ctx, config.KBPKI(), config.MDOps(), nil, "test_user1", tlf.Private) 391 require.NoError(t, err) 392 id := h.ResolvedWriters()[0] 393 394 // Put a block. 395 396 bCtx := kbfsblock.MakeFirstContext(id, keybase1.BlockType_DATA) 397 data := []byte{1, 2, 3, 4} 398 bID, err := kbfsblock.MakePermanentID( 399 data, kbfscrypto.EncryptionSecretboxWithKeyNonce) 400 require.NoError(t, err) 401 serverHalf, err := kbfscrypto.MakeRandomBlockCryptKeyServerHalf() 402 require.NoError(t, err) 403 err = blockServer.Put( 404 ctx, tlfID, bID, bCtx, data, serverHalf, DiskBlockAnyCache) 405 require.NoError(t, err) 406 407 // Put an MD. 408 409 rmd, err := makeInitialRootMetadata(config.MetadataVersion(), tlfID, h) 410 require.NoError(t, err) 411 rekeyDone, _, err := config.KeyManager().Rekey(ctx, rmd, false) 412 require.NoError(t, err) 413 require.True(t, rekeyDone) 414 415 session, err := config.KBPKI().GetCurrentSession(ctx) 416 require.NoError(t, err) 417 418 _, err = mdOps.Put( 419 ctx, rmd, session.VerifyingKey, nil, keybase1.MDPriorityNormal, nil) 420 require.NoError(t, err) 421 422 // Simulate a restart. 423 424 jManager = makeJournalManager( 425 config, jManager.log, tempdir, jManager.delegateBlockCache, 426 jManager.delegateDirtyBlockCache, 427 jManager.delegateBlockServer, jManager.delegateMDOps, nil, nil, 428 TLFJournalBackgroundWorkPaused) 429 err = jManager.EnableExistingJournals( 430 ctx, session.UID, session.VerifyingKey, TLFJournalBackgroundWorkPaused) 431 require.NoError(t, err) 432 config.SetBlockCache(jManager.blockCache()) 433 config.SetBlockServer(jManager.blockServer()) 434 config.SetMDOps(jManager.mdOps()) 435 436 // Get the block. 437 438 buf, key, err := blockServer.Get(ctx, tlfID, bID, bCtx, DiskBlockAnyCache) 439 require.NoError(t, err) 440 require.Equal(t, data, buf) 441 require.Equal(t, serverHalf, key) 442 443 // Get the MD. 444 445 head, err := mdOps.GetForTLF(ctx, tlfID, nil) 446 require.NoError(t, err) 447 require.Equal(t, rmd.Revision(), head.Revision()) 448 } 449 450 func TestJournalManagerLogOutLogIn(t *testing.T) { 451 tempdir, ctx, cancel, config, _, jManager := setupJournalManagerTest(t) 452 defer teardownJournalManagerTest(ctx, t, tempdir, cancel, config) 453 454 // Use a shutdown-only BlockServer so that it errors if the 455 // journal tries to access it. 456 jManager.delegateBlockServer = shutdownOnlyBlockServer{} 457 458 tlfID := tlf.FakeID(2, tlf.Private) 459 err := jManager.Enable(ctx, tlfID, nil, TLFJournalBackgroundWorkPaused) 460 require.NoError(t, err) 461 462 blockServer := config.BlockServer() 463 mdOps := config.MDOps() 464 465 h, err := tlfhandle.ParseHandle( 466 ctx, config.KBPKI(), config.MDOps(), nil, "test_user1", tlf.Private) 467 require.NoError(t, err) 468 id := h.ResolvedWriters()[0] 469 470 // Put a block. 471 472 bCtx := kbfsblock.MakeFirstContext(id, keybase1.BlockType_DATA) 473 data := []byte{1, 2, 3, 4} 474 bID, err := kbfsblock.MakePermanentID( 475 data, kbfscrypto.EncryptionSecretboxWithKeyNonce) 476 require.NoError(t, err) 477 serverHalf, err := kbfscrypto.MakeRandomBlockCryptKeyServerHalf() 478 require.NoError(t, err) 479 err = blockServer.Put( 480 ctx, tlfID, bID, bCtx, data, serverHalf, DiskBlockAnyCache) 481 require.NoError(t, err) 482 483 // Put an MD. 484 485 rmd, err := makeInitialRootMetadata(config.MetadataVersion(), tlfID, h) 486 require.NoError(t, err) 487 rekeyDone, _, err := config.KeyManager().Rekey(ctx, rmd, false) 488 require.NoError(t, err) 489 require.True(t, rekeyDone) 490 491 session, err := config.KBPKI().GetCurrentSession(ctx) 492 require.NoError(t, err) 493 494 _, err = mdOps.Put( 495 ctx, rmd, session.VerifyingKey, nil, keybase1.MDPriorityNormal, nil) 496 require.NoError(t, err) 497 498 // Simulate a log out. 499 500 serviceLoggedOut(ctx, config) 501 502 // Get the block, which should fail. 503 504 _, _, err = blockServer.Get(ctx, tlfID, bID, bCtx, DiskBlockAnyCache) 505 require.IsType(t, kbfsblock.ServerErrorBlockNonExistent{}, err) 506 507 // Get the head, which should be empty. 508 509 head, err := mdOps.GetForTLF(ctx, tlfID, nil) 510 require.NoError(t, err) 511 require.Equal(t, ImmutableRootMetadata{}, head) 512 513 wg := serviceLoggedIn( 514 ctx, config, session, TLFJournalBackgroundWorkPaused) 515 wg.Wait() 516 517 // Get the block. 518 519 buf, key, err := blockServer.Get(ctx, tlfID, bID, bCtx, DiskBlockAnyCache) 520 require.NoError(t, err) 521 require.Equal(t, data, buf) 522 require.Equal(t, serverHalf, key) 523 524 // Get the MD. 525 526 head, err = mdOps.GetForTLF(ctx, tlfID, nil) 527 require.NoError(t, err) 528 require.Equal(t, rmd.Revision(), head.Revision()) 529 } 530 531 func TestJournalManagerLogOutDirtyOp(t *testing.T) { 532 tempdir, ctx, cancel, config, _, jManager := setupJournalManagerTest(t) 533 defer teardownJournalManagerTest(ctx, t, tempdir, cancel, config) 534 535 tlfID := tlf.FakeID(2, tlf.Private) 536 err := jManager.Enable(ctx, tlfID, nil, TLFJournalBackgroundWorkPaused) 537 require.NoError(t, err) 538 539 jManager.dirtyOpStart(tlfID) 540 go func() { 541 jManager.dirtyOpEnd(tlfID) 542 }() 543 544 // Should wait for the dirtyOpEnd call to happen and then 545 // finish. 546 // 547 // TODO: Ideally, this test would be deterministic, i.e. we 548 // detect when serviceLoggedOut blocks on waiting for 549 // dirtyOpEnd, and only then do we call dirtyOpEnd. 550 serviceLoggedOut(ctx, config) 551 552 dirtyOps := func() uint { 553 jManager.lock.RLock() 554 defer jManager.lock.RUnlock() 555 return jManager.dirtyOps[tlfID] 556 }() 557 require.Equal(t, uint(0), dirtyOps) 558 } 559 560 func TestJournalManagerMultiUser(t *testing.T) { 561 tempdir, ctx, cancel, config, _, jManager := setupJournalManagerTest(t) 562 defer teardownJournalManagerTest(ctx, t, tempdir, cancel, config) 563 564 // Use a shutdown-only BlockServer so that it errors if the 565 // journal tries to access it. 566 jManager.delegateBlockServer = shutdownOnlyBlockServer{} 567 568 tlfID := tlf.FakeID(2, tlf.Private) 569 err := jManager.Enable(ctx, tlfID, nil, TLFJournalBackgroundWorkPaused) 570 require.NoError(t, err) 571 572 blockServer := config.BlockServer() 573 mdOps := config.MDOps() 574 575 h, err := tlfhandle.ParseHandle( 576 ctx, config.KBPKI(), config.MDOps(), nil, "test_user1,test_user2", 577 tlf.Private) 578 require.NoError(t, err) 579 id1 := h.ResolvedWriters()[0] 580 id2 := h.ResolvedWriters()[1] 581 582 // Put a block under user 1. 583 584 bCtx1 := kbfsblock.MakeFirstContext(id1, keybase1.BlockType_DATA) 585 data1 := []byte{1, 2, 3, 4} 586 bID1, err := kbfsblock.MakePermanentID( 587 data1, kbfscrypto.EncryptionSecretboxWithKeyNonce) 588 require.NoError(t, err) 589 serverHalf1, err := kbfscrypto.MakeRandomBlockCryptKeyServerHalf() 590 require.NoError(t, err) 591 err = blockServer.Put( 592 ctx, tlfID, bID1, bCtx1, data1, serverHalf1, DiskBlockAnyCache) 593 require.NoError(t, err) 594 595 // Put an MD under user 1. 596 597 rmd1, err := makeInitialRootMetadata(config.MetadataVersion(), tlfID, h) 598 require.NoError(t, err) 599 rmd1.SetLastModifyingWriter(id1.AsUserOrBust()) 600 rekeyDone, _, err := config.KeyManager().Rekey(ctx, rmd1, false) 601 require.NoError(t, err) 602 require.True(t, rekeyDone) 603 604 session, err := config.KBPKI().GetCurrentSession(ctx) 605 require.NoError(t, err) 606 607 _, err = mdOps.Put( 608 ctx, rmd1, session.VerifyingKey, nil, keybase1.MDPriorityNormal, nil) 609 require.NoError(t, err) 610 611 // Log in user 2. 612 613 serviceLoggedOut(ctx, config) 614 615 service := config.KeybaseService().(*KeybaseDaemonLocal) 616 service.SetCurrentUID(id2.AsUserOrBust()) 617 SwitchDeviceForLocalUserOrBust(t, config, 0) 618 619 session, err = config.KBPKI().GetCurrentSession(ctx) 620 require.NoError(t, err) 621 wg := serviceLoggedIn( 622 ctx, config, session, TLFJournalBackgroundWorkPaused) 623 wg.Wait() 624 625 err = jManager.Enable(ctx, tlfID, nil, TLFJournalBackgroundWorkPaused) 626 require.NoError(t, err) 627 628 // None of user 1's changes should be visible. 629 630 _, _, err = blockServer.Get(ctx, tlfID, bID1, bCtx1, DiskBlockAnyCache) 631 require.IsType(t, kbfsblock.ServerErrorBlockNonExistent{}, err) 632 633 head, err := mdOps.GetForTLF(ctx, tlfID, nil) 634 require.NoError(t, err) 635 require.Equal(t, ImmutableRootMetadata{}, head) 636 637 // Put a block under user 2. 638 639 bCtx2 := kbfsblock.MakeFirstContext(id2, keybase1.BlockType_DATA) 640 data2 := []byte{1, 2, 3, 4, 5} 641 bID2, err := kbfsblock.MakePermanentID( 642 data2, kbfscrypto.EncryptionSecretboxWithKeyNonce) 643 require.NoError(t, err) 644 serverHalf2, err := kbfscrypto.MakeRandomBlockCryptKeyServerHalf() 645 require.NoError(t, err) 646 err = blockServer.Put( 647 ctx, tlfID, bID2, bCtx2, data2, serverHalf2, DiskBlockAnyCache) 648 require.NoError(t, err) 649 650 // Put an MD under user 2. 651 652 rmd2, err := makeInitialRootMetadata(config.MetadataVersion(), tlfID, h) 653 require.NoError(t, err) 654 rmd2.SetLastModifyingWriter(id2.AsUserOrBust()) 655 rekeyDone, _, err = config.KeyManager().Rekey(ctx, rmd2, false) 656 require.NoError(t, err) 657 require.True(t, rekeyDone) 658 659 _, err = mdOps.Put( 660 ctx, rmd2, session.VerifyingKey, nil, keybase1.MDPriorityNormal, nil) 661 require.NoError(t, err) 662 663 // Log out. 664 665 serviceLoggedOut(ctx, config) 666 667 // No block or MD should be visible. 668 669 _, _, err = blockServer.Get(ctx, tlfID, bID1, bCtx1, DiskBlockAnyCache) 670 require.IsType(t, kbfsblock.ServerErrorBlockNonExistent{}, err) 671 672 _, _, err = blockServer.Get(ctx, tlfID, bID2, bCtx2, DiskBlockAnyCache) 673 require.IsType(t, kbfsblock.ServerErrorBlockNonExistent{}, err) 674 675 head, err = mdOps.GetForTLF(ctx, tlfID, nil) 676 require.NoError(t, err) 677 require.Equal(t, ImmutableRootMetadata{}, head) 678 679 // Log in user 1. 680 681 service.SetCurrentUID(id1.AsUserOrBust()) 682 SwitchDeviceForLocalUserOrBust(t, config, 0) 683 684 session, err = config.KBPKI().GetCurrentSession(ctx) 685 require.NoError(t, err) 686 wg = serviceLoggedIn( 687 ctx, config, session, TLFJournalBackgroundWorkPaused) 688 wg.Wait() 689 690 // Only user 1's block and MD should be visible. 691 692 buf, key, err := blockServer.Get(ctx, tlfID, bID1, bCtx1, DiskBlockAnyCache) 693 require.NoError(t, err) 694 require.Equal(t, data1, buf) 695 require.Equal(t, serverHalf1, key) 696 697 _, _, err = blockServer.Get(ctx, tlfID, bID2, bCtx2, DiskBlockAnyCache) 698 require.IsType(t, kbfsblock.ServerErrorBlockNonExistent{}, err) 699 700 head, err = mdOps.GetForTLF(ctx, tlfID, nil) 701 require.NoError(t, err) 702 require.Equal(t, id1.AsUserOrBust(), head.LastModifyingWriter()) 703 704 // Log in user 2. 705 706 serviceLoggedOut(ctx, config) 707 708 service.SetCurrentUID(id2.AsUserOrBust()) 709 SwitchDeviceForLocalUserOrBust(t, config, 0) 710 711 session, err = config.KBPKI().GetCurrentSession(ctx) 712 require.NoError(t, err) 713 wg = serviceLoggedIn( 714 ctx, config, session, TLFJournalBackgroundWorkPaused) 715 wg.Wait() 716 717 // Only user 2's block and MD should be visible. 718 719 _, _, err = blockServer.Get(ctx, tlfID, bID1, bCtx1, DiskBlockAnyCache) 720 require.IsType(t, kbfsblock.ServerErrorBlockNonExistent{}, err) 721 722 buf, key, err = blockServer.Get(ctx, tlfID, bID2, bCtx2, DiskBlockAnyCache) 723 require.NoError(t, err) 724 require.Equal(t, data2, buf) 725 require.Equal(t, serverHalf2, key) 726 727 head, err = mdOps.GetForTLF(ctx, tlfID, nil) 728 require.NoError(t, err) 729 require.Equal(t, id2.AsUserOrBust(), head.LastModifyingWriter()) 730 } 731 732 func TestJournalManagerEnableAuto(t *testing.T) { 733 delegateCtx, delegateCancel := context.WithCancel(context.Background()) 734 defer delegateCancel() 735 736 tempdir, ctx, cancel, config, _, jManager := setupJournalManagerTest(t) 737 defer teardownJournalManagerTest(ctx, t, tempdir, cancel, config) 738 739 err := jManager.EnableAuto(ctx) 740 require.NoError(t, err) 741 742 status, tlfIDs := jManager.Status(ctx) 743 require.True(t, status.EnableAuto) 744 require.Zero(t, status.JournalCount) 745 require.Len(t, tlfIDs, 0) 746 747 delegate := testBWDelegate{ 748 t: t, 749 testCtx: delegateCtx, 750 stateCh: make(chan bwState), 751 shutdownCh: make(chan struct{}, 1), 752 } 753 jManager.setDelegateMaker(func(_ tlf.ID) tlfJournalBWDelegate { 754 return delegate 755 }) 756 757 blockServer := config.BlockServer() 758 h, err := tlfhandle.ParseHandle( 759 ctx, config.KBPKI(), config.MDOps(), nil, "test_user1", tlf.Private) 760 require.NoError(t, err) 761 id := h.ResolvedWriters()[0] 762 tlfID := h.TlfID() 763 764 delegate.requireNextState(ctx, bwIdle) 765 delegate.requireNextState(ctx, bwBusy) 766 delegate.requireNextState(ctx, bwIdle) 767 768 t.Log("Pause journal, and wait for it to pause") 769 jManager.PauseBackgroundWork(ctx, tlfID) 770 delegate.requireNextState(ctx, bwPaused) 771 772 bCtx := kbfsblock.MakeFirstContext(id, keybase1.BlockType_DATA) 773 data := []byte{1, 2, 3, 4} 774 bID, err := kbfsblock.MakePermanentID( 775 data, kbfscrypto.EncryptionSecretboxWithKeyNonce) 776 require.NoError(t, err) 777 serverHalf, err := kbfscrypto.MakeRandomBlockCryptKeyServerHalf() 778 require.NoError(t, err) 779 err = blockServer.Put( 780 ctx, tlfID, bID, bCtx, data, serverHalf, DiskBlockAnyCache) 781 require.NoError(t, err) 782 783 status, tlfIDs = jManager.Status(ctx) 784 require.True(t, status.EnableAuto) 785 require.Equal(t, 1, status.JournalCount) 786 require.Len(t, tlfIDs, 1) 787 788 // Stop the journal so it's not still being operated on by 789 // another instance after the restart. 790 tj, ok := jManager.getTLFJournal(tlfID, nil) 791 require.True(t, ok) 792 tj.shutdown(ctx) 793 794 // Simulate a restart. 795 jManager = makeJournalManager( 796 config, jManager.log, tempdir, jManager.delegateBlockCache, 797 jManager.delegateDirtyBlockCache, 798 jManager.delegateBlockServer, jManager.delegateMDOps, nil, nil, 799 TLFJournalBackgroundWorkPaused) 800 session, err := config.KBPKI().GetCurrentSession(ctx) 801 require.NoError(t, err) 802 err = jManager.EnableExistingJournals( 803 ctx, session.UID, session.VerifyingKey, TLFJournalBackgroundWorkPaused) 804 require.NoError(t, err) 805 status, tlfIDs = jManager.Status(ctx) 806 require.True(t, status.EnableAuto) 807 require.Equal(t, 1, status.JournalCount) 808 require.Len(t, tlfIDs, 1) 809 } 810 811 func TestJournalManagerReaderTLFs(t *testing.T) { 812 tempdir, ctx, cancel, config, _, jManager := setupJournalManagerTest(t) 813 defer teardownJournalManagerTest(ctx, t, tempdir, cancel, config) 814 815 err := jManager.EnableAuto(ctx) 816 require.NoError(t, err) 817 818 status, tlfIDs := jManager.Status(ctx) 819 require.True(t, status.EnableAuto) 820 require.Zero(t, status.JournalCount) 821 require.Len(t, tlfIDs, 0) 822 823 // This will end up calling journalMDOps.GetIDForHandle, which 824 // initializes the journal if possible. In this case for a 825 // public, unwritable folder, it shouldn't. 826 _, err = tlfhandle.ParseHandle( 827 ctx, config.KBPKI(), config.MDOps(), nil, "test_user2", tlf.Public) 828 require.NoError(t, err) 829 830 status, tlfIDs = jManager.Status(ctx) 831 require.True(t, status.EnableAuto) 832 require.Equal(t, 0, status.JournalCount) 833 require.Len(t, tlfIDs, 0) 834 835 // Neither should a private, reader folder. 836 h, err := tlfhandle.ParseHandle( 837 ctx, config.KBPKI(), config.MDOps(), nil, "test_user2#test_user1", 838 tlf.Private) 839 require.NoError(t, err) 840 841 status, tlfIDs = jManager.Status(ctx) 842 require.True(t, status.EnableAuto) 843 require.Equal(t, 0, status.JournalCount) 844 require.Len(t, tlfIDs, 0) 845 846 // Or a team folder, where you're just a reader. 847 teamName := kbname.NormalizedUsername("t1") 848 teamInfos := AddEmptyTeamsForTestOrBust(t, config, teamName) 849 id := teamInfos[0].TID 850 AddTeamWriterForTestOrBust( 851 t, config, id, h.FirstResolvedWriter().AsUserOrBust()) 852 AddTeamReaderForTestOrBust( 853 t, config, id, h.ResolvedReaders()[0].AsUserOrBust()) 854 _, err = tlfhandle.ParseHandle( 855 ctx, config.KBPKI(), config.MDOps(), nil, string(teamName), 856 tlf.SingleTeam) 857 require.NoError(t, err) 858 859 status, tlfIDs = jManager.Status(ctx) 860 require.True(t, status.EnableAuto) 861 require.Equal(t, 0, status.JournalCount) 862 require.Len(t, tlfIDs, 0) 863 864 // But accessing our own should make one. 865 _, err = tlfhandle.ParseHandle( 866 ctx, config.KBPKI(), config.MDOps(), nil, "test_user1", tlf.Public) 867 require.NoError(t, err) 868 869 status, tlfIDs = jManager.Status(ctx) 870 require.True(t, status.EnableAuto) 871 require.Equal(t, 1, status.JournalCount) 872 require.Len(t, tlfIDs, 1) 873 } 874 875 func TestJournalManagerNukeEmptyJournalsOnRestart(t *testing.T) { 876 tempdir, ctx, cancel, config, _, jManager := setupJournalManagerTest(t) 877 defer teardownJournalManagerTest(ctx, t, tempdir, cancel, config) 878 879 err := jManager.EnableAuto(ctx) 880 require.NoError(t, err) 881 882 status, tlfIDs := jManager.Status(ctx) 883 require.True(t, status.EnableAuto) 884 require.Zero(t, status.JournalCount) 885 require.Len(t, tlfIDs, 0) 886 887 blockServer := config.BlockServer() 888 h, err := tlfhandle.ParseHandle( 889 ctx, config.KBPKI(), config.MDOps(), nil, "test_user1", tlf.Private) 890 require.NoError(t, err) 891 id := h.ResolvedWriters()[0] 892 tlfID := h.TlfID() 893 894 // Access a TLF, which should create a journal automatically. 895 bCtx := kbfsblock.MakeFirstContext(id, keybase1.BlockType_DATA) 896 data := []byte{1, 2, 3, 4} 897 bID, err := kbfsblock.MakePermanentID( 898 data, kbfscrypto.EncryptionSecretboxWithKeyNonce) 899 require.NoError(t, err) 900 serverHalf, err := kbfscrypto.MakeRandomBlockCryptKeyServerHalf() 901 require.NoError(t, err) 902 err = blockServer.Put( 903 ctx, tlfID, bID, bCtx, data, serverHalf, DiskBlockAnyCache) 904 require.NoError(t, err) 905 906 status, tlfIDs = jManager.Status(ctx) 907 require.True(t, status.EnableAuto) 908 require.Equal(t, 1, status.JournalCount) 909 require.Len(t, tlfIDs, 1) 910 911 tj, ok := jManager.getTLFJournal(tlfID, nil) 912 require.True(t, ok) 913 914 // Flush the journal so it's empty. 915 err = jManager.Flush(ctx, tlfID) 916 require.NoError(t, err) 917 918 // Simulate a restart and make sure the journal doesn't come back 919 // up. 920 jManager = makeJournalManager( 921 config, jManager.log, tempdir, jManager.delegateBlockCache, 922 jManager.delegateDirtyBlockCache, 923 jManager.delegateBlockServer, jManager.delegateMDOps, nil, nil, 924 TLFJournalBackgroundWorkPaused) 925 session, err := config.KBPKI().GetCurrentSession(ctx) 926 require.NoError(t, err) 927 err = jManager.EnableExistingJournals( 928 ctx, session.UID, session.VerifyingKey, TLFJournalBackgroundWorkPaused) 929 require.NoError(t, err) 930 status, tlfIDs = jManager.Status(ctx) 931 require.True(t, status.EnableAuto) 932 require.Equal(t, 0, status.JournalCount) 933 require.Len(t, tlfIDs, 0) 934 _, err = os.Stat(tj.dir) 935 require.True(t, ioutil.IsNotExist(err)) 936 } 937 938 func TestJournalManagerTeamTLFWithRestart(t *testing.T) { 939 tempdir, ctx, cancel, config, _, jManager := setupJournalManagerTest(t) 940 defer teardownJournalManagerTest(ctx, t, tempdir, cancel, config) 941 942 name := kbname.NormalizedUsername("t1") 943 teamInfos := AddEmptyTeamsForTestOrBust(t, config, name) 944 id := teamInfos[0].TID 945 session, err := config.KBPKI().GetCurrentSession(ctx) 946 require.NoError(t, err) 947 AddTeamWriterForTestOrBust(t, config, id, session.UID) 948 949 // Use a shutdown-only BlockServer so that it errors if the 950 // journal tries to access it. 951 jManager.delegateBlockServer = shutdownOnlyBlockServer{} 952 953 h, err := tlfhandle.ParseHandle( 954 ctx, config.KBPKI(), config.MDOps(), nil, string(name), tlf.SingleTeam) 955 require.NoError(t, err) 956 957 tlfID := tlf.FakeID(2, tlf.SingleTeam) 958 err = jManager.Enable(ctx, tlfID, h, TLFJournalBackgroundWorkPaused) 959 require.NoError(t, err) 960 961 blockServer := config.BlockServer() 962 mdOps := config.MDOps() 963 964 // Put a block. 965 966 bCtx := kbfsblock.MakeFirstContext( 967 id.AsUserOrTeam(), keybase1.BlockType_DATA) 968 data := []byte{1, 2, 3, 4} 969 bID, err := kbfsblock.MakePermanentID( 970 data, kbfscrypto.EncryptionSecretboxWithKeyNonce) 971 require.NoError(t, err) 972 serverHalf, err := kbfscrypto.MakeRandomBlockCryptKeyServerHalf() 973 require.NoError(t, err) 974 err = blockServer.Put( 975 ctx, tlfID, bID, bCtx, data, serverHalf, DiskBlockAnyCache) 976 require.NoError(t, err) 977 978 // Put an MD. 979 980 rmd, err := makeInitialRootMetadata(config.MetadataVersion(), tlfID, h) 981 require.NoError(t, err) 982 rmd.bareMd.SetLatestKeyGenerationForTeamTLF(kbfsmd.FirstValidKeyGen) 983 984 _, err = mdOps.Put( 985 ctx, rmd, session.VerifyingKey, nil, keybase1.MDPriorityNormal, nil) 986 require.NoError(t, err) 987 988 // Simulate a restart. 989 990 jManager = makeJournalManager( 991 config, jManager.log, tempdir, jManager.delegateBlockCache, 992 jManager.delegateDirtyBlockCache, 993 jManager.delegateBlockServer, jManager.delegateMDOps, nil, nil, 994 TLFJournalBackgroundWorkPaused) 995 err = jManager.EnableExistingJournals( 996 ctx, session.UID, session.VerifyingKey, TLFJournalBackgroundWorkPaused) 997 require.NoError(t, err) 998 config.SetBlockCache(jManager.blockCache()) 999 config.SetBlockServer(jManager.blockServer()) 1000 config.SetMDOps(jManager.mdOps()) 1001 1002 // Make sure the team ID was persisted. 1003 1004 tj, ok := jManager.getTLFJournal(tlfID, nil) 1005 require.True(t, ok) 1006 require.Equal(t, id.AsUserOrTeam(), tj.chargedTo) 1007 1008 // Get the block. 1009 1010 buf, key, err := blockServer.Get(ctx, tlfID, bID, bCtx, DiskBlockAnyCache) 1011 require.NoError(t, err) 1012 require.Equal(t, data, buf) 1013 require.Equal(t, serverHalf, key) 1014 1015 // Get the MD. 1016 1017 head, err := mdOps.GetForTLF(ctx, tlfID, nil) 1018 require.NoError(t, err) 1019 require.Equal(t, rmd.Revision(), head.Revision()) 1020 } 1021 1022 func TestJournalQuotaStatus(t *testing.T) { 1023 tempdir, ctx, cancel, config, _, jManager := setupJournalManagerTest(t) 1024 defer teardownJournalManagerTest(ctx, t, tempdir, cancel, config) 1025 1026 // Set initial quota usage and refresh quotaUsage's cache. 1027 qbs := "aBlockServer{BlockServer: config.BlockServer()} 1028 config.SetBlockServer(qbs) 1029 qbs.setUserQuotaInfo(10, 1000, 20, 2000) 1030 1031 // Make sure the quota status is correct, even if we haven't 1032 // written anything yet. 1033 s, _ := jManager.Status(ctx) 1034 bs := s.DiskLimiterStatus.(backpressureDiskLimiterStatus) 1035 require.Equal( 1036 t, int64(10), bs.JournalTrackerStatus.QuotaStatus.RemoteUsedBytes) 1037 require.Equal( 1038 t, int64(1000), bs.JournalTrackerStatus.QuotaStatus.QuotaBytes) 1039 } 1040 1041 func TestJournalQuotaStatusForGitBlocks(t *testing.T) { 1042 tempdir, ctx, cancel, config, _, jManager := setupJournalManagerTest(t) 1043 defer teardownJournalManagerTest(ctx, t, tempdir, cancel, config) 1044 config.SetDefaultBlockType(keybase1.BlockType_GIT) 1045 1046 // Set initial quota usage and refresh quotaUsage's cache. 1047 qbs := "aBlockServer{BlockServer: config.BlockServer()} 1048 config.SetBlockServer(qbs) 1049 qbs.setUserQuotaInfo(10, 1000, 20, 2000) 1050 1051 // Make sure the quota status is correct, even if we haven't 1052 // written anything yet. 1053 s, _ := jManager.Status(ctx) 1054 bs := s.DiskLimiterStatus.(backpressureDiskLimiterStatus) 1055 require.Equal( 1056 t, int64(20), bs.JournalTrackerStatus.QuotaStatus.RemoteUsedBytes) 1057 require.Equal( 1058 t, int64(2000), bs.JournalTrackerStatus.QuotaStatus.QuotaBytes) 1059 } 1060 1061 func TestJournalManagerCorruptJournal(t *testing.T) { 1062 tempdir, ctx, cancel, config, _, jManager := setupJournalManagerTest(t) 1063 defer teardownJournalManagerTest(ctx, t, tempdir, cancel, config) 1064 1065 err := jManager.EnableAuto(ctx) 1066 require.NoError(t, err) 1067 1068 status, tlfIDs := jManager.Status(ctx) 1069 require.True(t, status.EnableAuto) 1070 require.Zero(t, status.JournalCount) 1071 require.Len(t, tlfIDs, 0) 1072 1073 blockServer := config.BlockServer() 1074 h, err := tlfhandle.ParseHandle( 1075 ctx, config.KBPKI(), config.MDOps(), nil, "test_user1", tlf.Private) 1076 require.NoError(t, err) 1077 id := h.ResolvedWriters()[0] 1078 tlfID := h.TlfID() 1079 1080 jManager.PauseBackgroundWork(ctx, tlfID) 1081 1082 bCtx := kbfsblock.MakeFirstContext(id, keybase1.BlockType_DATA) 1083 data := []byte{1, 2, 3, 4} 1084 bID, err := kbfsblock.MakePermanentID( 1085 data, kbfscrypto.EncryptionSecretboxWithKeyNonce) 1086 require.NoError(t, err) 1087 serverHalf, err := kbfscrypto.MakeRandomBlockCryptKeyServerHalf() 1088 require.NoError(t, err) 1089 err = blockServer.Put( 1090 ctx, tlfID, bID, bCtx, data, serverHalf, DiskBlockAnyCache) 1091 require.NoError(t, err) 1092 1093 status, tlfIDs = jManager.Status(ctx) 1094 require.True(t, status.EnableAuto) 1095 require.Equal(t, 1, status.JournalCount) 1096 require.Len(t, tlfIDs, 1) 1097 1098 t.Log("Stop the journal and corrupt info.json") 1099 tj, ok := jManager.getTLFJournal(tlfID, nil) 1100 require.True(t, ok) 1101 dir := tj.dir 1102 tj.shutdown(ctx) 1103 1104 infoPath := getTLFJournalInfoFilePath(dir) 1105 err = os.Truncate(infoPath, 0) 1106 require.NoError(t, err) 1107 1108 t.Log("Simulate a restart -- the corrupted journal shouldn't show up") 1109 jManager = makeJournalManager( 1110 config, jManager.log, tempdir, jManager.delegateBlockCache, 1111 jManager.delegateDirtyBlockCache, 1112 jManager.delegateBlockServer, jManager.delegateMDOps, nil, nil, 1113 TLFJournalBackgroundWorkPaused) 1114 session, err := config.KBPKI().GetCurrentSession(ctx) 1115 require.NoError(t, err) 1116 err = jManager.EnableExistingJournals( 1117 ctx, session.UID, session.VerifyingKey, TLFJournalBackgroundWorkPaused) 1118 require.NoError(t, err) 1119 status, tlfIDs = jManager.Status(ctx) 1120 require.True(t, status.EnableAuto) 1121 require.Equal(t, 0, status.JournalCount) 1122 require.Len(t, tlfIDs, 0) 1123 config.SetBlockServer( 1124 journalBlockServer{jManager, jManager.delegateBlockServer, false}) 1125 blockServer = config.BlockServer() 1126 config.SetMDOps(journalMDOps{jManager.delegateMDOps, jManager}) 1127 1128 t.Log("Try writing to the journal again, it should make a new one") 1129 _, err = tlfhandle.ParseHandle( 1130 ctx, config.KBPKI(), config.MDOps(), nil, "test_user1", tlf.Private) 1131 require.NoError(t, err) 1132 bCtx2 := kbfsblock.MakeFirstContext(id, keybase1.BlockType_DATA) 1133 data2 := []byte{4, 3, 2, 1} 1134 bID2, err := kbfsblock.MakePermanentID( 1135 data2, kbfscrypto.EncryptionSecretboxWithKeyNonce) 1136 require.NoError(t, err) 1137 serverHalf2, err := kbfscrypto.MakeRandomBlockCryptKeyServerHalf() 1138 require.NoError(t, err) 1139 err = blockServer.Put( 1140 ctx, tlfID, bID2, bCtx2, data2, serverHalf2, DiskBlockAnyCache) 1141 require.NoError(t, err) 1142 status, tlfIDs = jManager.Status(ctx) 1143 require.True(t, status.EnableAuto) 1144 require.Equal(t, 1, status.JournalCount) 1145 require.Len(t, tlfIDs, 1) 1146 }