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
5package libkbfs
6
7import (
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
29func 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
81func 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
90type quotaBlockServer struct {
91	BlockServer
92
93	quotaInfoLock sync.Mutex
94	userQuotaInfo kbfsblock.QuotaInfo
95	teamQuotaInfo map[keybase1.TeamID]kbfsblock.QuotaInfo
96}
97
98func (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
112func (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
129func (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
137func (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
146func 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 := &quotaBlockServer{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
270type tlfJournalConfigWithDiskLimitTimeout struct {
271	tlfJournalConfig
272	dlTimeout time.Duration
273}
274
275func (c tlfJournalConfigWithDiskLimitTimeout) diskLimitTimeout() time.Duration {
276	return c.dlTimeout
277}
278
279func 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 := &quotaBlockServer{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
374func 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
450func 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
531func 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
560func 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
732func 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
811func 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
875func 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
938func 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
1022func 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 := &quotaBlockServer{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
1041func 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 := &quotaBlockServer{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
1061func 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}
1147