entity_actions_test.go

  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}