1package identity
2
3import (
4 "encoding/json"
5 "strings"
6 "testing"
7
8 "github.com/MichaelMure/git-bug/entity"
9 "github.com/MichaelMure/git-bug/repository"
10 "github.com/stretchr/testify/assert"
11 "github.com/stretchr/testify/require"
12 "golang.org/x/crypto/openpgp"
13 "golang.org/x/crypto/openpgp/armor"
14)
15
16// createPubkey returns an armored public PGP key.
17func createPubkey(t *testing.T) string {
18 // Generate a key pair for signing commits.
19 pgpEntity, err := openpgp.NewEntity("First Last", "", "fl@example.org", nil)
20 require.NoError(t, err)
21
22 // Armor the public part.
23 pubBuilder := &strings.Builder{}
24 w, err := armor.Encode(pubBuilder, openpgp.PublicKeyType, nil)
25 require.NoError(t, err)
26 err = pgpEntity.Serialize(w)
27 require.NoError(t, err)
28 err = w.Close()
29 require.NoError(t, err)
30 armoredPub := pubBuilder.String()
31 return armoredPub
32}
33
34// Test the commit and load of an Identity with multiple versions
35func TestIdentityCommitLoad(t *testing.T) {
36 mockRepo := repository.NewMockRepoForTest()
37
38 // single version
39
40 identity := &Identity{
41 id: entity.UnsetId,
42 versions: []*Version{
43 {
44 name: "René Descartes",
45 email: "rene.descartes@example.com",
46 },
47 },
48 }
49
50 err := identity.Commit(mockRepo)
51
52 assert.Nil(t, err)
53 assert.NotEmpty(t, identity.id)
54
55 loaded, err := ReadLocal(mockRepo, identity.id)
56 assert.Nil(t, err)
57 commitsAreSet(t, loaded)
58 assert.Equal(t, identity, loaded)
59
60 // multiple version
61
62 identity = &Identity{
63 id: entity.UnsetId,
64 versions: []*Version{
65 {
66 time: 100,
67 name: "René Descartes",
68 email: "rene.descartes@example.com",
69 keys: []*Key{
70 {ArmoredPublicKey: createPubkey(t)},
71 },
72 },
73 {
74 time: 200,
75 name: "René Descartes",
76 email: "rene.descartes@example.com",
77 keys: []*Key{
78 {ArmoredPublicKey: createPubkey(t)},
79 },
80 },
81 {
82 time: 201,
83 name: "René Descartes",
84 email: "rene.descartes@example.com",
85 keys: []*Key{
86 {ArmoredPublicKey: createPubkey(t)},
87 },
88 },
89 },
90 }
91
92 err = identity.Commit(mockRepo)
93
94 assert.Nil(t, err)
95 assert.NotEmpty(t, identity.id)
96
97 loaded, err = ReadLocal(mockRepo, identity.id)
98 assert.Nil(t, err)
99 commitsAreSet(t, loaded)
100 loadKeys(loaded)
101 assert.Equal(t, identity, loaded)
102
103 // add more version
104
105 identity.Mutate(func(orig Mutator) Mutator {
106
107 return orig
108 })
109
110 identity.addVersionForTest(&Version{
111 time: 201,
112 name: "René Descartes",
113 email: "rene.descartes@example.com",
114 keys: []*Key{
115 {ArmoredPublicKey: createPubkey(t)},
116 },
117 })
118
119 identity.addVersionForTest(&Version{
120 time: 300,
121 name: "René Descartes",
122 email: "rene.descartes@example.com",
123 keys: []*Key{
124 {ArmoredPublicKey: createPubkey(t)},
125 },
126 })
127
128 err = identity.Commit(mockRepo)
129
130 assert.Nil(t, err)
131 assert.NotEmpty(t, identity.id)
132
133 loaded, err = ReadLocal(mockRepo, identity.id)
134 assert.Nil(t, err)
135 commitsAreSet(t, loaded)
136 loadKeys(loaded)
137 assert.Equal(t, identity, loaded)
138}
139
140func loadKeys(identity *Identity) {
141 for _, v := range identity.versions {
142 for _, k := range v.keys {
143 k.GetPublicKey()
144 }
145 }
146}
147
148func commitsAreSet(t *testing.T, identity *Identity) {
149 for _, version := range identity.versions {
150 assert.NotEmpty(t, version.commitHash)
151 }
152}
153
154// Test that the correct crypto keys are returned for a given lamport time
155func TestIdentity_ValidKeysAtTime(t *testing.T) {
156 identity := Identity{
157 id: entity.UnsetId,
158 versions: []*Version{
159 {
160 time: 100,
161 name: "René Descartes",
162 email: "rene.descartes@example.com",
163 keys: []*Key{
164 {ArmoredPublicKey: "pubkeyA"},
165 },
166 },
167 {
168 time: 200,
169 name: "René Descartes",
170 email: "rene.descartes@example.com",
171 keys: []*Key{
172 {ArmoredPublicKey: "pubkeyB"},
173 },
174 },
175 {
176 time: 201,
177 name: "René Descartes",
178 email: "rene.descartes@example.com",
179 keys: []*Key{
180 {ArmoredPublicKey: "pubkeyC"},
181 },
182 },
183 {
184 time: 201,
185 name: "René Descartes",
186 email: "rene.descartes@example.com",
187 keys: []*Key{
188 {ArmoredPublicKey: "pubkeyD"},
189 },
190 },
191 {
192 time: 300,
193 name: "René Descartes",
194 email: "rene.descartes@example.com",
195 keys: []*Key{
196 {ArmoredPublicKey: "pubkeyE"},
197 },
198 },
199 },
200 }
201
202 assert.Nil(t, identity.ValidKeysAtTime(10))
203 assert.Equal(t, identity.ValidKeysAtTime(100), []*Key{{ArmoredPublicKey: "pubkeyA"}})
204 assert.Equal(t, identity.ValidKeysAtTime(140), []*Key{{ArmoredPublicKey: "pubkeyA"}})
205 assert.Equal(t, identity.ValidKeysAtTime(200), []*Key{{ArmoredPublicKey: "pubkeyB"}})
206 assert.Equal(t, identity.ValidKeysAtTime(201), []*Key{{ArmoredPublicKey: "pubkeyD"}})
207 assert.Equal(t, identity.ValidKeysAtTime(202), []*Key{{ArmoredPublicKey: "pubkeyD"}})
208 assert.Equal(t, identity.ValidKeysAtTime(300), []*Key{{ArmoredPublicKey: "pubkeyE"}})
209 assert.Equal(t, identity.ValidKeysAtTime(3000), []*Key{{ArmoredPublicKey: "pubkeyE"}})
210}
211
212// Test the immutable or mutable metadata search
213func TestMetadata(t *testing.T) {
214 mockRepo := repository.NewMockRepoForTest()
215
216 identity := NewIdentity("René Descartes", "rene.descartes@example.com")
217
218 identity.SetMetadata("key1", "value1")
219 assertHasKeyValue(t, identity.ImmutableMetadata(), "key1", "value1")
220 assertHasKeyValue(t, identity.MutableMetadata(), "key1", "value1")
221
222 err := identity.Commit(mockRepo)
223 assert.NoError(t, err)
224
225 assertHasKeyValue(t, identity.ImmutableMetadata(), "key1", "value1")
226 assertHasKeyValue(t, identity.MutableMetadata(), "key1", "value1")
227
228 // try override
229 identity.addVersionForTest(&Version{
230 name: "René Descartes",
231 email: "rene.descartes@example.com",
232 })
233
234 identity.SetMetadata("key1", "value2")
235 assertHasKeyValue(t, identity.ImmutableMetadata(), "key1", "value1")
236 assertHasKeyValue(t, identity.MutableMetadata(), "key1", "value2")
237
238 err = identity.Commit(mockRepo)
239 assert.NoError(t, err)
240
241 // reload
242 loaded, err := ReadLocal(mockRepo, identity.id)
243 assert.Nil(t, err)
244
245 assertHasKeyValue(t, loaded.ImmutableMetadata(), "key1", "value1")
246 assertHasKeyValue(t, loaded.MutableMetadata(), "key1", "value2")
247}
248
249func assertHasKeyValue(t *testing.T, metadata map[string]string, key, value string) {
250 val, ok := metadata[key]
251 assert.True(t, ok)
252 assert.Equal(t, val, value)
253}
254
255func TestJSON(t *testing.T) {
256 mockRepo := repository.NewMockRepoForTest()
257
258 identity := &Identity{
259 id: entity.UnsetId,
260 versions: []*Version{
261 {
262 name: "René Descartes",
263 email: "rene.descartes@example.com",
264 },
265 },
266 }
267
268 // commit to make sure we have an Id
269 err := identity.Commit(mockRepo)
270 assert.Nil(t, err)
271 assert.NotEmpty(t, identity.id)
272
273 // serialize
274 data, err := json.Marshal(identity)
275 assert.NoError(t, err)
276
277 // deserialize, got a IdentityStub with the same id
278 var i Interface
279 i, err = UnmarshalJSON(data)
280 assert.NoError(t, err)
281 assert.Equal(t, identity.id, i.Id())
282
283 // make sure we can load the identity properly
284 i, err = ReadLocal(mockRepo, i.Id())
285 assert.NoError(t, err)
286}