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  }