1package identity
2
3import (
4 "encoding/json"
5 "testing"
6
7 "github.com/stretchr/testify/require"
8
9 bootstrap "github.com/MichaelMure/git-bug/entity/boostrap"
10 "github.com/MichaelMure/git-bug/repository"
11 "github.com/MichaelMure/git-bug/util/lamport"
12)
13
14// Test the commit and load of an Identity with multiple versions
15func TestIdentityCommitLoad(t *testing.T) {
16 repo := makeIdentityTestRepo(t)
17
18 // single version
19
20 identity, err := NewIdentity(repo, "René Descartes", "rene.descartes@example.com")
21 require.NoError(t, err)
22
23 idBeforeCommit := identity.Id()
24
25 err = identity.Commit(repo)
26 require.NoError(t, err)
27
28 commitsAreSet(t, identity)
29 require.NotEmpty(t, identity.Id())
30 require.Equal(t, idBeforeCommit, identity.Id())
31 require.Equal(t, idBeforeCommit, identity.versions[0].Id())
32
33 loaded, err := ReadLocal(repo, identity.Id())
34 require.NoError(t, err)
35 commitsAreSet(t, loaded)
36 require.Equal(t, identity, loaded)
37
38 // multiple versions
39
40 identity, err = NewIdentityFull(repo, "René Descartes", "rene.descartes@example.com", "", "", []bootstrap.Key{generatePublicKey()})
41 require.NoError(t, err)
42
43 idBeforeCommit = identity.Id()
44
45 err = identity.Mutate(repo, func(orig *Mutator) {
46 orig.Keys = []bootstrap.Key{generatePublicKey()}
47 })
48 require.NoError(t, err)
49
50 err = identity.Mutate(repo, func(orig *Mutator) {
51 orig.Keys = []bootstrap.Key{generatePublicKey()}
52 })
53 require.NoError(t, err)
54
55 require.Equal(t, idBeforeCommit, identity.Id())
56
57 err = identity.Commit(repo)
58 require.NoError(t, err)
59
60 commitsAreSet(t, identity)
61 require.NotEmpty(t, identity.Id())
62 require.Equal(t, idBeforeCommit, identity.Id())
63 require.Equal(t, idBeforeCommit, identity.versions[0].Id())
64
65 loaded, err = ReadLocal(repo, identity.Id())
66 require.NoError(t, err)
67 commitsAreSet(t, loaded)
68 require.Equal(t, identity, loaded)
69
70 // add more version
71
72 err = identity.Mutate(repo, func(orig *Mutator) {
73 orig.Email = "rene@descartes.com"
74 orig.Keys = []bootstrap.Key{generatePublicKey()}
75 })
76 require.NoError(t, err)
77
78 err = identity.Mutate(repo, func(orig *Mutator) {
79 orig.Email = "rene@descartes.com"
80 orig.Keys = []bootstrap.Key{generatePublicKey(), generatePublicKey()}
81 })
82 require.NoError(t, err)
83
84 err = identity.Commit(repo)
85 require.NoError(t, err)
86
87 commitsAreSet(t, identity)
88 require.NotEmpty(t, identity.Id())
89 require.Equal(t, idBeforeCommit, identity.Id())
90 require.Equal(t, idBeforeCommit, identity.versions[0].Id())
91
92 loaded, err = ReadLocal(repo, identity.Id())
93 require.NoError(t, err)
94 commitsAreSet(t, loaded)
95 require.Equal(t, identity, loaded)
96}
97
98func TestIdentityMutate(t *testing.T) {
99 repo := makeIdentityTestRepo(t)
100
101 identity, err := NewIdentity(repo, "René Descartes", "rene.descartes@example.com")
102 require.NoError(t, err)
103
104 require.Len(t, identity.versions, 1)
105
106 err = identity.Mutate(repo, func(orig *Mutator) {
107 orig.Email = "rene@descartes.fr"
108 orig.Name = "René"
109 orig.Login = "rene"
110 })
111 require.NoError(t, err)
112
113 require.Len(t, identity.versions, 2)
114 require.Equal(t, identity.Email(), "rene@descartes.fr")
115 require.Equal(t, identity.Name(), "René")
116 require.Equal(t, identity.Login(), "rene")
117}
118
119func commitsAreSet(t *testing.T, identity *Identity) {
120 for _, version := range identity.versions {
121 require.NotEmpty(t, version.commitHash)
122 }
123}
124
125// Test that the correct crypto keys are returned for a given lamport time
126func TestIdentity_ValidKeysAtTime(t *testing.T) {
127 pubKeyA := generatePublicKey()
128 pubKeyB := generatePublicKey()
129 pubKeyC := generatePublicKey()
130 pubKeyD := generatePublicKey()
131 pubKeyE := generatePublicKey()
132
133 identity := Identity{
134 versions: []*version{
135 {
136 times: map[string]lamport.Time{"foo": 100},
137 keys: []bootstrap.Key{pubKeyA},
138 },
139 {
140 times: map[string]lamport.Time{"foo": 200},
141 keys: []bootstrap.Key{pubKeyB},
142 },
143 {
144 times: map[string]lamport.Time{"foo": 201},
145 keys: []bootstrap.Key{pubKeyC},
146 },
147 {
148 times: map[string]lamport.Time{"foo": 201},
149 keys: []bootstrap.Key{pubKeyD},
150 },
151 {
152 times: map[string]lamport.Time{"foo": 300},
153 keys: []bootstrap.Key{pubKeyE},
154 },
155 },
156 }
157
158 require.Nil(t, identity.ValidKeysAtTime("foo", 10))
159 require.Equal(t, identity.ValidKeysAtTime("foo", 100), []bootstrap.Key{pubKeyA})
160 require.Equal(t, identity.ValidKeysAtTime("foo", 140), []bootstrap.Key{pubKeyA})
161 require.Equal(t, identity.ValidKeysAtTime("foo", 200), []bootstrap.Key{pubKeyB})
162 require.Equal(t, identity.ValidKeysAtTime("foo", 201), []bootstrap.Key{pubKeyD})
163 require.Equal(t, identity.ValidKeysAtTime("foo", 202), []bootstrap.Key{pubKeyD})
164 require.Equal(t, identity.ValidKeysAtTime("foo", 300), []bootstrap.Key{pubKeyE})
165 require.Equal(t, identity.ValidKeysAtTime("foo", 3000), []bootstrap.Key{pubKeyE})
166}
167
168// Test the immutable or mutable metadata search
169func TestMetadata(t *testing.T) {
170 repo := makeIdentityTestRepo(t)
171
172 identity, err := NewIdentity(repo, "René Descartes", "rene.descartes@example.com")
173 require.NoError(t, err)
174
175 identity.SetMetadata("key1", "value1")
176 assertHasKeyValue(t, identity.ImmutableMetadata(), "key1", "value1")
177 assertHasKeyValue(t, identity.MutableMetadata(), "key1", "value1")
178
179 err = identity.Commit(repo)
180 require.NoError(t, err)
181
182 assertHasKeyValue(t, identity.ImmutableMetadata(), "key1", "value1")
183 assertHasKeyValue(t, identity.MutableMetadata(), "key1", "value1")
184
185 // try override
186 err = identity.Mutate(repo, func(orig *Mutator) {
187 orig.Email = "rene@descartes.fr"
188 })
189 require.NoError(t, err)
190
191 identity.SetMetadata("key1", "value2")
192 assertHasKeyValue(t, identity.ImmutableMetadata(), "key1", "value1")
193 assertHasKeyValue(t, identity.MutableMetadata(), "key1", "value2")
194
195 err = identity.Commit(repo)
196 require.NoError(t, err)
197
198 // reload
199 loaded, err := ReadLocal(repo, identity.Id())
200 require.NoError(t, err)
201
202 assertHasKeyValue(t, loaded.ImmutableMetadata(), "key1", "value1")
203 assertHasKeyValue(t, loaded.MutableMetadata(), "key1", "value2")
204
205 // set metadata after commit
206 versionCount := len(identity.versions)
207 identity.SetMetadata("foo", "bar")
208 require.True(t, identity.NeedCommit())
209 require.Len(t, identity.versions, versionCount+1)
210
211 err = identity.Commit(repo)
212 require.NoError(t, err)
213 require.Len(t, identity.versions, versionCount+1)
214}
215
216func assertHasKeyValue(t *testing.T, metadata map[string]string, key, value string) {
217 val, ok := metadata[key]
218 require.True(t, ok)
219 require.Equal(t, val, value)
220}
221
222func TestJSON(t *testing.T) {
223 repo := makeIdentityTestRepo(t)
224
225 identity, err := NewIdentity(repo, "René Descartes", "rene.descartes@example.com")
226 require.NoError(t, err)
227
228 // commit to make sure we have an Id
229 err = identity.Commit(repo)
230 require.NoError(t, err)
231 require.NotEmpty(t, identity.Id())
232
233 // serialize
234 data, err := json.Marshal(identity)
235 require.NoError(t, err)
236
237 // deserialize, got a IdentityStub with the same id
238 var i bootstrap.Identity
239 i, err = UnmarshalJSON(data)
240 require.NoError(t, err)
241 require.Equal(t, identity.Id(), i.Id())
242
243 // make sure we can load the identity properly
244 i, err = ReadLocal(repo, i.Id())
245 require.NoError(t, err)
246}
247
248func TestIdentityRemove(t *testing.T) {
249 repo := repository.CreateGoGitTestRepo(t, false)
250 remoteA := repository.CreateGoGitTestRepo(t, true)
251 remoteB := repository.CreateGoGitTestRepo(t, true)
252
253 err := repo.AddRemote("remoteA", remoteA.GetLocalRemote())
254 require.NoError(t, err)
255
256 err = repo.AddRemote("remoteB", remoteB.GetLocalRemote())
257 require.NoError(t, err)
258
259 // generate an identity for testing
260 rene, err := NewIdentity(repo, "René Descartes", "rene@descartes.fr")
261 require.NoError(t, err)
262
263 err = rene.Commit(repo)
264 require.NoError(t, err)
265
266 _, err = Push(repo, "remoteA")
267 require.NoError(t, err)
268
269 _, err = Push(repo, "remoteB")
270 require.NoError(t, err)
271
272 _, err = Fetch(repo, "remoteA")
273 require.NoError(t, err)
274
275 _, err = Fetch(repo, "remoteB")
276 require.NoError(t, err)
277
278 err = Remove(repo, rene.Id())
279 require.NoError(t, err)
280
281 _, err = ReadLocal(repo, rene.Id())
282 require.ErrorAs(t, bootstrap.ErrNotFound{}, err)
283
284 _, err = ReadRemote(repo, "remoteA", string(rene.Id()))
285 require.ErrorAs(t, bootstrap.ErrNotFound{}, err)
286
287 _, err = ReadRemote(repo, "remoteB", string(rene.Id()))
288 require.ErrorAs(t, bootstrap.ErrNotFound{}, err)
289
290 ids, err := ListLocalIds(repo)
291 require.NoError(t, err)
292 require.Len(t, ids, 0)
293}