repo_cache_test.go

  1package cache
  2
  3import (
  4	"strings"
  5	"testing"
  6	"time"
  7
  8	"github.com/stretchr/testify/assert"
  9	"github.com/stretchr/testify/require"
 10
 11	"github.com/MichaelMure/git-bug/entities/bug"
 12	"github.com/MichaelMure/git-bug/query"
 13	"github.com/MichaelMure/git-bug/repository"
 14)
 15
 16func TestCache(t *testing.T) {
 17	repo := repository.CreateGoGitTestRepo(t, false)
 18	cache, stderr := NewTestRepoCache(t, repo)
 19
 20	// Create, set and get user identity
 21	iden1, err := cache.NewIdentity("René Descartes", "rene@descartes.fr")
 22	require.NoError(t, err)
 23	err = cache.SetUserIdentity(iden1)
 24	require.NoError(t, err)
 25	userIden, err := cache.GetUserIdentity()
 26	require.NoError(t, err)
 27	require.Equal(t, iden1.Id(), userIden.Id())
 28
 29	// it's possible to create two identical identities
 30	iden2, err := cache.NewIdentity("René Descartes", "rene@descartes.fr")
 31	require.NoError(t, err)
 32
 33	// Two identical identities yield a different id
 34	require.NotEqual(t, iden1.Id(), iden2.Id())
 35
 36	// There is now two identities in the cache
 37	require.Len(t, cache.AllIdentityIds(), 2)
 38	require.Len(t, cache.identitiesExcerpts, 2)
 39	require.Len(t, cache.identities, 2)
 40
 41	// Create a bug
 42	bug1, _, err := cache.NewBug("title", "message")
 43	require.NoError(t, err)
 44
 45	// It's possible to create two identical bugs
 46	bug2, _, err := cache.NewBug("title", "message")
 47	require.NoError(t, err)
 48
 49	// two identical bugs yield a different id
 50	require.NotEqual(t, bug1.Id(), bug2.Id())
 51
 52	// There is now two bugs in the cache
 53	require.Len(t, cache.AllBugsIds(), 2)
 54	require.Len(t, cache.bugExcerpts, 2)
 55	require.Len(t, cache.bugs, 2)
 56
 57	// Resolving
 58	_, err = cache.ResolveIdentity(iden1.Id())
 59	require.NoError(t, err)
 60	_, err = cache.ResolveIdentityExcerpt(iden1.Id())
 61	require.NoError(t, err)
 62	_, err = cache.ResolveIdentityPrefix(iden1.Id().String()[:10])
 63	require.NoError(t, err)
 64
 65	_, err = cache.ResolveBug(bug1.Id())
 66	require.NoError(t, err)
 67	_, err = cache.ResolveBugExcerpt(bug1.Id())
 68	require.NoError(t, err)
 69	_, err = cache.ResolveBugPrefix(bug1.Id().String()[:10])
 70	require.NoError(t, err)
 71
 72	// Querying
 73	q, err := query.Parse("status:open author:descartes sort:edit-asc")
 74	require.NoError(t, err)
 75	res, err := cache.QueryBugs(q)
 76	require.NoError(t, err)
 77	require.Len(t, res, 2)
 78
 79	// Close
 80	require.NoError(t, cache.Close())
 81	require.Empty(t, cache.bugs)
 82	require.Empty(t, cache.bugExcerpts)
 83	require.Empty(t, cache.identities)
 84	require.Empty(t, cache.identitiesExcerpts)
 85
 86	// There should be no output to stderr
 87	require.Empty(t, stderr.String())
 88
 89	// Reload, only excerpt are loaded, but as we need to load the identities used in the bugs
 90	// to check the signatures, we also load the identity used above
 91	cache, stderr = NewTestRepoCache(t, repo)
 92	require.Empty(t, cache.bugs)
 93	require.Len(t, cache.identities, 1)
 94	require.Len(t, cache.bugExcerpts, 2)
 95	require.Len(t, cache.identitiesExcerpts, 2)
 96
 97	// Resolving load from the disk
 98	_, err = cache.ResolveIdentity(iden1.Id())
 99	require.NoError(t, err)
100	_, err = cache.ResolveIdentityExcerpt(iden1.Id())
101	require.NoError(t, err)
102	_, err = cache.ResolveIdentityPrefix(iden1.Id().String()[:10])
103	require.NoError(t, err)
104
105	_, err = cache.ResolveBug(bug1.Id())
106	require.NoError(t, err)
107	_, err = cache.ResolveBugExcerpt(bug1.Id())
108	require.NoError(t, err)
109	_, err = cache.ResolveBugPrefix(bug1.Id().String()[:10])
110	require.NoError(t, err)
111
112	require.Empty(t, stderr.String())
113}
114
115func TestCachePushPull(t *testing.T) {
116	repoA, repoB, _ := repository.SetupGoGitReposAndRemote(t)
117	cacheA, stderrA := NewTestRepoCache(t, repoA)
118	cacheB, stderrB := NewTestRepoCache(t, repoB)
119
120	// Create, set and get user identity
121	reneA, err := cacheA.NewIdentity("René Descartes", "rene@descartes.fr")
122	require.NoError(t, err)
123	err = cacheA.SetUserIdentity(reneA)
124	require.NoError(t, err)
125	isaacB, err := cacheB.NewIdentity("Isaac Newton", "isaac@newton.uk")
126	require.NoError(t, err)
127	err = cacheB.SetUserIdentity(isaacB)
128	require.NoError(t, err)
129
130	// distribute the identity
131	_, err = cacheA.Push("origin")
132	require.NoError(t, err)
133	err = cacheB.Pull("origin")
134	require.NoError(t, err)
135
136	// Create a bug in A
137	_, _, err = cacheA.NewBug("bug1", "message")
138	require.NoError(t, err)
139
140	// A --> remote --> B
141	_, err = cacheA.Push("origin")
142	require.NoError(t, err)
143
144	err = cacheB.Pull("origin")
145	require.NoError(t, err)
146
147	require.Len(t, cacheB.AllBugsIds(), 1)
148
149	// retrieve and set identity
150	reneB, err := cacheB.ResolveIdentity(reneA.Id())
151	require.NoError(t, err)
152
153	err = cacheB.SetUserIdentity(reneB)
154	require.NoError(t, err)
155
156	// B --> remote --> A
157	_, _, err = cacheB.NewBug("bug2", "message")
158	require.NoError(t, err)
159
160	_, err = cacheB.Push("origin")
161	require.NoError(t, err)
162
163	err = cacheA.Pull("origin")
164	require.NoError(t, err)
165
166	require.Len(t, cacheA.AllBugsIds(), 2)
167
168	require.Empty(t, stderrA.String())
169	require.Empty(t, stderrB.String())
170}
171
172func TestRemove(t *testing.T) {
173	repo := repository.CreateGoGitTestRepo(t, false)
174	remoteA := repository.CreateGoGitTestRepo(t, true)
175	remoteB := repository.CreateGoGitTestRepo(t, true)
176
177	err := repo.AddRemote("remoteA", remoteA.GetLocalRemote())
178	require.NoError(t, err)
179
180	err = repo.AddRemote("remoteB", remoteB.GetLocalRemote())
181	require.NoError(t, err)
182
183	repoCache, stderr := NewTestRepoCache(t, repo)
184
185	rene, err := repoCache.NewIdentity("René Descartes", "rene@descartes.fr")
186	require.NoError(t, err)
187
188	err = repoCache.SetUserIdentity(rene)
189	require.NoError(t, err)
190
191	_, _, err = repoCache.NewBug("title", "message")
192	require.NoError(t, err)
193
194	// and one more for testing
195	b1, _, err := repoCache.NewBug("title", "message")
196	require.NoError(t, err)
197
198	_, err = repoCache.Push("remoteA")
199	require.NoError(t, err)
200
201	_, err = repoCache.Push("remoteB")
202	require.NoError(t, err)
203
204	_, err = repoCache.Fetch("remoteA")
205	require.NoError(t, err)
206
207	_, err = repoCache.Fetch("remoteB")
208	require.NoError(t, err)
209
210	err = repoCache.RemoveBug(b1.Id().String())
211	require.NoError(t, err)
212	assert.Equal(t, 1, len(repoCache.bugs))
213	assert.Equal(t, 1, len(repoCache.bugExcerpts))
214
215	_, err = repoCache.ResolveBug(b1.Id())
216	assert.Error(t, bug.ErrBugNotExist, err)
217
218	require.Empty(t, stderr.String())
219}
220
221func TestCacheEviction(t *testing.T) {
222	repo := repository.CreateGoGitTestRepo(t, false)
223	repoCache, stderr := NewTestRepoCache(t, repo)
224	repoCache.setCacheSize(2)
225
226	require.Equal(t, 2, repoCache.maxLoadedBugs)
227	require.Equal(t, 0, repoCache.loadedBugs.Len())
228	require.Equal(t, 0, len(repoCache.bugs))
229
230	// Generating some bugs
231	rene, err := repoCache.NewIdentity("René Descartes", "rene@descartes.fr")
232	require.NoError(t, err)
233	err = repoCache.SetUserIdentity(rene)
234	require.NoError(t, err)
235
236	bug1, _, err := repoCache.NewBug("title", "message")
237	require.NoError(t, err)
238
239	checkBugPresence(t, repoCache, bug1, true)
240	require.Equal(t, 1, repoCache.loadedBugs.Len())
241	require.Equal(t, 1, len(repoCache.bugs))
242
243	bug2, _, err := repoCache.NewBug("title", "message")
244	require.NoError(t, err)
245
246	checkBugPresence(t, repoCache, bug1, true)
247	checkBugPresence(t, repoCache, bug2, true)
248	require.Equal(t, 2, repoCache.loadedBugs.Len())
249	require.Equal(t, 2, len(repoCache.bugs))
250
251	// Number of bugs should not exceed max size of lruCache, oldest one should be evicted
252	bug3, _, err := repoCache.NewBug("title", "message")
253	require.NoError(t, err)
254
255	require.Equal(t, 2, repoCache.loadedBugs.Len())
256	require.Equal(t, 2, len(repoCache.bugs))
257	checkBugPresence(t, repoCache, bug1, false)
258	checkBugPresence(t, repoCache, bug2, true)
259	checkBugPresence(t, repoCache, bug3, true)
260
261	// Accessing bug should update position in lruCache and therefore it should not be evicted
262	repoCache.loadedBugs.Get(bug2.Id())
263	oldestId, _ := repoCache.loadedBugs.GetOldest()
264	require.Equal(t, bug3.Id(), oldestId)
265
266	checkBugPresence(t, repoCache, bug1, false)
267	checkBugPresence(t, repoCache, bug2, true)
268	checkBugPresence(t, repoCache, bug3, true)
269	require.Equal(t, 2, repoCache.loadedBugs.Len())
270	require.Equal(t, 2, len(repoCache.bugs))
271
272	require.Empty(t, stderr.String())
273}
274
275func checkBugPresence(t *testing.T, cache *RepoCache, bug *BugCache, presence bool) {
276	id := bug.Id()
277	require.Equal(t, presence, cache.loadedBugs.Contains(id))
278	b, ok := cache.bugs[id]
279	require.Equal(t, presence, ok)
280	if ok {
281		require.Equal(t, bug, b)
282	}
283}
284
285func TestLongDescription(t *testing.T) {
286	// See https://github.com/MichaelMure/git-bug/issues/606
287
288	text := strings.Repeat("x", 65536)
289
290	repo := repository.CreateGoGitTestRepo(t, false)
291
292	backend, stderr := NewTestRepoCache(t, repo)
293
294	i, err := backend.NewIdentity("René Descartes", "rene@descartes.fr")
295	require.NoError(t, err)
296
297	_, _, err = backend.NewBugRaw(i, time.Now().Unix(), text, text, nil, nil)
298	require.NoError(t, err)
299
300	require.Empty(t, stderr.String())
301}