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(false)
249	remoteA := repository.CreateGoGitTestRepo(true)
250	remoteB := repository.CreateGoGitTestRepo(true)
251	defer repository.CleanupTestRepos(repo, remoteA, remoteB)
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 = RemoveIdentity(repo, rene.Id())
279	require.NoError(t, err)
280
281	_, err = ReadLocal(repo, rene.Id())
282	require.Error(t, ErrIdentityNotExist, err)
283
284	_, err = ReadRemote(repo, "remoteA", string(rene.Id()))
285	require.Error(t, ErrIdentityNotExist, err)
286
287	_, err = ReadRemote(repo, "remoteB", string(rene.Id()))
288	require.Error(t, ErrIdentityNotExist, err)
289
290	ids, err := ListLocalIds(repo)
291	require.NoError(t, err)
292	require.Len(t, ids, 0)
293}