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