Skip to content

Commit 1cddea6

Browse files
committed
test: add unit tests on post / put methods
Upgrade helper module to support more API response mocks Fix all errors detected by unit tests
1 parent 1b573c7 commit 1cddea6

File tree

12 files changed

+827
-49
lines changed

12 files changed

+827
-49
lines changed

internal/mirroring/get_group.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ func (g *GitlabInstance) fetchAndProcessGroupsLargeInstance(groupFilters *map[st
169169
}
170170

171171
// fetchAndProcessGroupRecursive fetches a group and its projects recursively
172-
// It uses a wait group to ensure that all goroutines finish before returning
172+
// It uses a wait group to ensure that all goroutines finish befopidpre returning
173173
// It sends the fetched group to the allGroupsChannel and the projects to the allProjectsChanel
174174
//
175175
// gid can be either an int, a string or a *gitlab.Group
@@ -188,7 +188,8 @@ func (g *GitlabInstance) fetchAndProcessGroupRecursive(gid any, fetchOriginPath
188188
case *gitlab.Group:
189189
group = v
190190
default:
191-
errChan <- fmt.Errorf("invalid group ID type %T (%s)", gid, gid)
191+
errChan <- fmt.Errorf("invalid group ID type %T (%v)", gid, gid)
192+
return
192193
}
193194
if group != nil {
194195
g.storeGroup(group, fetchOriginPath, mirrorMapping)

internal/mirroring/get_project.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,14 +149,14 @@ func (g *GitlabInstance) fetchAndProcessProjectsBigInstance(projectFilters *map[
149149
// Fetch each project in parallel
150150
var wg sync.WaitGroup
151151
projectsChan := make(chan *gitlab.Project, len(*projectFilters))
152-
errCh := make(chan error)
152+
errCh := make(chan error, len(*projectFilters))
153153
wg.Add(len(*projectFilters))
154154
for project := range *projectFilters {
155155
go func(projectPath string) {
156156
defer wg.Done()
157157
p, _, err := g.Gitlab.Projects.GetProject(projectPath, &gitlab.GetProjectOptions{})
158158
if err != nil {
159-
errCh <- err
159+
errCh <- fmt.Errorf("failed to retrieve project %s: %v", projectPath, err)
160160
return
161161
}
162162
projectsChan <- p
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package mirroring
2+
3+
import (
4+
"gitlab-sync/internal/utils"
5+
"testing"
6+
)
7+
8+
func TestFetchAndProcessProjectsBigInstance(t *testing.T) {
9+
tests := []struct {
10+
name string
11+
role string
12+
projectFilters map[string]struct{}
13+
expectedProjects map[string]struct{}
14+
expectError bool
15+
}{
16+
{
17+
name: "Test with source role, 1 project only, no error",
18+
role: ROLE_SOURCE,
19+
projectFilters: map[string]struct{}{
20+
TEST_PROJECT.PathWithNamespace: {},
21+
},
22+
expectedProjects: map[string]struct{}{
23+
TEST_PROJECT.PathWithNamespace: {},
24+
},
25+
},
26+
{
27+
name: "Test with destination role, 1 project only, no error",
28+
role: ROLE_DESTINATION,
29+
projectFilters: map[string]struct{}{
30+
TEST_PROJECT.PathWithNamespace: {},
31+
},
32+
expectedProjects: map[string]struct{}{
33+
TEST_PROJECT.PathWithNamespace: {},
34+
},
35+
},
36+
{
37+
name: "Test with source role, 2 projects, no error",
38+
role: ROLE_SOURCE,
39+
projectFilters: map[string]struct{}{
40+
TEST_PROJECT.PathWithNamespace: {},
41+
TEST_PROJECT_2.PathWithNamespace: {},
42+
},
43+
expectedProjects: map[string]struct{}{
44+
TEST_PROJECT.PathWithNamespace: {},
45+
TEST_PROJECT_2.PathWithNamespace: {},
46+
},
47+
},
48+
{
49+
name: "Test with destination role, 2 projects, no error",
50+
role: ROLE_DESTINATION,
51+
projectFilters: map[string]struct{}{
52+
TEST_PROJECT.PathWithNamespace: {},
53+
TEST_PROJECT_2.PathWithNamespace: {},
54+
},
55+
expectedProjects: map[string]struct{}{
56+
TEST_PROJECT.PathWithNamespace: {},
57+
TEST_PROJECT_2.PathWithNamespace: {},
58+
},
59+
},
60+
{
61+
name: "Test with source role, 1 project, 1 error",
62+
role: ROLE_SOURCE,
63+
projectFilters: map[string]struct{}{
64+
TEST_PROJECT.PathWithNamespace: {},
65+
INVALID_PROJECT.PathWithNamespace: {},
66+
},
67+
expectedProjects: map[string]struct{}{
68+
TEST_PROJECT.PathWithNamespace: {},
69+
},
70+
expectError: true,
71+
},
72+
}
73+
74+
for _, test := range tests {
75+
t.Run(test.name, func(t *testing.T) {
76+
t.Parallel()
77+
78+
gitlabMirrorArgs := &utils.MirrorMapping{
79+
Projects: map[string]*utils.MirroringOptions{
80+
TEST_PROJECT.PathWithNamespace: {
81+
DestinationPath: TEST_PROJECT.PathWithNamespace,
82+
},
83+
},
84+
}
85+
86+
_, gitlabInstance := setupTestServer(t, test.role, INSTANCE_SIZE_BIG)
87+
88+
err := gitlabInstance.fetchAndProcessProjectsBigInstance(&test.projectFilters, gitlabMirrorArgs)
89+
if (err != nil) != test.expectError {
90+
t.Fatalf("Expected error: %v, got: %v", test.expectError, err)
91+
}
92+
if len(gitlabInstance.Projects) != len(test.expectedProjects) {
93+
t.Fatalf("Expected %d projects, got %d", len(test.expectedProjects), len(gitlabInstance.Projects))
94+
}
95+
for project := range test.expectedProjects {
96+
if _, ok := gitlabInstance.Projects[project]; !ok {
97+
t.Errorf("Expected project %s to be in the cache", project)
98+
}
99+
}
100+
})
101+
}
102+
103+
}

internal/mirroring/get_test.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,6 @@ func TestFetchAll(t *testing.T) {
190190
if _, ok := gitlabInstance.Groups[TEST_GROUP_2.FullPath]; !ok {
191191
t.Errorf("expected group %s not found in %s %s instance cache", TEST_GROUP_2.FullPath, gitlabInstance.Role, gitlabInstance.InstanceSize)
192192
}
193-
194193
})
195194
}
196195

internal/mirroring/helper.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package mirroring
2+
3+
import (
4+
"gitlab-sync/internal/utils"
5+
"sort"
6+
7+
"go.uber.org/zap"
8+
)
9+
10+
// reverseGroupMirrorMap reverses the mirror mapping to get the source group path for each destination group.
11+
// It creates a map where the keys are the destination group paths and the values are the source group paths.
12+
// The function also returns a sorted list of destination group paths.
13+
func (g *GitlabInstance) reverseGroupMirrorMap(mirrorMapping *utils.MirrorMapping) (map[string]string, []string) {
14+
var reversedMirrorMap map[string]string
15+
destinationGroupPaths := make([]string, 0, len(g.Groups))
16+
if mirrorMapping != nil {
17+
// Reverse the mirror mapping to get the source group path for each destination group
18+
reversedMirrorMap = make(map[string]string, len(mirrorMapping.Groups))
19+
// Extract the keys (group paths) and sort them
20+
// This ensures that the parent groups are created before their children
21+
for sourceGroupPath, createOptions := range mirrorMapping.Groups {
22+
if _, ok := reversedMirrorMap[createOptions.DestinationPath]; ok {
23+
zap.L().Error("duplicate destination path found in mirror mapping", zap.String("destinationPath", createOptions.DestinationPath))
24+
continue
25+
}
26+
reversedMirrorMap[createOptions.DestinationPath] = sourceGroupPath
27+
destinationGroupPaths = append(destinationGroupPaths, createOptions.DestinationPath)
28+
}
29+
sort.Strings(destinationGroupPaths)
30+
}
31+
return reversedMirrorMap, destinationGroupPaths
32+
}

0 commit comments

Comments
 (0)