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{{PubKey: "pubkeyA"}})
40 require.NoError(t, err)
41
42 idBeforeCommit = identity.Id()
43
44 err = identity.Mutate(repo, func(orig *Mutator) {
45 orig.Keys = []*Key{{PubKey: "pubkeyB"}}
46 })
47 require.NoError(t, err)
48
49 err = identity.Mutate(repo, func(orig *Mutator) {
50 orig.Keys = []*Key{{PubKey: "pubkeyC"}}
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{{PubKey: "pubkeyD"}}
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{{PubKey: "pubkeyD"}, {PubKey: "pubkeyE"}}
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 identity := Identity{
127 versions: []*version{
128 {
129 times: map[string]lamport.Time{"foo": 100},
130 keys: []*Key{
131 {PubKey: "pubkeyA"},
132 },
133 },
134 {
135 times: map[string]lamport.Time{"foo": 200},
136 keys: []*Key{
137 {PubKey: "pubkeyB"},
138 },
139 },
140 {
141 times: map[string]lamport.Time{"foo": 201},
142 keys: []*Key{
143 {PubKey: "pubkeyC"},
144 },
145 },
146 {
147 times: map[string]lamport.Time{"foo": 201},
148 keys: []*Key{
149 {PubKey: "pubkeyD"},
150 },
151 },
152 {
153 times: map[string]lamport.Time{"foo": 300},
154 keys: []*Key{
155 {PubKey: "pubkeyE"},
156 },
157 },
158 },
159 }
160
161 require.Nil(t, identity.ValidKeysAtTime("foo", 10))
162 require.Equal(t, identity.ValidKeysAtTime("foo", 100), []*Key{{PubKey: "pubkeyA"}})
163 require.Equal(t, identity.ValidKeysAtTime("foo", 140), []*Key{{PubKey: "pubkeyA"}})
164 require.Equal(t, identity.ValidKeysAtTime("foo", 200), []*Key{{PubKey: "pubkeyB"}})
165 require.Equal(t, identity.ValidKeysAtTime("foo", 201), []*Key{{PubKey: "pubkeyD"}})
166 require.Equal(t, identity.ValidKeysAtTime("foo", 202), []*Key{{PubKey: "pubkeyD"}})
167 require.Equal(t, identity.ValidKeysAtTime("foo", 300), []*Key{{PubKey: "pubkeyE"}})
168 require.Equal(t, identity.ValidKeysAtTime("foo", 3000), []*Key{{PubKey: "pubkeyE"}})
169}
170
171// Test the immutable or mutable metadata search
172func TestMetadata(t *testing.T) {
173 repo := makeIdentityTestRepo(t)
174
175 identity, err := NewIdentity(repo, "René Descartes", "rene.descartes@example.com")
176 require.NoError(t, err)
177
178 identity.SetMetadata("key1", "value1")
179 assertHasKeyValue(t, identity.ImmutableMetadata(), "key1", "value1")
180 assertHasKeyValue(t, identity.MutableMetadata(), "key1", "value1")
181
182 err = identity.Commit(repo)
183 require.NoError(t, err)
184
185 assertHasKeyValue(t, identity.ImmutableMetadata(), "key1", "value1")
186 assertHasKeyValue(t, identity.MutableMetadata(), "key1", "value1")
187
188 // try override
189 err = identity.Mutate(repo, func(orig *Mutator) {
190 orig.Email = "rene@descartes.fr"
191 })
192 require.NoError(t, err)
193
194 identity.SetMetadata("key1", "value2")
195 assertHasKeyValue(t, identity.ImmutableMetadata(), "key1", "value1")
196 assertHasKeyValue(t, identity.MutableMetadata(), "key1", "value2")
197
198 err = identity.Commit(repo)
199 require.NoError(t, err)
200
201 // reload
202 loaded, err := ReadLocal(repo, identity.Id())
203 require.NoError(t, err)
204
205 assertHasKeyValue(t, loaded.ImmutableMetadata(), "key1", "value1")
206 assertHasKeyValue(t, loaded.MutableMetadata(), "key1", "value2")
207
208 // set metadata after commit
209 versionCount := len(identity.versions)
210 identity.SetMetadata("foo", "bar")
211 require.True(t, identity.NeedCommit())
212 require.Len(t, identity.versions, versionCount+1)
213
214 err = identity.Commit(repo)
215 require.NoError(t, err)
216 require.Len(t, identity.versions, versionCount+1)
217}
218
219func assertHasKeyValue(t *testing.T, metadata map[string]string, key, value string) {
220 val, ok := metadata[key]
221 require.True(t, ok)
222 require.Equal(t, val, value)
223}
224
225func TestJSON(t *testing.T) {
226 repo := makeIdentityTestRepo(t)
227
228 identity, err := NewIdentity(repo, "René Descartes", "rene.descartes@example.com")
229 require.NoError(t, err)
230
231 // commit to make sure we have an Id
232 err = identity.Commit(repo)
233 require.NoError(t, err)
234 require.NotEmpty(t, identity.Id())
235
236 // serialize
237 data, err := json.Marshal(identity)
238 require.NoError(t, err)
239
240 // deserialize, got a IdentityStub with the same id
241 var i Interface
242 i, err = UnmarshalJSON(data)
243 require.NoError(t, err)
244 require.Equal(t, identity.Id(), i.Id())
245
246 // make sure we can load the identity properly
247 i, err = ReadLocal(repo, i.Id())
248 require.NoError(t, err)
249}
250
251func TestIdentityRemove(t *testing.T) {
252 repo := repository.CreateGoGitTestRepo(false)
253 remoteA := repository.CreateGoGitTestRepo(true)
254 remoteB := repository.CreateGoGitTestRepo(true)
255 defer repository.CleanupTestRepos(repo, remoteA, remoteB)
256
257 err := repo.AddRemote("remoteA", remoteA.GetLocalRemote())
258 require.NoError(t, err)
259
260 err = repo.AddRemote("remoteB", remoteB.GetLocalRemote())
261 require.NoError(t, err)
262
263 // generate an identity for testing
264 rene, err := NewIdentity(repo, "René Descartes", "rene@descartes.fr")
265 require.NoError(t, err)
266
267 err = rene.Commit(repo)
268 require.NoError(t, err)
269
270 _, err = Push(repo, "remoteA")
271 require.NoError(t, err)
272
273 _, err = Push(repo, "remoteB")
274 require.NoError(t, err)
275
276 _, err = Fetch(repo, "remoteA")
277 require.NoError(t, err)
278
279 _, err = Fetch(repo, "remoteB")
280 require.NoError(t, err)
281
282 err = RemoveIdentity(repo, rene.Id())
283 require.NoError(t, err)
284
285 _, err = ReadLocal(repo, rene.Id())
286 require.Error(t, ErrIdentityNotExist, err)
287
288 _, err = ReadRemote(repo, "remoteA", string(rene.Id()))
289 require.Error(t, ErrIdentityNotExist, err)
290
291 _, err = ReadRemote(repo, "remoteB", string(rene.Id()))
292 require.Error(t, ErrIdentityNotExist, err)
293
294 ids, err := ListLocalIds(repo)
295 require.NoError(t, err)
296 require.Len(t, ids, 0)
297}