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	"context"
9	"fmt"
10	"testing"
11	"time"
12
13	idutiltest "github.com/keybase/client/go/kbfs/idutil/test"
14	"github.com/keybase/client/go/kbfs/kbfscodec"
15	"github.com/keybase/client/go/kbfs/kbfscrypto"
16	"github.com/keybase/client/go/kbfs/kbfsmd"
17	"github.com/keybase/client/go/kbfs/tlf"
18	"github.com/keybase/client/go/kbfs/tlfhandle"
19	kbname "github.com/keybase/client/go/kbun"
20	"github.com/keybase/client/go/protocol/keybase1"
21	"github.com/stretchr/testify/require"
22)
23
24func testMdcacheMakeHandle(t *testing.T, n uint32) *tlfhandle.Handle {
25	id := keybase1.MakeTestUID(n).AsUserOrTeam()
26	bh, err := tlf.MakeHandle([]keybase1.UserOrTeamID{id}, nil, nil, nil, nil)
27	require.NoError(t, err)
28
29	nug := idutiltest.NormalizedUsernameGetter{
30		id: kbname.NormalizedUsername(fmt.Sprintf("fake_user_%d", n)),
31	}
32
33	ctx := context.Background()
34	h, err := tlfhandle.MakeHandle(
35		ctx, bh, bh.Type(), nil, nug, nil, keybase1.OfflineAvailability_NONE)
36	require.NoError(t, err)
37	return h
38}
39
40func testMdcachePut(t *testing.T, tlfID tlf.ID, rev kbfsmd.Revision,
41	bid kbfsmd.BranchID, h *tlfhandle.Handle, mdcache *MDCacheStandard) {
42	rmd, err := makeInitialRootMetadata(defaultClientMetadataVer, tlfID, h)
43	require.NoError(t, err)
44	rmd.SetRevision(rev)
45	if bid != kbfsmd.NullBranchID {
46		rmd.SetUnmerged()
47		rmd.SetBranchID(bid)
48	}
49
50	signingKey := kbfscrypto.MakeFakeSigningKeyOrBust("fake signing key")
51	err = rmd.bareMd.SignWriterMetadataInternally(context.Background(),
52		kbfscodec.NewMsgpack(),
53		kbfscrypto.SigningKeySigner{Key: signingKey})
54	require.NoError(t, err)
55
56	// put the md
57	irmd := MakeImmutableRootMetadata(
58		rmd, signingKey.GetVerifyingKey(), kbfsmd.FakeID(1), time.Now(), true)
59	if err := mdcache.Put(irmd); err != nil {
60		t.Errorf("Got error on put on md %v: %v", tlfID, err)
61	}
62
63	// make sure we can get it successfully
64	irmd2, err := mdcache.Get(tlfID, rev, bid)
65	require.NoError(t, err)
66	require.Equal(t, irmd, irmd2)
67}
68
69func TestMdcachePut(t *testing.T) {
70	tlfID := tlf.FakeID(1, tlf.Private)
71	h := testMdcacheMakeHandle(t, 1)
72
73	mdcache := NewMDCacheStandard(100)
74	testMdcachePut(t, tlfID, 1, kbfsmd.NullBranchID, h, mdcache)
75}
76
77func TestMdcachePutPastCapacity(t *testing.T) {
78	id0 := tlf.FakeID(1, tlf.Private)
79	h0 := testMdcacheMakeHandle(t, 0)
80
81	id1 := tlf.FakeID(2, tlf.Private)
82	h1 := testMdcacheMakeHandle(t, 1)
83
84	id2 := tlf.FakeID(3, tlf.Private)
85	h2 := testMdcacheMakeHandle(t, 2)
86
87	mdcache := NewMDCacheStandard(2)
88	testMdcachePut(t, id0, 0, kbfsmd.NullBranchID, h0, mdcache)
89	bid := kbfsmd.FakeBranchID(1)
90	testMdcachePut(t, id1, 0, bid, h1, mdcache)
91	testMdcachePut(t, id2, 1, kbfsmd.NullBranchID, h2, mdcache)
92
93	// id 0 should no longer be in the cache
94	_, err := mdcache.Get(id0, 0, kbfsmd.NullBranchID)
95	require.Equal(t, NoSuchMDError{id0, 0, kbfsmd.NullBranchID}, err)
96}
97
98func TestMdcacheReplace(t *testing.T) {
99	id := tlf.FakeID(1, tlf.Private)
100	h := testMdcacheMakeHandle(t, 1)
101
102	mdcache := NewMDCacheStandard(100)
103	testMdcachePut(t, id, 1, kbfsmd.NullBranchID, h, mdcache)
104
105	irmd, err := mdcache.Get(id, 1, kbfsmd.NullBranchID)
106	require.NoError(t, err)
107
108	// Change the BID
109	bid := kbfsmd.FakeBranchID(1)
110	newRmd, err := irmd.deepCopy(kbfscodec.NewMsgpack())
111	require.NoError(t, err)
112
113	newRmd.SetBranchID(bid)
114	err = mdcache.Replace(MakeImmutableRootMetadata(newRmd,
115		irmd.LastModifyingWriterVerifyingKey(), kbfsmd.FakeID(2), time.Now(),
116		true), kbfsmd.NullBranchID)
117	require.NoError(t, err)
118
119	_, err = mdcache.Get(id, 1, kbfsmd.NullBranchID)
120	require.IsType(t, NoSuchMDError{}, err)
121	_, err = mdcache.Get(id, 1, bid)
122	require.NoError(t, err)
123}
124