1package dag
2
3import (
4 "sort"
5 "testing"
6
7 "github.com/stretchr/testify/require"
8
9 "github.com/MichaelMure/git-bug/entity"
10 "github.com/MichaelMure/git-bug/repository"
11)
12
13func allEntities(t testing.TB, bugs <-chan StreamedEntity) []*Entity {
14 t.Helper()
15
16 var result []*Entity
17 for streamed := range bugs {
18 require.NoError(t, streamed.Err)
19
20 result = append(result, streamed.Entity)
21 }
22 return result
23}
24
25func TestPushPull(t *testing.T) {
26 repoA, repoB, remote, id1, id2, def := makeTestContextRemote(t)
27 defer repository.CleanupTestRepos(repoA, repoB, remote)
28
29 // A --> remote --> B
30 e := New(def)
31 e.Append(newOp1(id1, "foo"))
32
33 err := e.Commit(repoA)
34 require.NoError(t, err)
35
36 _, err = Push(def, repoA, "remote")
37 require.NoError(t, err)
38
39 err = Pull(def, repoB, "remote")
40 require.NoError(t, err)
41
42 entities := allEntities(t, ReadAll(def, repoB))
43 require.Len(t, entities, 1)
44
45 // B --> remote --> A
46 e = New(def)
47 e.Append(newOp2(id2, "bar"))
48
49 err = e.Commit(repoB)
50 require.NoError(t, err)
51
52 _, err = Push(def, repoB, "remote")
53 require.NoError(t, err)
54
55 err = Pull(def, repoA, "remote")
56 require.NoError(t, err)
57
58 entities = allEntities(t, ReadAll(def, repoB))
59 require.Len(t, entities, 2)
60}
61
62func TestListLocalIds(t *testing.T) {
63 repoA, repoB, remote, id1, id2, def := makeTestContextRemote(t)
64 defer repository.CleanupTestRepos(repoA, repoB, remote)
65
66 // A --> remote --> B
67 e := New(def)
68 e.Append(newOp1(id1, "foo"))
69 err := e.Commit(repoA)
70 require.NoError(t, err)
71
72 e = New(def)
73 e.Append(newOp2(id2, "bar"))
74 err = e.Commit(repoA)
75 require.NoError(t, err)
76
77 listLocalIds(t, def, repoA, 2)
78 listLocalIds(t, def, repoB, 0)
79
80 _, err = Push(def, repoA, "remote")
81 require.NoError(t, err)
82
83 _, err = Fetch(def, repoB, "remote")
84 require.NoError(t, err)
85
86 listLocalIds(t, def, repoA, 2)
87 listLocalIds(t, def, repoB, 0)
88
89 err = Pull(def, repoB, "remote")
90 require.NoError(t, err)
91
92 listLocalIds(t, def, repoA, 2)
93 listLocalIds(t, def, repoB, 2)
94}
95
96func listLocalIds(t *testing.T, def Definition, repo repository.RepoData, expectedCount int) {
97 ids, err := ListLocalIds(def, repo)
98 require.NoError(t, err)
99 require.Len(t, ids, expectedCount)
100}
101
102func assertMergeResults(t *testing.T, expected []entity.MergeResult, results <-chan entity.MergeResult) {
103 t.Helper()
104
105 var allResults []entity.MergeResult
106 for result := range results {
107 allResults = append(allResults, result)
108 }
109
110 require.Equal(t, len(expected), len(allResults))
111
112 sort.Slice(allResults, func(i, j int) bool {
113 return allResults[i].Id < allResults[j].Id
114 })
115 sort.Slice(expected, func(i, j int) bool {
116 return expected[i].Id < expected[j].Id
117 })
118
119 for i, result := range allResults {
120 require.NoError(t, result.Err)
121
122 require.Equal(t, expected[i].Id, result.Id)
123 require.Equal(t, expected[i].Status, result.Status)
124
125 switch result.Status {
126 case entity.MergeStatusNew, entity.MergeStatusUpdated:
127 require.NotNil(t, result.Entity)
128 require.Equal(t, expected[i].Id, result.Entity.Id())
129 }
130
131 i++
132 }
133}
134
135func TestMerge(t *testing.T) {
136 repoA, repoB, remote, id1, id2, def := makeTestContextRemote(t)
137 defer repository.CleanupTestRepos(repoA, repoB, remote)
138
139 // SCENARIO 1
140 // if the remote Entity doesn't exist locally, it's created
141
142 // 2 entities in repoA + push to remote
143 e1 := New(def)
144 e1.Append(newOp1(id1, "foo"))
145 err := e1.Commit(repoA)
146 require.NoError(t, err)
147
148 e2 := New(def)
149 e2.Append(newOp2(id2, "bar"))
150 err = e2.Commit(repoA)
151 require.NoError(t, err)
152
153 _, err = Push(def, repoA, "remote")
154 require.NoError(t, err)
155
156 // repoB: fetch + merge from remote
157
158 _, err = Fetch(def, repoB, "remote")
159 require.NoError(t, err)
160
161 results := MergeAll(def, repoB, "remote")
162
163 assertMergeResults(t, []entity.MergeResult{
164 {
165 Id: e1.Id(),
166 Status: entity.MergeStatusNew,
167 },
168 {
169 Id: e2.Id(),
170 Status: entity.MergeStatusNew,
171 },
172 }, results)
173
174 // SCENARIO 2
175 // if the remote and local Entity have the same state, nothing is changed
176
177 results = MergeAll(def, repoB, "remote")
178
179 assertMergeResults(t, []entity.MergeResult{
180 {
181 Id: e1.Id(),
182 Status: entity.MergeStatusNothing,
183 },
184 {
185 Id: e2.Id(),
186 Status: entity.MergeStatusNothing,
187 },
188 }, results)
189
190 // SCENARIO 3
191 // if the local Entity has new commits but the remote don't, nothing is changed
192
193 e1.Append(newOp1(id1, "barbar"))
194 err = e1.Commit(repoA)
195 require.NoError(t, err)
196
197 e2.Append(newOp2(id2, "barbarbar"))
198 err = e2.Commit(repoA)
199 require.NoError(t, err)
200
201 results = MergeAll(def, repoA, "remote")
202
203 assertMergeResults(t, []entity.MergeResult{
204 {
205 Id: e1.Id(),
206 Status: entity.MergeStatusNothing,
207 },
208 {
209 Id: e2.Id(),
210 Status: entity.MergeStatusNothing,
211 },
212 }, results)
213
214 // SCENARIO 4
215 // if the remote has new commit, the local bug is updated to match the same history
216 // (fast-forward update)
217}