github.com/ouraigua/jenkins-library@v0.0.0-20231028010029-fbeaf2f3aa9b/pkg/orchestrator/azureDevOps_test.go (about) 1 //go:build unit 2 // +build unit 3 4 package orchestrator 5 6 import ( 7 "fmt" 8 "net/http" 9 "os" 10 "testing" 11 "time" 12 13 piperhttp "github.com/SAP/jenkins-library/pkg/http" 14 "github.com/jarcoal/httpmock" 15 "github.com/pkg/errors" 16 17 "github.com/stretchr/testify/assert" 18 ) 19 20 func TestAzure(t *testing.T) { 21 t.Run("Azure - BranchBuild", func(t *testing.T) { 22 defer resetEnv(os.Environ()) 23 os.Clearenv() 24 os.Setenv("AZURE_HTTP_USER_AGENT", "FOO BAR BAZ") 25 os.Setenv("BUILD_SOURCEBRANCH", "refs/heads/feat/test-azure") 26 os.Setenv("SYSTEM_TEAMFOUNDATIONCOLLECTIONURI", "https://pogo.sap/") 27 os.Setenv("SYSTEM_TEAMPROJECT", "foo") 28 os.Setenv("BUILD_BUILDID", "42") 29 os.Setenv("BUILD_SOURCEVERSION", "abcdef42713") 30 os.Setenv("BUILD_REPOSITORY_URI", "github.com/foo/bar") 31 os.Setenv("SYSTEM_DEFINITIONNAME", "bar") 32 os.Setenv("SYSTEM_DEFINITIONID", "1234") 33 p, _ := NewOrchestratorSpecificConfigProvider() 34 35 assert.False(t, p.IsPullRequest()) 36 assert.Equal(t, "feat/test-azure", p.GetBranch()) 37 assert.Equal(t, "refs/heads/feat/test-azure", p.GetReference()) 38 assert.Equal(t, "https://pogo.sap/foo/bar/_build/results?buildId=42", p.GetBuildURL()) 39 assert.Equal(t, "abcdef42713", p.GetCommit()) 40 assert.Equal(t, "github.com/foo/bar", p.GetRepoURL()) 41 assert.Equal(t, "Azure", p.OrchestratorType()) 42 assert.Equal(t, "https://pogo.sap/foo/bar/_build?definitionId=1234", p.GetJobURL()) 43 }) 44 45 t.Run("PR", func(t *testing.T) { 46 defer resetEnv(os.Environ()) 47 os.Clearenv() 48 os.Setenv("SYSTEM_PULLREQUEST_SOURCEBRANCH", "feat/test-azure") 49 os.Setenv("SYSTEM_PULLREQUEST_TARGETBRANCH", "main") 50 os.Setenv("SYSTEM_PULLREQUEST_PULLREQUESTID", "42") 51 os.Setenv("BUILD_REASON", "PullRequest") 52 53 p := AzureDevOpsConfigProvider{} 54 c := p.GetPullRequestConfig() 55 56 assert.True(t, p.IsPullRequest()) 57 assert.Equal(t, "feat/test-azure", c.Branch) 58 assert.Equal(t, "main", c.Base) 59 assert.Equal(t, "42", c.Key) 60 }) 61 62 t.Run("PR - Branch Policy", func(t *testing.T) { 63 defer resetEnv(os.Environ()) 64 os.Clearenv() 65 os.Setenv("SYSTEM_PULLREQUEST_SOURCEBRANCH", "feat/test-azure") 66 os.Setenv("SYSTEM_PULLREQUEST_TARGETBRANCH", "main") 67 os.Setenv("SYSTEM_PULLREQUEST_PULLREQUESTID", "123456789") 68 os.Setenv("SYSTEM_PULLREQUEST_PULLREQUESTNUMBER", "42") 69 os.Setenv("BUILD_REASON", "PullRequest") 70 71 p := AzureDevOpsConfigProvider{} 72 c := p.GetPullRequestConfig() 73 74 assert.True(t, p.IsPullRequest()) 75 assert.Equal(t, "feat/test-azure", c.Branch) 76 assert.Equal(t, "main", c.Base) 77 assert.Equal(t, "42", c.Key) 78 }) 79 80 t.Run("Azure DevOps - false", func(t *testing.T) { 81 defer resetEnv(os.Environ()) 82 os.Clearenv() 83 84 os.Setenv("AZURE_HTTP_USER_AGENT", "false") 85 86 o := DetectOrchestrator() 87 88 assert.Equal(t, Orchestrator(Unknown), o) 89 }) 90 91 t.Run("env variables", func(t *testing.T) { 92 defer resetEnv(os.Environ()) 93 os.Clearenv() 94 os.Setenv("SYSTEM_COLLECTIONURI", "https://dev.azure.com/fabrikamfiber/") 95 os.Setenv("SYSTEM_TEAMPROJECTID", "123a4567-ab1c-12a1-1234-123456ab7890") 96 os.Setenv("BUILD_BUILDID", "42") 97 os.Setenv("AGENT_VERSION", "2.193.0") 98 os.Setenv("BUILD_BUILDNUMBER", "20220318.16") 99 os.Setenv("BUILD_REPOSITORY_NAME", "repo-org/repo-name") 100 101 p := AzureDevOpsConfigProvider{} 102 103 assert.Equal(t, "https://dev.azure.com/fabrikamfiber/", p.getSystemCollectionURI()) 104 assert.Equal(t, "123a4567-ab1c-12a1-1234-123456ab7890", p.getTeamProjectID()) 105 assert.Equal(t, "42", p.getAzureBuildID()) // Don't confuse getAzureBuildID and GetBuildID! 106 assert.Equal(t, "20220318.16", p.GetBuildID()) // buildNumber is used in the UI 107 assert.Equal(t, "2.193.0", p.OrchestratorVersion()) 108 assert.Equal(t, "repo-org/repo-name", p.GetJobName()) 109 110 }) 111 } 112 113 func TestAzureDevOpsConfigProvider_GetPipelineStartTime(t *testing.T) { 114 115 tests := []struct { 116 name string 117 apiInformation map[string]interface{} 118 want time.Time 119 }{ 120 { 121 name: "Retrieve correct time", 122 apiInformation: map[string]interface{}{"startTime": "2022-03-18T12:30:42.0Z"}, 123 want: time.Date(2022, time.March, 18, 12, 30, 42, 0, time.UTC), 124 }, 125 { 126 name: "Empty apiInformation", 127 apiInformation: map[string]interface{}{}, 128 want: time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), 129 }, 130 { 131 name: "apiInformation does not contain key", 132 apiInformation: map[string]interface{}{"someKey": "someValue"}, 133 want: time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), 134 }, 135 { 136 name: "apiInformation contains malformed date", 137 apiInformation: map[string]interface{}{"startTime": "2022-03/18 12:30:42.0Z"}, 138 want: time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), 139 }, 140 } 141 for _, tt := range tests { 142 t.Run(tt.name, func(t *testing.T) { 143 a := &AzureDevOpsConfigProvider{} 144 a.apiInformation = tt.apiInformation 145 pipelineStartTime := a.GetPipelineStartTime() 146 assert.Equalf(t, tt.want, pipelineStartTime, "GetPipelineStartTime()") 147 }) 148 } 149 } 150 151 func TestAzureDevOpsConfigProvider_GetBuildStatus(t *testing.T) { 152 153 tests := []struct { 154 name string 155 want string 156 envVar string 157 }{ 158 { 159 name: "Success", 160 envVar: "Succeeded", 161 want: "SUCCESS", 162 }, 163 { 164 name: "aborted", 165 envVar: "Canceled", 166 want: "ABORTED", 167 }, 168 { 169 name: "failure", 170 envVar: "failed", 171 want: "FAILURE", 172 }, 173 { 174 name: "other", 175 envVar: "some other status", 176 want: "FAILURE", 177 }, 178 } 179 for _, tt := range tests { 180 t.Run(tt.name, func(t *testing.T) { 181 defer resetEnv(os.Environ()) 182 os.Clearenv() 183 os.Setenv("AGENT_JOBSTATUS", tt.envVar) 184 a := &AzureDevOpsConfigProvider{} 185 186 assert.Equalf(t, tt.want, a.GetBuildStatus(), "GetBuildStatus()") 187 }) 188 } 189 } 190 191 func TestAzureDevOpsConfigProvider_getAPIInformation(t *testing.T) { 192 tests := []struct { 193 name string 194 wantHTTPErr bool 195 wantHTTPStatusCodeError bool 196 wantHTTPJSONParseError bool 197 apiInformation map[string]interface{} 198 wantAPIInformation map[string]interface{} 199 }{ 200 { 201 name: "success case", 202 apiInformation: map[string]interface{}{}, 203 wantAPIInformation: map[string]interface{}{"Success": "Case"}, 204 }, 205 { 206 name: "apiInformation already set", 207 apiInformation: map[string]interface{}{"API info": "set"}, 208 wantAPIInformation: map[string]interface{}{"API info": "set"}, 209 }, 210 { 211 name: "failed to get response", 212 apiInformation: map[string]interface{}{}, 213 wantHTTPErr: true, 214 wantAPIInformation: map[string]interface{}{}, 215 }, 216 { 217 name: "response code != 200 http.StatusNoContent", 218 wantHTTPStatusCodeError: true, 219 apiInformation: map[string]interface{}{}, 220 wantAPIInformation: map[string]interface{}{}, 221 }, 222 { 223 name: "parseResponseBodyJson fails", 224 wantHTTPJSONParseError: true, 225 apiInformation: map[string]interface{}{}, 226 wantAPIInformation: map[string]interface{}{}, 227 }, 228 } 229 230 for _, tt := range tests { 231 t.Run(tt.name, func(t *testing.T) { 232 a := &AzureDevOpsConfigProvider{ 233 apiInformation: tt.apiInformation, 234 } 235 236 a.client.SetOptions(piperhttp.ClientOptions{ 237 MaxRequestDuration: 5 * time.Second, 238 Token: "TOKEN", 239 TransportSkipVerification: true, 240 UseDefaultTransport: true, // need to use default transport for http mock 241 MaxRetries: -1, 242 }) 243 244 defer resetEnv(os.Environ()) 245 os.Clearenv() 246 os.Setenv("SYSTEM_COLLECTIONURI", "https://dev.azure.com/fabrikamfiber/") 247 os.Setenv("SYSTEM_TEAMPROJECTID", "123a4567-ab1c-12a1-1234-123456ab7890") 248 os.Setenv("BUILD_BUILDID", "1234") 249 250 fakeUrl := "https://dev.azure.com/fabrikamfiber/123a4567-ab1c-12a1-1234-123456ab7890/_apis/build/builds/1234/" 251 httpmock.Activate() 252 defer httpmock.DeactivateAndReset() 253 httpmock.RegisterResponder("GET", fakeUrl, 254 func(req *http.Request) (*http.Response, error) { 255 if tt.wantHTTPErr { 256 return nil, errors.New("this error shows up") 257 } 258 if tt.wantHTTPStatusCodeError { 259 return &http.Response{ 260 Status: "204", 261 StatusCode: http.StatusNoContent, 262 Request: req, 263 }, nil 264 } 265 if tt.wantHTTPJSONParseError { 266 // Intentionally malformed JSON response 267 return httpmock.NewJsonResponse(200, "timestamp:broken") 268 } 269 return httpmock.NewStringResponse(200, "{\"Success\":\"Case\"}"), nil 270 }, 271 ) 272 273 a.fetchAPIInformation() 274 assert.Equal(t, tt.wantAPIInformation, a.apiInformation) 275 }) 276 } 277 } 278 279 func TestAzureDevOpsConfigProvider_GetLog(t *testing.T) { 280 tests := []struct { 281 name string 282 want []byte 283 wantErr assert.ErrorAssertionFunc 284 wantHTTPErr bool 285 wantHTTPStatusCodeError bool 286 wantLogCountError bool 287 }{ 288 { 289 name: "Successfully got log file", 290 want: []byte("Success"), 291 wantErr: assert.NoError, 292 }, 293 { 294 name: "Log count variable not available", 295 want: []byte(""), 296 wantErr: assert.NoError, 297 wantLogCountError: true, 298 }, 299 { 300 name: "HTTP error", 301 want: []byte(""), 302 wantErr: assert.Error, 303 wantHTTPErr: true, 304 }, 305 { 306 name: "Status code error", 307 want: []byte(""), 308 wantErr: assert.NoError, 309 wantHTTPStatusCodeError: true, 310 }, 311 } 312 for _, tt := range tests { 313 t.Run(tt.name, func(t *testing.T) { 314 a := &AzureDevOpsConfigProvider{} 315 a.client.SetOptions(piperhttp.ClientOptions{ 316 MaxRequestDuration: 5 * time.Second, 317 Token: "TOKEN", 318 TransportSkipVerification: true, 319 UseDefaultTransport: true, // need to use default transport for http mock 320 MaxRetries: -1, 321 }) 322 323 defer resetEnv(os.Environ()) 324 os.Clearenv() 325 os.Setenv("SYSTEM_COLLECTIONURI", "https://dev.azure.com/fabrikamfiber/") 326 os.Setenv("SYSTEM_TEAMPROJECTID", "123a4567-ab1c-12a1-1234-123456ab7890") 327 os.Setenv("BUILD_BUILDID", "1234") 328 329 fakeUrl := "https://dev.azure.com/fabrikamfiber/123a4567-ab1c-12a1-1234-123456ab7890/_apis/build/builds/1234/logs" 330 httpmock.Activate() 331 defer httpmock.DeactivateAndReset() 332 httpmock.RegisterResponder("GET", fakeUrl+"/1", 333 func(req *http.Request) (*http.Response, error) { 334 return httpmock.NewStringResponse(200, "Success"), nil 335 }) 336 httpmock.RegisterResponder("GET", fakeUrl, 337 func(req *http.Request) (*http.Response, error) { 338 if tt.wantHTTPErr { 339 return nil, errors.New("this error shows up") 340 } 341 if tt.wantHTTPStatusCodeError { 342 return &http.Response{ 343 Status: "204", 344 StatusCode: http.StatusNoContent, 345 Request: req, 346 }, nil 347 } 348 if tt.wantLogCountError { 349 return httpmock.NewJsonResponse(200, map[string]interface{}{ 350 "some": "value", 351 }) 352 } 353 return httpmock.NewJsonResponse(200, map[string]interface{}{ 354 "count": 1, 355 }) 356 }, 357 ) 358 got, err := a.GetLog() 359 if !tt.wantErr(t, err, fmt.Sprintf("GetLog()")) { 360 return 361 } 362 assert.Equalf(t, tt.want, got, "GetLog()") 363 }) 364 } 365 }