1package libkb
2
3import (
4	"strings"
5	"testing"
6
7	"github.com/keybase/client/go/msgpack"
8	keybase1 "github.com/keybase/client/go/protocol/keybase1"
9	"github.com/stretchr/testify/require"
10)
11
12// requireErrorHasSuffix makes sure that err's string has
13// expectedErrSuffix's string as a suffix. This is necessary as
14// go-codec prepends stuff to any errors it catches.
15func requireErrorHasSuffix(t *testing.T, expectedErrSuffix, err error) {
16	t.Helper()
17	require.Error(t, err)
18	require.True(t, strings.HasSuffix(err.Error(), expectedErrSuffix.Error()), "Expected %q to have %q as a suffix", err, expectedErrSuffix)
19}
20
21// Test that various ways in which OuterLinkV2WithMetadata may be
22// encoded/decoded all fail.
23
24func TestOuterLinkV2WithMetadataEncode(t *testing.T) {
25	var o OuterLinkV2WithMetadata
26	_, err := msgpack.Encode(o)
27	requireErrorHasSuffix(t, errCodecEncodeSelf, err)
28	_, err = msgpack.Encode(&o)
29	requireErrorHasSuffix(t, errCodecEncodeSelf, err)
30}
31
32func TestOuterLinkV2WithMetadataDecode(t *testing.T) {
33	var o OuterLinkV2WithMetadata
34	err := msgpack.Decode(&o, []byte{0x1, 0x2})
35	requireErrorHasSuffix(t, errCodecDecodeSelf, err)
36}
37
38type outerLinkV2WithMetadataEmbedder struct {
39	OuterLinkV2WithMetadata
40}
41
42func TestOuterLinkV2WithMetadataEmbedderEncode(t *testing.T) {
43	var o outerLinkV2WithMetadataEmbedder
44	_, err := msgpack.Encode(o)
45	requireErrorHasSuffix(t, errCodecEncodeSelf, err)
46}
47
48func TestOuterLinkV2WithMetadataEmbedderDecode(t *testing.T) {
49	var o outerLinkV2WithMetadataEmbedder
50	err := msgpack.Decode(&o, []byte{0x1, 0x2})
51	requireErrorHasSuffix(t, errCodecDecodeSelf, err)
52}
53
54type outerLinkV2WithMetadataPointerEmbedder struct {
55	*OuterLinkV2WithMetadata
56}
57
58func TestOuterLinkV2WithMetadataPointerEmbedderEncode(t *testing.T) {
59	o := outerLinkV2WithMetadataPointerEmbedder{
60		OuterLinkV2WithMetadata: &OuterLinkV2WithMetadata{},
61	}
62	_, err := msgpack.Encode(o)
63	requireErrorHasSuffix(t, errCodecEncodeSelf, err)
64}
65
66func TestOuterLinkV2WithMetadataPointerEmbedderDecode(t *testing.T) {
67	var o outerLinkV2WithMetadataPointerEmbedder
68	err := msgpack.Decode(&o, []byte{0x1, 0x2})
69	requireErrorHasSuffix(t, errCodecDecodeSelf, err)
70}
71
72type outerLinkV2WithMetadataContainer struct {
73	O OuterLinkV2WithMetadata
74}
75
76func TestOuterLinkV2WithMetadataContainerEncode(t *testing.T) {
77	var o outerLinkV2WithMetadataContainer
78	_, err := msgpack.Encode(o)
79	requireErrorHasSuffix(t, errCodecEncodeSelf, err)
80}
81
82func TestOuterLinkV2WithMetadataContainerDecode(t *testing.T) {
83	bytes, err := msgpack.Encode(map[string]interface{}{
84		"O": []byte{0x01, 0x02},
85	})
86	require.NoError(t, err)
87
88	var o outerLinkV2WithMetadataContainer
89	err = msgpack.Decode(&o, bytes)
90	requireErrorHasSuffix(t, errCodecDecodeSelf, err)
91}
92
93type outerLinkV2WithMetadataPointerContainer struct {
94	O *OuterLinkV2WithMetadata
95}
96
97func TestOuterLinkV2WithMetadataPointerContainerEncode(t *testing.T) {
98	o := outerLinkV2WithMetadataPointerContainer{
99		O: &OuterLinkV2WithMetadata{},
100	}
101	_, err := msgpack.Encode(o)
102	requireErrorHasSuffix(t, errCodecEncodeSelf, err)
103}
104
105func TestOuterLinkV2WithMetadataPointerContainerDecode(t *testing.T) {
106	bytes, err := msgpack.Encode(map[string]interface{}{
107		"O": []byte{0x01, 0x02},
108	})
109	require.NoError(t, err)
110
111	var o outerLinkV2WithMetadataPointerContainer
112	err = msgpack.Decode(&o, bytes)
113	requireErrorHasSuffix(t, errCodecDecodeSelf, err)
114}
115
116func serdeOuterLink(t *testing.T, tc TestContext, seqno keybase1.Seqno, highSkipSeqno *keybase1.Seqno, highSkipHash LinkID) OuterLinkV2 {
117	m := NewMetaContextForTest(tc)
118
119	AddEnvironmentFeatureForTest(tc, EnvironmentFeatureAllowHighSkips)
120
121	var highSkip *HighSkip
122	if highSkipSeqno != nil {
123		highSkipPre := NewHighSkip(*highSkipSeqno, highSkipHash)
124		highSkip = &highSkipPre
125	}
126	encoded, err := encodeOuterLink(m, LinkTypeLeave, seqno, nil, nil, false, keybase1.SeqType_PUBLIC, false, highSkip)
127	require.NoError(t, err)
128
129	o2 := OuterLinkV2{}
130	err = msgpack.Decode(&o2, encoded)
131	require.NoError(t, err)
132	return o2
133}
134
135func highSkipMatch(ol OuterLinkV2, highSkip *HighSkip) error {
136	return ol.AssertFields(ol.Version, ol.Seqno, ol.Prev, ol.Curr, ol.LinkType, ol.SeqType, ol.IgnoreIfUnsupported, highSkip)
137}
138
139func TestHighSkipBackwardsCompatibility(t *testing.T) {
140	tc := SetupTest(t, "test_high_skip_backwards_compatibility", 1)
141	defer tc.Cleanup()
142
143	seqno := keybase1.Seqno(1)
144	highSkipSeqno := keybase1.Seqno(0)
145
146	o := serdeOuterLink(t, tc, seqno, nil, nil)
147	require.True(t, o.HighSkipSeqno == nil)
148	require.True(t, o.HighSkipHash == nil)
149	require.NoError(t, highSkipMatch(o, nil))
150
151	o = serdeOuterLink(t, tc, seqno, &highSkipSeqno, nil)
152	require.True(t, *o.HighSkipSeqno == 0)
153	require.True(t, o.HighSkipHash == nil)
154	highSkip := NewHighSkip(keybase1.Seqno(0), nil)
155	badHighSkip1 := NewHighSkip(keybase1.Seqno(0), []byte{0, 5, 2})
156	badHighSkip2 := NewHighSkip(keybase1.Seqno(2), nil)
157	require.NoError(t, highSkipMatch(o, &highSkip))
158	require.Error(t, highSkipMatch(o, &badHighSkip1))
159	require.Error(t, highSkipMatch(o, &badHighSkip2))
160
161	seqno = keybase1.Seqno(10)
162	highSkipSeqno = keybase1.Seqno(5)
163
164	highSkipHash := []byte{0, 6, 2, 42, 123}
165	o = serdeOuterLink(t, tc, seqno, &highSkipSeqno, highSkipHash)
166	highSkip = NewHighSkip(keybase1.Seqno(5), highSkipHash)
167	badHighSkip1 = NewHighSkip(keybase1.Seqno(5), []byte{0, 5, 2})
168	badHighSkip2 = NewHighSkip(keybase1.Seqno(5), nil)
169	require.NoError(t, highSkipMatch(o, &highSkip))
170	require.Error(t, highSkipMatch(o, &badHighSkip1))
171	require.Error(t, highSkipMatch(o, &badHighSkip2))
172}
173