github.com/argoproj/argo-cd/v3@v3.2.1/applicationset/services/pull_request/azure_devops_test.go (about) 1 package pull_request 2 3 import ( 4 "context" 5 "errors" 6 "testing" 7 8 "github.com/microsoft/azure-devops-go-api/azuredevops/v7/core" 9 "github.com/microsoft/azure-devops-go-api/azuredevops/v7/git" 10 "github.com/microsoft/azure-devops-go-api/azuredevops/v7/webapi" 11 "github.com/stretchr/testify/assert" 12 "github.com/stretchr/testify/mock" 13 "github.com/stretchr/testify/require" 14 15 azureMock "github.com/argoproj/argo-cd/v3/applicationset/services/scm_provider/azure_devops/git/mocks" 16 ) 17 18 func createBoolPtr(x bool) *bool { 19 return &x 20 } 21 22 func createStringPtr(x string) *string { 23 return &x 24 } 25 26 func createIntPtr(x int) *int { 27 return &x 28 } 29 30 func createLabelsPtr(x []core.WebApiTagDefinition) *[]core.WebApiTagDefinition { 31 return &x 32 } 33 34 func createUniqueNamePtr(x string) *string { 35 return &x 36 } 37 38 type AzureClientFactoryMock struct { 39 mock *mock.Mock 40 } 41 42 func (m *AzureClientFactoryMock) GetClient(ctx context.Context) (git.Client, error) { 43 args := m.mock.Called(ctx) 44 45 var client git.Client 46 c := args.Get(0) 47 if c != nil { 48 client = c.(git.Client) 49 } 50 51 var err error 52 if len(args) > 1 { 53 if e, ok := args.Get(1).(error); ok { 54 err = e 55 } 56 } 57 58 return client, err 59 } 60 61 func TestListPullRequest(t *testing.T) { 62 teamProject := "myorg_project" 63 repoName := "myorg_project_repo" 64 prID := 123 65 prTitle := "feat(123)" 66 prHeadSha := "cd4973d9d14a08ffe6b641a89a68891d6aac8056" 67 ctx := t.Context() 68 uniqueName := "testName" 69 70 pullRequestMock := []git.GitPullRequest{ 71 { 72 PullRequestId: createIntPtr(prID), 73 Title: createStringPtr(prTitle), 74 SourceRefName: createStringPtr("refs/heads/feature-branch"), 75 TargetRefName: createStringPtr("refs/heads/main"), 76 LastMergeSourceCommit: &git.GitCommitRef{ 77 CommitId: createStringPtr(prHeadSha), 78 }, 79 Labels: &[]core.WebApiTagDefinition{}, 80 Repository: &git.GitRepository{ 81 Name: createStringPtr(repoName), 82 }, 83 CreatedBy: &webapi.IdentityRef{ 84 UniqueName: createUniqueNamePtr(uniqueName + "@example.com"), 85 }, 86 }, 87 } 88 89 args := git.GetPullRequestsByProjectArgs{ 90 Project: &teamProject, 91 SearchCriteria: &git.GitPullRequestSearchCriteria{}, 92 } 93 94 gitClientMock := azureMock.Client{} 95 clientFactoryMock := &AzureClientFactoryMock{mock: &mock.Mock{}} 96 clientFactoryMock.mock.On("GetClient", mock.Anything).Return(&gitClientMock, nil) 97 gitClientMock.On("GetPullRequestsByProject", ctx, args).Return(&pullRequestMock, nil) 98 99 provider := AzureDevOpsService{ 100 clientFactory: clientFactoryMock, 101 project: teamProject, 102 repo: repoName, 103 labels: nil, 104 } 105 106 list, err := provider.List(ctx) 107 require.NoError(t, err) 108 assert.Len(t, list, 1) 109 assert.Equal(t, "feature-branch", list[0].Branch) 110 assert.Equal(t, "main", list[0].TargetBranch) 111 assert.Equal(t, prHeadSha, list[0].HeadSHA) 112 assert.Equal(t, "feat(123)", list[0].Title) 113 assert.Equal(t, prID, list[0].Number) 114 assert.Equal(t, uniqueName, list[0].Author) 115 } 116 117 func TestConvertLabes(t *testing.T) { 118 testCases := []struct { 119 name string 120 gotLabels *[]core.WebApiTagDefinition 121 expectedLabels []string 122 }{ 123 { 124 name: "empty labels", 125 gotLabels: createLabelsPtr([]core.WebApiTagDefinition{}), 126 expectedLabels: []string{}, 127 }, 128 { 129 name: "nil labels", 130 gotLabels: createLabelsPtr(nil), 131 expectedLabels: []string{}, 132 }, 133 { 134 name: "one label", 135 gotLabels: createLabelsPtr([]core.WebApiTagDefinition{ 136 {Name: createStringPtr("label1"), Active: createBoolPtr(true)}, 137 }), 138 expectedLabels: []string{"label1"}, 139 }, 140 { 141 name: "two label", 142 gotLabels: createLabelsPtr([]core.WebApiTagDefinition{ 143 {Name: createStringPtr("label1"), Active: createBoolPtr(true)}, 144 {Name: createStringPtr("label2"), Active: createBoolPtr(true)}, 145 }), 146 expectedLabels: []string{"label1", "label2"}, 147 }, 148 } 149 150 for _, tc := range testCases { 151 t.Run(tc.name, func(t *testing.T) { 152 got := convertLabels(tc.gotLabels) 153 assert.Equal(t, tc.expectedLabels, got) 154 }) 155 } 156 } 157 158 func TestContainAzureDevOpsLabels(t *testing.T) { 159 testCases := []struct { 160 name string 161 expectedLabels []string 162 gotLabels []string 163 expectedResult bool 164 }{ 165 { 166 name: "empty labels", 167 expectedLabels: []string{}, 168 gotLabels: []string{}, 169 expectedResult: true, 170 }, 171 { 172 name: "no matching labels", 173 expectedLabels: []string{"label1", "label2"}, 174 gotLabels: []string{"label3", "label4"}, 175 expectedResult: false, 176 }, 177 { 178 name: "some matching labels", 179 expectedLabels: []string{"label1", "label2"}, 180 gotLabels: []string{"label1", "label3"}, 181 expectedResult: false, 182 }, 183 { 184 name: "all matching labels", 185 expectedLabels: []string{"label1", "label2"}, 186 gotLabels: []string{"label1", "label2"}, 187 expectedResult: true, 188 }, 189 } 190 191 for _, tc := range testCases { 192 t.Run(tc.name, func(t *testing.T) { 193 got := containAzureDevOpsLabels(tc.expectedLabels, tc.gotLabels) 194 assert.Equal(t, tc.expectedResult, got) 195 }) 196 } 197 } 198 199 func TestBuildURL(t *testing.T) { 200 testCases := []struct { 201 name string 202 url string 203 organization string 204 expected string 205 }{ 206 { 207 name: "Provided default URL and organization", 208 url: "https://dev.azure.com/", 209 organization: "myorganization", 210 expected: "https://dev.azure.com/myorganization", 211 }, 212 { 213 name: "Provided default URL and organization without trailing slash", 214 url: "https://dev.azure.com", 215 organization: "myorganization", 216 expected: "https://dev.azure.com/myorganization", 217 }, 218 { 219 name: "Provided no URL and organization", 220 url: "", 221 organization: "myorganization", 222 expected: "https://dev.azure.com/myorganization", 223 }, 224 { 225 name: "Provided custom URL and organization", 226 url: "https://azuredevops.example.com/", 227 organization: "myorganization", 228 expected: "https://azuredevops.example.com/myorganization", 229 }, 230 } 231 232 for _, tc := range testCases { 233 t.Run(tc.name, func(t *testing.T) { 234 result := buildURL(tc.url, tc.organization) 235 assert.Equal(t, tc.expected, result) 236 }) 237 } 238 } 239 240 func TestAzureDevOpsListReturnsRepositoryNotFoundError(t *testing.T) { 241 args := git.GetPullRequestsByProjectArgs{ 242 Project: createStringPtr("nonexistent"), 243 SearchCriteria: &git.GitPullRequestSearchCriteria{}, 244 } 245 246 pullRequestMock := []git.GitPullRequest{} 247 248 gitClientMock := azureMock.Client{} 249 clientFactoryMock := &AzureClientFactoryMock{mock: &mock.Mock{}} 250 clientFactoryMock.mock.On("GetClient", mock.Anything).Return(&gitClientMock, nil) 251 252 // Mock the GetPullRequestsByProject to return an error containing "404" 253 gitClientMock.On("GetPullRequestsByProject", t.Context(), args).Return(&pullRequestMock, 254 errors.New("The following project does not exist:")) 255 256 provider := AzureDevOpsService{ 257 clientFactory: clientFactoryMock, 258 project: "nonexistent", 259 repo: "nonexistent", 260 labels: nil, 261 } 262 263 prs, err := provider.List(t.Context()) 264 265 // Should return empty pull requests list 266 assert.Empty(t, prs) 267 268 // Should return RepositoryNotFoundError 269 require.Error(t, err) 270 assert.True(t, IsRepositoryNotFoundError(err), "Expected RepositoryNotFoundError but got: %v", err) 271 }