github.com/ouraigua/jenkins-library@v0.0.0-20231028010029-fbeaf2f3aa9b/pkg/orchestrator/gitHubActions_test.go (about) 1 //go:build unit 2 // +build unit 3 4 package orchestrator 5 6 import ( 7 "fmt" 8 "math/rand" 9 "net/http" 10 "os" 11 "testing" 12 "time" 13 14 "github.com/google/go-github/v45/github" 15 "github.com/jarcoal/httpmock" 16 "github.com/stretchr/testify/assert" 17 ) 18 19 func TestGitHubActionsConfigProvider_GetBuildStatus(t *testing.T) { 20 tests := []struct { 21 name string 22 runData run 23 want string 24 }{ 25 {"BuildStatusSuccess", run{fetched: true, Status: "success"}, BuildStatusSuccess}, 26 {"BuildStatusAborted", run{fetched: true, Status: "cancelled"}, BuildStatusAborted}, 27 {"BuildStatusInProgress", run{fetched: true, Status: "in_progress"}, BuildStatusInProgress}, 28 {"BuildStatusFailure", run{fetched: true, Status: "qwertyu"}, BuildStatusFailure}, 29 {"BuildStatusFailure", run{fetched: true, Status: ""}, BuildStatusFailure}, 30 } 31 for _, tt := range tests { 32 t.Run(tt.name, func(t *testing.T) { 33 g := &GitHubActionsConfigProvider{ 34 runData: tt.runData, 35 } 36 assert.Equalf(t, tt.want, g.GetBuildStatus(), "GetBuildStatus()") 37 }) 38 } 39 } 40 41 func TestGitHubActionsConfigProvider_GetBuildReason(t *testing.T) { 42 tests := []struct { 43 name string 44 envGithubRef string 45 want string 46 }{ 47 {"BuildReasonManual", "workflow_dispatch", BuildReasonManual}, 48 {"BuildReasonSchedule", "schedule", BuildReasonSchedule}, 49 {"BuildReasonPullRequest", "pull_request", BuildReasonPullRequest}, 50 {"BuildReasonResourceTrigger", "workflow_call", BuildReasonResourceTrigger}, 51 {"BuildReasonIndividualCI", "push", BuildReasonIndividualCI}, 52 {"BuildReasonUnknown", "qwerty", BuildReasonUnknown}, 53 {"BuildReasonUnknown", "", BuildReasonUnknown}, 54 } 55 for _, tt := range tests { 56 t.Run(tt.name, func(t *testing.T) { 57 g := &GitHubActionsConfigProvider{} 58 59 _ = os.Setenv("GITHUB_EVENT_NAME", tt.envGithubRef) 60 assert.Equalf(t, tt.want, g.GetBuildReason(), "GetBuildReason()") 61 }) 62 } 63 } 64 65 func TestGitHubActionsConfigProvider_GetRepoURL(t *testing.T) { 66 tests := []struct { 67 name string 68 envServerURL string 69 envRepo string 70 want string 71 }{ 72 {"github.com", "https://github.com", "SAP/jenkins-library", "https://github.com/SAP/jenkins-library"}, 73 } 74 for _, tt := range tests { 75 t.Run(tt.name, func(t *testing.T) { 76 g := &GitHubActionsConfigProvider{} 77 78 _ = os.Setenv("GITHUB_SERVER_URL", tt.envServerURL) 79 _ = os.Setenv("GITHUB_REPOSITORY", tt.envRepo) 80 assert.Equalf(t, tt.want, g.GetRepoURL(), "GetRepoURL()") 81 }) 82 } 83 } 84 85 func TestGitHubActionsConfigProvider_GetPullRequestConfig(t *testing.T) { 86 tests := []struct { 87 name string 88 envRef string 89 want PullRequestConfig 90 }{ 91 {"1", "refs/pull/1234/merge", PullRequestConfig{"n/a", "n/a", "1234"}}, 92 {"2", "refs/pull/1234", PullRequestConfig{"n/a", "n/a", "1234"}}, 93 {"2", "1234/merge", PullRequestConfig{"n/a", "n/a", "1234"}}, 94 } 95 for _, tt := range tests { 96 t.Run(tt.name, func(t *testing.T) { 97 g := &GitHubActionsConfigProvider{} 98 99 _ = os.Setenv("GITHUB_REF", tt.envRef) 100 _ = os.Setenv("GITHUB_HEAD_REF", "n/a") 101 _ = os.Setenv("GITHUB_BASE_REF", "n/a") 102 assert.Equalf(t, tt.want, g.GetPullRequestConfig(), "GetPullRequestConfig()") 103 }) 104 } 105 } 106 107 func TestGitHubActionsConfigProvider_guessCurrentJob(t *testing.T) { 108 tests := []struct { 109 name string 110 jobs []job 111 jobsFetched bool 112 targetJobName string 113 wantJob job 114 }{ 115 { 116 name: "job found", 117 jobs: []job{{Name: "Job1"}, {Name: "Job2"}, {Name: "Job3"}}, 118 jobsFetched: true, 119 targetJobName: "Job2", 120 wantJob: job{Name: "Job2"}, 121 }, 122 { 123 name: "job found", 124 jobs: []job{{Name: "Piper / Job1"}, {Name: "Piper / Job2"}, {Name: "Piper / Job3"}}, 125 jobsFetched: true, 126 targetJobName: "Job2", 127 wantJob: job{Name: "Piper / Job2"}, 128 }, 129 { 130 name: "job not found", 131 jobs: []job{{Name: "Job1"}, {Name: "Job2"}, {Name: "Job3"}}, 132 jobsFetched: true, 133 targetJobName: "Job123", 134 wantJob: job{}, 135 }, 136 } 137 for _, tt := range tests { 138 t.Run(tt.name, func(t *testing.T) { 139 g := &GitHubActionsConfigProvider{ 140 jobs: tt.jobs, 141 jobsFetched: tt.jobsFetched, 142 } 143 _ = os.Setenv("GITHUB_JOB", tt.targetJobName) 144 g.guessCurrentJob() 145 146 assert.Equal(t, tt.wantJob, g.currentJob) 147 }) 148 } 149 } 150 151 func TestGitHubActionsConfigProvider_fetchRunData(t *testing.T) { 152 // data 153 respJson := map[string]interface{}{ 154 "status": "completed", 155 "run_started_at": "2023-08-11T07:28:24Z", 156 "html_url": "https://github.com/SAP/jenkins-library/actions/runs/11111", 157 } 158 startedAt, _ := time.Parse(time.RFC3339, "2023-08-11T07:28:24Z") 159 wantRunData := run{ 160 fetched: true, 161 Status: "completed", 162 StartedAt: startedAt, 163 } 164 165 // setup env vars 166 defer resetEnv(os.Environ()) 167 os.Clearenv() 168 _ = os.Setenv("GITHUB_API_URL", "https://api.github.com") 169 _ = os.Setenv("GITHUB_REPOSITORY", "SAP/jenkins-library") 170 _ = os.Setenv("GITHUB_RUN_ID", "11111") 171 172 // setup provider 173 g := &GitHubActionsConfigProvider{} 174 g.InitOrchestratorProvider(&OrchestratorSettings{}) 175 g.client = github.NewClient(http.DefaultClient) 176 177 // setup http mock 178 httpmock.Activate() 179 defer httpmock.DeactivateAndReset() 180 httpmock.RegisterResponder(http.MethodGet, "https://api.github.com/repos/SAP/jenkins-library/actions/runs/11111", 181 func(req *http.Request) (*http.Response, error) { 182 return httpmock.NewJsonResponse(200, respJson) 183 }, 184 ) 185 186 // run 187 g.fetchRunData() 188 assert.Equal(t, wantRunData, g.runData) 189 } 190 191 func TestGitHubActionsConfigProvider_fetchJobs(t *testing.T) { 192 // data 193 respJson := map[string]interface{}{"jobs": []map[string]interface{}{{ 194 "id": 111, 195 "name": "Piper / Init", 196 "html_url": "https://github.com/SAP/jenkins-library/actions/runs/11111/jobs/111", 197 }, { 198 "id": 222, 199 "name": "Piper / Build", 200 "html_url": "https://github.com/SAP/jenkins-library/actions/runs/11111/jobs/222", 201 }, { 202 "id": 333, 203 "name": "Piper / Acceptance", 204 "html_url": "https://github.com/SAP/jenkins-library/actions/runs/11111/jobs/333", 205 }, 206 }} 207 wantJobs := []job{{ 208 ID: 111, 209 Name: "Piper / Init", 210 HtmlURL: "https://github.com/SAP/jenkins-library/actions/runs/11111/jobs/111", 211 }, { 212 ID: 222, 213 Name: "Piper / Build", 214 HtmlURL: "https://github.com/SAP/jenkins-library/actions/runs/11111/jobs/222", 215 }, { 216 ID: 333, 217 Name: "Piper / Acceptance", 218 HtmlURL: "https://github.com/SAP/jenkins-library/actions/runs/11111/jobs/333", 219 }} 220 221 // setup env vars 222 defer resetEnv(os.Environ()) 223 os.Clearenv() 224 _ = os.Setenv("GITHUB_API_URL", "https://api.github.com") 225 _ = os.Setenv("GITHUB_REPOSITORY", "SAP/jenkins-library") 226 _ = os.Setenv("GITHUB_RUN_ID", "11111") 227 228 // setup provider 229 g := &GitHubActionsConfigProvider{} 230 g.InitOrchestratorProvider(&OrchestratorSettings{}) 231 g.client = github.NewClient(http.DefaultClient) 232 233 // setup http mock 234 httpmock.Activate() 235 defer httpmock.DeactivateAndReset() 236 httpmock.RegisterResponder( 237 http.MethodGet, 238 "https://api.github.com/repos/SAP/jenkins-library/actions/runs/11111/jobs", 239 func(req *http.Request) (*http.Response, error) { 240 return httpmock.NewJsonResponse(200, respJson) 241 }, 242 ) 243 244 // run 245 err := g.fetchJobs() 246 assert.NoError(t, err) 247 assert.Equal(t, wantJobs, g.jobs) 248 } 249 250 func TestGitHubActionsConfigProvider_GetLog(t *testing.T) { 251 // data 252 respLogs := []string{ 253 "log_record11\nlog_record12\nlog_record13\n", 254 "log_record21\nlog_record22\n", 255 "log_record31\nlog_record32\n", 256 "log_record41\n", 257 } 258 wantLogs := "log_record11\nlog_record12\nlog_record13\nlog_record21\n" + 259 "log_record22\nlog_record31\nlog_record32\nlog_record41\n" 260 jobs := []job{ 261 {ID: 111}, {ID: 222}, {ID: 333}, {ID: 444}, {ID: 555}, 262 } 263 264 // setup env vars 265 defer resetEnv(os.Environ()) 266 os.Clearenv() 267 _ = os.Setenv("GITHUB_API_URL", "https://api.github.com") 268 _ = os.Setenv("GITHUB_REPOSITORY", "SAP/jenkins-library") 269 270 // setup provider 271 g := &GitHubActionsConfigProvider{ 272 jobs: jobs, 273 jobsFetched: true, 274 } 275 g.InitOrchestratorProvider(&OrchestratorSettings{}) 276 g.client = github.NewClient(http.DefaultClient) 277 278 // setup http mock 279 rand.Seed(time.Now().UnixNano()) 280 latencyMin, latencyMax := 15, 500 // milliseconds 281 httpmock.Activate() 282 defer httpmock.DeactivateAndReset() 283 for i, j := range jobs { 284 idx := i 285 httpmock.RegisterResponder( 286 http.MethodGet, 287 fmt.Sprintf("https://api.github.com/repos/SAP/jenkins-library/actions/jobs/%d/logs", j.ID), 288 func(jobId int64) func(req *http.Request) (*http.Response, error) { 289 return func(req *http.Request) (*http.Response, error) { 290 resp := httpmock.NewStringResponse(http.StatusFound, respLogs[idx]) 291 logsDownloadUrl := fmt.Sprintf("https://api.github.com/repos/SAP/jenkins-library/actions/jobs/%d/logs/download", jobId) 292 resp.Header.Set("Location", logsDownloadUrl) 293 return resp, nil 294 } 295 }(j.ID), 296 ) 297 httpmock.RegisterResponder( 298 http.MethodGet, 299 fmt.Sprintf("https://api.github.com/repos/SAP/jenkins-library/actions/jobs/%d/logs/download", j.ID), 300 func(req *http.Request) (*http.Response, error) { 301 // simulate response delay 302 latency := rand.Intn(latencyMax-latencyMin) + latencyMin 303 time.Sleep(time.Duration(latency) * time.Millisecond) 304 return httpmock.NewStringResponse(200, respLogs[idx]), nil 305 }, 306 ) 307 } 308 // run 309 logs, err := g.GetLog() 310 assert.NoError(t, err) 311 assert.Equal(t, wantLogs, string(logs)) 312 } 313 314 func TestGitHubActionsConfigProvider_Others(t *testing.T) { 315 defer resetEnv(os.Environ()) 316 os.Clearenv() 317 _ = os.Setenv("GITHUB_ACTION", "1") 318 _ = os.Setenv("GITHUB_JOB", "Build") 319 _ = os.Setenv("GITHUB_RUN_ID", "11111") 320 _ = os.Setenv("GITHUB_REF_NAME", "main") 321 _ = os.Setenv("GITHUB_HEAD_REF", "feature-branch-1") 322 _ = os.Setenv("GITHUB_REF", "refs/pull/42/merge") 323 _ = os.Setenv("GITHUB_WORKFLOW", "Piper workflow") 324 _ = os.Setenv("GITHUB_SHA", "ffac537e6cbbf934b08745a378932722df287a53") 325 _ = os.Setenv("GITHUB_API_URL", "https://api.github.com") 326 _ = os.Setenv("GITHUB_SERVER_URL", "https://github.com") 327 _ = os.Setenv("GITHUB_REPOSITORY", "SAP/jenkins-library") 328 329 p := GitHubActionsConfigProvider{} 330 startedAt, _ := time.Parse(time.RFC3339, "2023-08-11T07:28:24Z") 331 p.runData = run{ 332 fetched: true, 333 Status: "", 334 StartedAt: startedAt, 335 } 336 p.currentJob = job{ID: 111, Name: "job1", HtmlURL: "https://github.com/SAP/jenkins-library/actions/runs/123456/jobs/7654321"} 337 338 assert.Equal(t, "n/a", p.OrchestratorVersion()) 339 assert.Equal(t, "GitHubActions", p.OrchestratorType()) 340 assert.Equal(t, "11111", p.GetBuildID()) 341 assert.Equal(t, []ChangeSet{}, p.GetChangeSet()) 342 assert.Equal(t, startedAt, p.GetPipelineStartTime()) 343 assert.Equal(t, "Build", p.GetStageName()) 344 assert.Equal(t, "main", p.GetBranch()) 345 assert.Equal(t, "refs/pull/42/merge", p.GetReference()) 346 assert.Equal(t, "https://github.com/SAP/jenkins-library/actions/runs/11111", p.GetBuildURL()) 347 assert.Equal(t, "https://github.com/SAP/jenkins-library/actions/runs/123456/jobs/7654321", p.GetJobURL()) 348 assert.Equal(t, "Piper workflow", p.GetJobName()) 349 assert.Equal(t, "ffac537e6cbbf934b08745a378932722df287a53", p.GetCommit()) 350 assert.Equal(t, "https://api.github.com/repos/SAP/jenkins-library/actions", actionsURL()) 351 assert.True(t, p.IsPullRequest()) 352 assert.True(t, isGitHubActions()) 353 }