identity_test.go

  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}