Skip to content

Commit 1c4f546

Browse files
authored
Update IGroupsClient to support paging of groups and projects (#642)
* Add Page support to IGroupsClient * Add unit tests for mock GroupClient * Add integration tests * Fix integration test failures * Replace WebHeaderCollection with NameValueCollection Do not use System.Net types in public APIs. * Revert all possible breaking changes * Update docs to use the 3rd person descriptive form * Replace `ToList` with `ToArray` * Keep static fields together * Dispose `StreamReader` * Return early in some cases to reduce indentation * Use `PagedResponse<T>` for all paged responses * Replace NameValueCollection with a IReadOnlyDictionary * Add unit tests for WebHeadersDictionaryAdaptor * Replace the custom IEnumerator impl with the IEnumerable's enumerator * Use custom error message
1 parent 2ae5ce0 commit 1c4f546

19 files changed

+1518
-285
lines changed

NGitLab.Mock.Tests/GroupsMockTests.cs

Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,27 @@ namespace NGitLab.Mock.Tests;
77

88
public class GroupsMockTests
99
{
10+
private static GitLabServer CreateGroupHierarchy() =>
11+
new GitLabConfig()
12+
.WithUser("user1", isDefault: true)
13+
.WithGroup("tlg", 1)
14+
.WithGroup("sg1", 2, @namespace: "tlg")
15+
.WithGroup("sg1_1", 3, @namespace: "tlg/sg1")
16+
.WithGroup("sg2", 4, @namespace: "tlg")
17+
.WithGroup("sg2_1", 5, @namespace: "tlg/sg2")
18+
.BuildServer();
19+
20+
private static GitLabServer CreateProjectHierarchy() =>
21+
new GitLabConfig()
22+
.WithUser("user1", isDefault: true)
23+
.WithGroup("tlg", 1)
24+
.WithProject("p1", 2, @namespace: "tlg")
25+
.WithGroup("sg1", 3, @namespace: "tlg")
26+
.WithProject("p2", 4, @namespace: "tlg/sg1")
27+
.WithProject("p3", 5, @namespace: "tlg/sg1")
28+
.WithGroup("sg2", 6, @namespace: "tlg")
29+
.BuildServer();
30+
1031
[Test]
1132
public async Task Test_group_get_by_id()
1233
{
@@ -41,6 +62,69 @@ public async Task Test_group_get_by_fullpath()
4162
Assert.That(group.FullPath, Is.EqualTo("name3"), "Subgroups found are invalid");
4263
}
4364

65+
[Test]
66+
public void Test_get_groups_with_top_level_only_ignores_subgroups()
67+
{
68+
using var server = CreateGroupHierarchy();
69+
70+
var client = server.CreateClient("user1");
71+
var groups = client.Groups.GetAsync(new Models.GroupQuery { TopLevelOnly = true });
72+
73+
var expected = new string[] { "user1", "tlg" };
74+
Assert.That(groups.Select(g => g.FullPath), Is.EquivalentTo(expected));
75+
}
76+
77+
[Test]
78+
public async Task Test_page_groups_first_page()
79+
{
80+
using var server = CreateGroupHierarchy();
81+
82+
var client = server.CreateClient("user1");
83+
(var page, var total) = await client.Groups.PageAsync(new(page: 1, perPage: 3));
84+
85+
var expected = new string[] { "user1", "tlg", "tlg/sg1" };
86+
Assert.Multiple(() =>
87+
{
88+
Assert.That(page.Select(g => g.FullPath), Is.EquivalentTo(expected));
89+
Assert.That(total, Is.EqualTo(6));
90+
});
91+
}
92+
93+
[Test]
94+
public async Task Test_page_groups_last_page()
95+
{
96+
using var server = CreateGroupHierarchy();
97+
98+
var client = server.CreateClient("user1");
99+
(var page, var total) = await client.Groups.PageAsync(new(page: 2, perPage: 4));
100+
101+
var expected = new string[] { "tlg/sg2", "tlg/sg2/sg2_1" };
102+
Assert.Multiple(() =>
103+
{
104+
Assert.That(page.Select(g => g.FullPath), Is.EquivalentTo(expected));
105+
Assert.That(total, Is.EqualTo(6));
106+
});
107+
}
108+
109+
[Test]
110+
public async Task Test_page_groups_with_page_0_returns_page_1()
111+
{
112+
using var server = CreateGroupHierarchy();
113+
114+
var client = server.CreateClient("user1");
115+
(var page, var total) = await client.Groups.PageAsync(new(page: 0));
116+
117+
Assert.That(total, Is.EqualTo(6));
118+
}
119+
120+
[Test]
121+
public void Test_page_groups_with_invalid_perpage_throws()
122+
{
123+
using var server = CreateGroupHierarchy();
124+
var client = server.CreateClient("user1");
125+
Assert.ThrowsAsync<Clients.GitLabBadRequestException>(() => client.Groups.PageAsync(new(perPage: 0)));
126+
}
127+
44128
[Test]
45129
public void Test_get_subgroups_by_id()
46130
{
@@ -78,4 +162,181 @@ public void Test_get_subgroups_by_fullpath()
78162

79163
Assert.That(group.Count(), Is.EqualTo(2), "Subgroups found are invalid");
80164
}
165+
166+
[Test]
167+
public void Test_get_subgroups_descendants_by_fullpath()
168+
{
169+
using var server = CreateGroupHierarchy();
170+
171+
var client = server.CreateClient("user1");
172+
var group = client.Groups.GetSubgroupsByFullPathAsync("tlg", new Models.SubgroupQuery { IncludeDescendants = true });
173+
174+
var expected = new string[] { "tlg/sg1", "tlg/sg1/sg1_1", "tlg/sg2", "tlg/sg2/sg2_1" };
175+
Assert.That(group.Select(g => g.FullPath), Is.EquivalentTo(expected));
176+
}
177+
178+
[Test]
179+
public void Test_get_subgroups_descendants_by_id()
180+
{
181+
using var server = CreateGroupHierarchy();
182+
183+
var client = server.CreateClient("user1");
184+
var group = client.Groups.GetSubgroupsByIdAsync(1, new Models.SubgroupQuery { IncludeDescendants = true });
185+
186+
var expected = new string[] { "tlg/sg1", "tlg/sg1/sg1_1", "tlg/sg2", "tlg/sg2/sg2_1" };
187+
Assert.That(group.Select(g => g.FullPath), Is.EquivalentTo(expected));
188+
}
189+
190+
[Test]
191+
public void Test_get_subgroups_descendants_of_subgroup_by_fullpath()
192+
{
193+
using var server = CreateGroupHierarchy();
194+
195+
var client = server.CreateClient("user1");
196+
var group = client.Groups.GetSubgroupsAsync("tlg/sg2", new Models.SubgroupQuery { IncludeDescendants = true });
197+
198+
var expected = new string[] { "tlg/sg2/sg2_1" };
199+
Assert.That(group.Select(g => g.FullPath), Is.EquivalentTo(expected));
200+
}
201+
202+
[Test]
203+
public void Test_get_subgroups_descendants_of_subgroup_by_id()
204+
{
205+
using var server = CreateGroupHierarchy();
206+
207+
var client = server.CreateClient("user1");
208+
var group = client.Groups.GetSubgroupsAsync(2, new Models.SubgroupQuery { IncludeDescendants = true });
209+
210+
var expected = new string[] { "tlg/sg1/sg1_1" };
211+
Assert.That(group.Select(g => g.FullPath), Is.EquivalentTo(expected));
212+
}
213+
214+
[Test]
215+
public async Task Test_page_subgroups_with_descendants_first_page()
216+
{
217+
using var server = CreateGroupHierarchy();
218+
219+
var client = server.CreateClient("user1");
220+
(var page, var total) = await client.Groups.PageSubgroupsAsync("tlg", new(page: 1, perPage: 3, new Models.SubgroupQuery { IncludeDescendants = true }));
221+
222+
var expected = new string[] { "tlg/sg1", "tlg/sg1/sg1_1", "tlg/sg2" };
223+
Assert.Multiple(() =>
224+
{
225+
Assert.That(page.Select(g => g.FullPath), Is.EquivalentTo(expected));
226+
Assert.That(total, Is.EqualTo(4));
227+
});
228+
}
229+
230+
[Test]
231+
public async Task Test_page_subgroups_with_descendants_last_page()
232+
{
233+
using var server = CreateGroupHierarchy();
234+
235+
var client = server.CreateClient("user1");
236+
(var page, var total) = await client.Groups.PageSubgroupsAsync(1, new(page: 2, perPage: 3, new Models.SubgroupQuery { IncludeDescendants = true }));
237+
238+
var expected = new string[] { "tlg/sg2/sg2_1" };
239+
Assert.Multiple(() =>
240+
{
241+
Assert.That(page.Select(g => g.FullPath), Is.EquivalentTo(expected));
242+
Assert.That(total, Is.EqualTo(4));
243+
});
244+
}
245+
246+
[Test]
247+
public async Task Test_page_subgroups_with_descendants_after_last_page()
248+
{
249+
using var server = CreateGroupHierarchy();
250+
251+
var client = server.CreateClient("user1");
252+
(var page, var total) = await client.Groups.PageSubgroupsAsync(1, new(page: 100, perPage: 3, new Models.SubgroupQuery { IncludeDescendants = true }));
253+
254+
Assert.Multiple(() =>
255+
{
256+
Assert.That(page.Select(g => g.FullPath), Is.Empty);
257+
Assert.That(total, Is.EqualTo(4));
258+
});
259+
}
260+
261+
[Test]
262+
public async Task Test_page_subgroups_with_page_0_returns_page_1()
263+
{
264+
using var server = CreateGroupHierarchy();
265+
266+
var client = server.CreateClient("user1");
267+
(var page, var total) = await client.Groups.PageSubgroupsAsync("tlg", new(page: 0));
268+
269+
Assert.That(total, Is.EqualTo(2));
270+
}
271+
272+
[Test]
273+
public void Test_page_subgroups_with_invalid_perpage_throws()
274+
{
275+
using var server = CreateGroupHierarchy();
276+
var client = server.CreateClient("user1");
277+
Assert.ThrowsAsync<Clients.GitLabBadRequestException>(() => client.Groups.PageSubgroupsAsync(1, new(page: 1, perPage: 0)));
278+
}
279+
280+
[Test]
281+
public async Task Test_page_projects_first_page()
282+
{
283+
using var server = CreateProjectHierarchy();
284+
285+
var client = server.CreateClient("user1");
286+
(var page, var total) = await client.Groups.PageProjectsAsync("tlg", new(page: 1, perPage: 1000));
287+
288+
var expected = new string[] { "tlg/p1" };
289+
Assert.Multiple(() =>
290+
{
291+
Assert.That(page.Select(p => p.PathWithNamespace), Is.EquivalentTo(expected));
292+
Assert.That(total, Is.EqualTo(1));
293+
});
294+
}
295+
296+
[Test]
297+
public async Task Test_page_projects_in_subgroup()
298+
{
299+
using var server = CreateProjectHierarchy();
300+
301+
var client = server.CreateClient("user1");
302+
(var page, var total) = await client.Groups.PageProjectsAsync("tlg/sg1", new(page: 2, perPage: 1));
303+
304+
var expected = new string[] { "tlg/sg1/p3" };
305+
Assert.Multiple(() =>
306+
{
307+
Assert.That(page.Select(p => p.PathWithNamespace), Is.EquivalentTo(expected));
308+
Assert.That(total, Is.EqualTo(2));
309+
});
310+
}
311+
312+
[Test]
313+
public async Task Test_page_projects_in_subgroup_with_no_projects()
314+
{
315+
using var server = CreateProjectHierarchy();
316+
317+
var client = server.CreateClient("user1");
318+
(var page, var total) = await client.Groups.PageProjectsAsync("tlg/sg2", new());
319+
320+
Assert.Multiple(() =>
321+
{
322+
Assert.That(page.Select(p => p.PathWithNamespace), Is.Empty);
323+
Assert.That(total, Is.EqualTo(0));
324+
});
325+
}
326+
327+
[Test]
328+
public async Task Test_page_projects_in_subgroup_with_descendants()
329+
{
330+
using var server = CreateProjectHierarchy();
331+
332+
var client = server.CreateClient("user1");
333+
(var page, var total) = await client.Groups.PageProjectsAsync("tlg", new(query: new() { IncludeSubGroups = true }));
334+
335+
var expected = new string[] { "p1", "p2", "p3" };
336+
Assert.Multiple(() =>
337+
{
338+
Assert.That(page.Select(p => p.Name), Is.EquivalentTo(expected));
339+
Assert.That(total, Is.EqualTo(3));
340+
});
341+
}
81342
}

0 commit comments

Comments
 (0)