github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/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 := &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  
   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 := &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  
   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 := &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  
  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 := &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  
  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  }