github.com/zppinho/prow@v0.0.0-20240510014325-1738badeb017/cmd/deck/rerun_test.go (about)

     1  /*
     2  Copyright 2022 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package main
    18  
    19  import (
    20  	"context"
    21  	"io"
    22  	"net/http"
    23  	"net/http/httptest"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/google/go-cmp/cmp"
    28  	"github.com/gorilla/sessions"
    29  	"github.com/sirupsen/logrus"
    30  	"golang.org/x/oauth2"
    31  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    32  	prowapi "sigs.k8s.io/prow/pkg/apis/prowjobs/v1"
    33  	"sigs.k8s.io/prow/pkg/client/clientset/versioned/fake"
    34  	"sigs.k8s.io/prow/pkg/config"
    35  	"sigs.k8s.io/prow/pkg/github/fakegithub"
    36  	"sigs.k8s.io/prow/pkg/githuboauth"
    37  	"sigs.k8s.io/prow/pkg/kube"
    38  	"sigs.k8s.io/prow/pkg/plugins"
    39  	"sigs.k8s.io/yaml"
    40  )
    41  
    42  func getPresubmitConfig() *config.Config {
    43  	presubmitJobs := []config.Presubmit{
    44  		{
    45  			JobBase: config.JobBase{
    46  				Name: "whoa",
    47  				Labels: map[string]string{
    48  					"foo": "foo",
    49  				},
    50  				Annotations: map[string]string{
    51  					"foo": "foo",
    52  				},
    53  				RerunAuthConfig: &prowapi.RerunAuthConfig{
    54  					AllowAnyone:   false,
    55  					GitHubUsers:   []string{"authorized", "alsoauthorized"},
    56  					GitHubTeamIDs: []int{42},
    57  				},
    58  			},
    59  			Brancher: config.Brancher{
    60  				Branches: []string{"master"},
    61  			},
    62  		},
    63  	}
    64  	config.SetPresubmitRegexes(presubmitJobs)
    65  	return &config.Config{
    66  		JobConfig: config.JobConfig{
    67  			PresubmitsStatic: map[string][]config.Presubmit{"org/repo": presubmitJobs},
    68  		},
    69  	}
    70  }
    71  
    72  func getPeriodicConfig() *config.Config {
    73  	return &config.Config{
    74  		JobConfig: config.JobConfig{
    75  			Periodics: []config.Periodic{{
    76  				JobBase: config.JobBase{
    77  					Name: "whoa",
    78  					Labels: map[string]string{
    79  						"foo": "foo",
    80  					},
    81  					Annotations: map[string]string{
    82  						"foo": "foo",
    83  					},
    84  					RerunAuthConfig: &prowapi.RerunAuthConfig{
    85  						AllowAnyone:   false,
    86  						GitHubUsers:   []string{"authorized", "alsoauthorized"},
    87  						GitHubTeamIDs: []int{42},
    88  					},
    89  				},
    90  			}},
    91  		},
    92  	}
    93  }
    94  
    95  // TestRerun just checks that the result can be unmarshaled properly, has an
    96  // updated status, and has equal spec.
    97  func TestRerun(t *testing.T) {
    98  	testCases := []struct {
    99  		name                string
   100  		login               string
   101  		authorized          []string
   102  		allowAnyone         bool
   103  		rerunCreatesJob     bool
   104  		shouldCreateProwJob bool
   105  		httpCode            int
   106  		httpMethod          string
   107  		enableScheduling    bool
   108  		wantProwJobState    prowapi.ProwJobState
   109  	}{
   110  		{
   111  			name:                "Handler returns ProwJob",
   112  			login:               "authorized",
   113  			authorized:          []string{"authorized", "alsoauthorized"},
   114  			allowAnyone:         false,
   115  			rerunCreatesJob:     true,
   116  			shouldCreateProwJob: true,
   117  			httpCode:            http.StatusOK,
   118  			httpMethod:          http.MethodPost,
   119  			wantProwJobState:    prowapi.TriggeredState,
   120  		},
   121  		{
   122  			name:                "User not authorized to create prow job",
   123  			login:               "random-dude",
   124  			authorized:          []string{"authorized", "alsoauthorized"},
   125  			allowAnyone:         false,
   126  			rerunCreatesJob:     true,
   127  			shouldCreateProwJob: false,
   128  			httpCode:            http.StatusOK,
   129  			httpMethod:          http.MethodPost,
   130  		},
   131  		{
   132  			name:                "RerunCreatesJob set to false, should not create prow job",
   133  			login:               "authorized",
   134  			authorized:          []string{"authorized", "alsoauthorized"},
   135  			allowAnyone:         true,
   136  			rerunCreatesJob:     false,
   137  			shouldCreateProwJob: false,
   138  			httpCode:            http.StatusOK,
   139  			httpMethod:          http.MethodGet,
   140  		},
   141  		{
   142  			name:                "Allow anyone set to true, creates job",
   143  			login:               "ugh",
   144  			authorized:          []string{"authorized", "alsoauthorized"},
   145  			allowAnyone:         true,
   146  			rerunCreatesJob:     true,
   147  			shouldCreateProwJob: true,
   148  			httpCode:            http.StatusOK,
   149  			httpMethod:          http.MethodPost,
   150  			wantProwJobState:    prowapi.TriggeredState,
   151  		},
   152  		{
   153  			name:                "Direct rerun disabled, post request",
   154  			login:               "authorized",
   155  			authorized:          []string{"authorized", "alsoauthorized"},
   156  			allowAnyone:         true,
   157  			rerunCreatesJob:     false,
   158  			shouldCreateProwJob: false,
   159  			httpCode:            http.StatusMethodNotAllowed,
   160  			httpMethod:          http.MethodPost,
   161  		},
   162  		{
   163  			name:                "User permitted on specific job",
   164  			login:               "authorized",
   165  			authorized:          []string{},
   166  			allowAnyone:         false,
   167  			rerunCreatesJob:     true,
   168  			shouldCreateProwJob: true,
   169  			httpCode:            http.StatusOK,
   170  			httpMethod:          http.MethodPost,
   171  			wantProwJobState:    prowapi.TriggeredState,
   172  		},
   173  		{
   174  			name:                "User on permitted team",
   175  			login:               "sig-lead",
   176  			authorized:          []string{},
   177  			allowAnyone:         false,
   178  			rerunCreatesJob:     true,
   179  			shouldCreateProwJob: true,
   180  			httpCode:            http.StatusOK,
   181  			httpMethod:          http.MethodPost,
   182  			wantProwJobState:    prowapi.TriggeredState,
   183  		},
   184  		{
   185  			name:                "Org member permitted for presubmits",
   186  			login:               "org-member",
   187  			authorized:          []string{},
   188  			allowAnyone:         false,
   189  			rerunCreatesJob:     true,
   190  			shouldCreateProwJob: true,
   191  			httpCode:            http.StatusOK,
   192  			httpMethod:          http.MethodPost,
   193  			wantProwJobState:    prowapi.TriggeredState,
   194  		},
   195  		{
   196  			name:                "Rerun ProwJob in scheduling state",
   197  			login:               "authorized",
   198  			authorized:          []string{"authorized", "alsoauthorized"},
   199  			allowAnyone:         false,
   200  			rerunCreatesJob:     true,
   201  			shouldCreateProwJob: true,
   202  			httpCode:            http.StatusOK,
   203  			httpMethod:          http.MethodPost,
   204  			enableScheduling:    true,
   205  			wantProwJobState:    prowapi.SchedulingState,
   206  		},
   207  	}
   208  
   209  	for _, tc := range testCases {
   210  		t.Run(tc.name, func(t *testing.T) {
   211  			fakeProwJobClient := fake.NewSimpleClientset(&prowapi.ProwJob{
   212  				ObjectMeta: metav1.ObjectMeta{
   213  					Name:      "wowsuch",
   214  					Namespace: "prowjobs",
   215  				},
   216  				Spec: prowapi.ProwJobSpec{
   217  					Job:  "whoa",
   218  					Type: prowapi.PresubmitJob,
   219  					Refs: &prowapi.Refs{
   220  						Org:  "org",
   221  						Repo: "repo",
   222  						Pulls: []prowapi.Pull{
   223  							{
   224  								Number: 1,
   225  								Author: tc.login,
   226  							},
   227  						},
   228  					},
   229  					RerunAuthConfig: &prowapi.RerunAuthConfig{
   230  						AllowAnyone:   false,
   231  						GitHubUsers:   []string{"authorized", "alsoauthorized"},
   232  						GitHubTeamIDs: []int{42},
   233  					},
   234  				},
   235  				Status: prowapi.ProwJobStatus{
   236  					State: prowapi.PendingState,
   237  				},
   238  			})
   239  			authCfgGetter := func(refs *prowapi.ProwJobSpec) *prowapi.RerunAuthConfig {
   240  				return &prowapi.RerunAuthConfig{
   241  					AllowAnyone: tc.allowAnyone,
   242  					GitHubUsers: tc.authorized,
   243  				}
   244  			}
   245  
   246  			req, err := http.NewRequest(tc.httpMethod, "/rerun?prowjob=wowsuch", nil)
   247  			if err != nil {
   248  				t.Fatalf("Error making request: %v", err)
   249  			}
   250  			req.AddCookie(&http.Cookie{
   251  				Name:    "github_login",
   252  				Value:   tc.login,
   253  				Path:    "/",
   254  				Expires: time.Now().Add(time.Hour * 24 * 30),
   255  				Secure:  true,
   256  			})
   257  			mockCookieStore := sessions.NewCookieStore([]byte("secret-key"))
   258  			session, err := sessions.GetRegistry(req).Get(mockCookieStore, "access-token-session")
   259  			if err != nil {
   260  				t.Fatalf("Error making access token session: %v", err)
   261  			}
   262  			session.Values["access-token"] = &oauth2.Token{AccessToken: "validtoken"}
   263  
   264  			rr := httptest.NewRecorder()
   265  			mockConfig := &githuboauth.Config{
   266  				CookieStore: mockCookieStore,
   267  			}
   268  			goa := githuboauth.NewAgent(mockConfig, &logrus.Entry{})
   269  			ghc := &fakeAuthenticatedUserIdentifier{login: tc.login}
   270  			rc := fakegithub.NewFakeClient()
   271  			rc.OrgMembers = map[string][]string{"org": {"org-member"}}
   272  			pca := plugins.NewFakeConfigAgent()
   273  			cfg := func() *config.Config {
   274  				return &config.Config{ProwConfig: config.ProwConfig{Scheduler: config.Scheduler{Enabled: tc.enableScheduling}}}
   275  			}
   276  			handler := handleRerun(cfg, fakeProwJobClient.ProwV1().ProwJobs("prowjobs"), tc.rerunCreatesJob, authCfgGetter, goa, ghc, rc, &pca, logrus.WithField("handler", "/rerun"))
   277  			handler.ServeHTTP(rr, req)
   278  			if rr.Code != tc.httpCode {
   279  				t.Fatalf("Bad error code: %d", rr.Code)
   280  			}
   281  
   282  			if tc.shouldCreateProwJob {
   283  				pjs, err := fakeProwJobClient.ProwV1().ProwJobs("prowjobs").List(context.Background(), metav1.ListOptions{})
   284  				if err != nil {
   285  					t.Fatalf("failed to list prowjobs: %v", err)
   286  				}
   287  				if numPJs := len(pjs.Items); numPJs != 2 {
   288  					t.Errorf("expected to get two prowjobs, got %d", numPJs)
   289  				}
   290  				for i := range pjs.Items {
   291  					pj := &pjs.Items[i]
   292  					if pj.Name != "wowsuch" && pj.Status.State != tc.wantProwJobState {
   293  						t.Errorf("expected state %s but got %s in pj %s", tc.wantProwJobState, pj.Status.State, pj.Spec.Job)
   294  					}
   295  				}
   296  			} else if !tc.rerunCreatesJob && tc.httpCode == http.StatusOK {
   297  				resp := rr.Result()
   298  				defer resp.Body.Close()
   299  				body, err := io.ReadAll(resp.Body)
   300  				if err != nil {
   301  					t.Fatalf("Error reading response body: %v", err)
   302  				}
   303  				var res prowapi.ProwJob
   304  				if err := yaml.Unmarshal(body, &res); err != nil {
   305  					t.Fatalf("Error unmarshaling: %v", err)
   306  				}
   307  				if res.Spec.Job != "whoa" {
   308  					t.Errorf("Wrong job, expected \"whoa\", got \"%s\"", res.Spec.Job)
   309  				}
   310  				if res.Status.State != prowapi.TriggeredState {
   311  					t.Errorf("Wrong state, expected \"%v\", got \"%v\"", prowapi.TriggeredState, res.Status.State)
   312  				}
   313  			}
   314  		})
   315  	}
   316  }
   317  
   318  // TestLatestRerun just checks that the result can be unmarshaled properly, has an
   319  // updated status, and has equal spec.
   320  func TestLatestRerun(t *testing.T) {
   321  	testCases := []struct {
   322  		name                string
   323  		pjType              prowapi.ProwJobType
   324  		config              *config.Config
   325  		login               string
   326  		authorized          []string
   327  		allowAnyone         bool
   328  		rerunCreatesJob     bool
   329  		shouldCreateProwJob bool
   330  		reported            bool
   331  		httpCode            int
   332  		httpMethod          string
   333  		enableScheduling    bool
   334  		wantProwJobState    prowapi.ProwJobState
   335  	}{
   336  		{
   337  			name:                "Handler returns Presubmit ProwJob",
   338  			pjType:              prowapi.PresubmitJob,
   339  			config:              getPresubmitConfig(),
   340  			login:               "authorized",
   341  			authorized:          []string{"authorized", "alsoauthorized"},
   342  			allowAnyone:         false,
   343  			rerunCreatesJob:     true,
   344  			shouldCreateProwJob: true,
   345  			reported:            false,
   346  			httpCode:            http.StatusOK,
   347  			httpMethod:          http.MethodPost,
   348  			wantProwJobState:    prowapi.TriggeredState,
   349  		},
   350  		{
   351  			name:                "Handler returns Periodic ProwJob",
   352  			pjType:              prowapi.PeriodicJob,
   353  			config:              getPeriodicConfig(),
   354  			login:               "authorized",
   355  			authorized:          []string{"authorized", "alsoauthorized"},
   356  			allowAnyone:         false,
   357  			rerunCreatesJob:     true,
   358  			shouldCreateProwJob: true,
   359  			reported:            false,
   360  			httpCode:            http.StatusOK,
   361  			httpMethod:          http.MethodPost,
   362  			wantProwJobState:    prowapi.TriggeredState,
   363  		},
   364  		{
   365  			name:                "User not authorized to create prow job",
   366  			pjType:              prowapi.PresubmitJob,
   367  			config:              getPresubmitConfig(),
   368  			login:               "random-dude",
   369  			authorized:          []string{"authorized", "alsoauthorized"},
   370  			allowAnyone:         false,
   371  			rerunCreatesJob:     true,
   372  			shouldCreateProwJob: false,
   373  			reported:            false,
   374  			httpCode:            http.StatusOK,
   375  			httpMethod:          http.MethodPost,
   376  		},
   377  		{
   378  			name:                "RerunCreatesJob set to false, should not create prow job",
   379  			pjType:              prowapi.PresubmitJob,
   380  			config:              getPresubmitConfig(),
   381  			login:               "authorized",
   382  			authorized:          []string{"authorized", "alsoauthorized"},
   383  			allowAnyone:         true,
   384  			rerunCreatesJob:     false,
   385  			shouldCreateProwJob: false,
   386  			reported:            true,
   387  			httpCode:            http.StatusOK,
   388  			httpMethod:          http.MethodGet,
   389  		},
   390  		{
   391  			name:                "Allow anyone set to true, creates job",
   392  			pjType:              prowapi.PresubmitJob,
   393  			config:              getPresubmitConfig(),
   394  			login:               "ugh",
   395  			authorized:          []string{"authorized", "alsoauthorized"},
   396  			allowAnyone:         true,
   397  			rerunCreatesJob:     true,
   398  			shouldCreateProwJob: true,
   399  			reported:            false,
   400  			httpCode:            http.StatusOK,
   401  			httpMethod:          http.MethodPost,
   402  			wantProwJobState:    prowapi.TriggeredState,
   403  		},
   404  		{
   405  			name:                "Direct rerun disabled, post request",
   406  			pjType:              prowapi.PresubmitJob,
   407  			config:              getPresubmitConfig(),
   408  			login:               "authorized",
   409  			authorized:          []string{"authorized", "alsoauthorized"},
   410  			allowAnyone:         true,
   411  			rerunCreatesJob:     false,
   412  			shouldCreateProwJob: false,
   413  			httpCode:            http.StatusMethodNotAllowed,
   414  			httpMethod:          http.MethodPost,
   415  		},
   416  		{
   417  			name:                "User permitted on specific job",
   418  			pjType:              prowapi.PresubmitJob,
   419  			config:              getPresubmitConfig(),
   420  			login:               "authorized",
   421  			authorized:          []string{},
   422  			allowAnyone:         false,
   423  			rerunCreatesJob:     true,
   424  			shouldCreateProwJob: true,
   425  			reported:            false,
   426  			httpCode:            http.StatusOK,
   427  			httpMethod:          http.MethodPost,
   428  			wantProwJobState:    prowapi.TriggeredState,
   429  		},
   430  		{
   431  			name:                "User on permitted team",
   432  			pjType:              prowapi.PresubmitJob,
   433  			config:              getPresubmitConfig(),
   434  			login:               "sig-lead",
   435  			authorized:          []string{},
   436  			allowAnyone:         false,
   437  			rerunCreatesJob:     true,
   438  			shouldCreateProwJob: true,
   439  			reported:            false,
   440  			httpCode:            http.StatusOK,
   441  			httpMethod:          http.MethodPost,
   442  			wantProwJobState:    prowapi.TriggeredState,
   443  		},
   444  		{
   445  			name:                "Org member permitted for presubmits",
   446  			pjType:              prowapi.PresubmitJob,
   447  			config:              getPresubmitConfig(),
   448  			login:               "org-member",
   449  			authorized:          []string{},
   450  			allowAnyone:         false,
   451  			rerunCreatesJob:     true,
   452  			shouldCreateProwJob: true,
   453  			reported:            false,
   454  			httpCode:            http.StatusOK,
   455  			httpMethod:          http.MethodPost,
   456  			wantProwJobState:    prowapi.TriggeredState,
   457  		},
   458  		{
   459  			name:                "Org member not permitted for periodic",
   460  			pjType:              prowapi.PeriodicJob,
   461  			config:              getPeriodicConfig(),
   462  			login:               "org-member",
   463  			authorized:          []string{},
   464  			allowAnyone:         false,
   465  			rerunCreatesJob:     true,
   466  			shouldCreateProwJob: false,
   467  			reported:            false,
   468  			httpCode:            http.StatusOK,
   469  			httpMethod:          http.MethodPost,
   470  		},
   471  		{
   472  			name:                "Rerun ProwJob in scheduling state",
   473  			pjType:              prowapi.PresubmitJob,
   474  			config:              getPresubmitConfig(),
   475  			login:               "authorized",
   476  			authorized:          []string{"authorized", "alsoauthorized"},
   477  			allowAnyone:         false,
   478  			rerunCreatesJob:     true,
   479  			shouldCreateProwJob: true,
   480  			reported:            false,
   481  			httpCode:            http.StatusOK,
   482  			httpMethod:          http.MethodPost,
   483  			enableScheduling:    true,
   484  			wantProwJobState:    prowapi.SchedulingState,
   485  		},
   486  	}
   487  
   488  	for _, tc := range testCases {
   489  		t.Run(tc.name, func(t *testing.T) {
   490  			fakeProwJobClient := fake.NewSimpleClientset(&prowapi.ProwJob{
   491  				ObjectMeta: metav1.ObjectMeta{
   492  					Name:      "wowsuch",
   493  					Namespace: "prowjobs",
   494  					Labels: map[string]string{
   495  						kube.GerritReportLabel: "foo",
   496  						"random":               "foo",
   497  					},
   498  					Annotations: map[string]string{
   499  						kube.GerritID: "foo",
   500  						"random":      "foo",
   501  					},
   502  				},
   503  				Spec: prowapi.ProwJobSpec{
   504  					Job:  "whoa",
   505  					Type: tc.pjType,
   506  					Refs: &prowapi.Refs{
   507  						Org:  "org",
   508  						Repo: "repo",
   509  						Pulls: []prowapi.Pull{
   510  							{
   511  								Number: 1,
   512  								Author: tc.login,
   513  							},
   514  						},
   515  						BaseSHA: "foo",
   516  						BaseRef: "master",
   517  					},
   518  					RerunAuthConfig: &prowapi.RerunAuthConfig{
   519  						AllowAnyone: false,
   520  						GitHubUsers: []string{"random", "random"},
   521  					},
   522  				},
   523  				Status: prowapi.ProwJobStatus{
   524  					State: prowapi.PendingState,
   525  				},
   526  			})
   527  			authCfgGetter := func(refs *prowapi.ProwJobSpec) *prowapi.RerunAuthConfig {
   528  				return &prowapi.RerunAuthConfig{
   529  					AllowAnyone: tc.allowAnyone,
   530  					GitHubUsers: tc.authorized,
   531  				}
   532  			}
   533  
   534  			req, err := http.NewRequest(tc.httpMethod, "/rerun?mode=latest&prowjob=wowsuch", nil)
   535  			if err != nil {
   536  				t.Fatalf("Error making request: %v", err)
   537  			}
   538  			req.AddCookie(&http.Cookie{
   539  				Name:    "github_login",
   540  				Value:   tc.login,
   541  				Path:    "/",
   542  				Expires: time.Now().Add(time.Hour * 24 * 30),
   543  				Secure:  true,
   544  			})
   545  			mockCookieStore := sessions.NewCookieStore([]byte("secret-key"))
   546  			session, err := sessions.GetRegistry(req).Get(mockCookieStore, "access-token-session")
   547  			if err != nil {
   548  				t.Fatalf("Error making access token session: %v", err)
   549  			}
   550  			session.Values["access-token"] = &oauth2.Token{AccessToken: "validtoken"}
   551  
   552  			rr := httptest.NewRecorder()
   553  			mockConfig := &githuboauth.Config{
   554  				CookieStore: mockCookieStore,
   555  			}
   556  			goa := githuboauth.NewAgent(mockConfig, &logrus.Entry{})
   557  			ghc := &fakeAuthenticatedUserIdentifier{login: tc.login}
   558  			rc := fakegithub.NewFakeClient()
   559  			rc.OrgMembers = map[string][]string{"org": {"org-member"}}
   560  			pca := plugins.NewFakeConfigAgent()
   561  			cfg := func() *config.Config {
   562  				cfg := tc.config
   563  				cfg.Scheduler.Enabled = tc.enableScheduling
   564  				return cfg
   565  			}
   566  			handler := handleRerun(cfg, fakeProwJobClient.ProwV1().ProwJobs("prowjobs"), tc.rerunCreatesJob, authCfgGetter, goa, ghc, rc, &pca, logrus.WithField("handler", "/rerun"))
   567  			handler.ServeHTTP(rr, req)
   568  			if rr.Code != tc.httpCode {
   569  				t.Fatalf("Bad error code: %d", rr.Code)
   570  			}
   571  
   572  			if tc.shouldCreateProwJob {
   573  				pjs, err := fakeProwJobClient.ProwV1().ProwJobs("prowjobs").List(context.Background(), metav1.ListOptions{})
   574  				if err != nil {
   575  					t.Fatalf("failed to list prowjobs: %v", err)
   576  				}
   577  				if numPJs := len(pjs.Items); numPJs != 2 {
   578  					t.Errorf("expected to get two prowjobs, got %d", numPJs)
   579  				}
   580  				for i := range pjs.Items {
   581  					pj := &pjs.Items[i]
   582  					if pj.Name != "wowsuch" && pj.Status.State != tc.wantProwJobState {
   583  						t.Errorf("expected state %s but got %s in pj %s", tc.wantProwJobState, pj.Status.State, pj.Spec.Job)
   584  					}
   585  				}
   586  			} else if !tc.rerunCreatesJob && tc.httpCode == http.StatusOK {
   587  				expectedProwJob := prowapi.ProwJob{
   588  					TypeMeta: metav1.TypeMeta{
   589  						Kind:       "ProwJob",
   590  						APIVersion: "prow.k8s.io/v1",
   591  					},
   592  					ObjectMeta: metav1.ObjectMeta{
   593  						Labels: map[string]string{
   594  							"created-by-prow":                 "true",
   595  							"foo":                             "foo",
   596  							"prow.k8s.io/context":             "",
   597  							"prow.k8s.io/gerrit-report-label": "foo",
   598  							"prow.k8s.io/job":                 "whoa",
   599  							"prow.k8s.io/refs.base_ref":       "master",
   600  							"prow.k8s.io/refs.org":            "org",
   601  							"prow.k8s.io/refs.pull":           "1",
   602  							"prow.k8s.io/refs.repo":           "repo",
   603  							"prow.k8s.io/type":                string(tc.pjType),
   604  						},
   605  						Annotations: map[string]string{
   606  							"foo":                   "foo",
   607  							"prow.k8s.io/context":   "",
   608  							"prow.k8s.io/gerrit-id": "foo",
   609  							"prow.k8s.io/job":       "whoa",
   610  						},
   611  					},
   612  					Spec: prowapi.ProwJobSpec{
   613  						Job:  "whoa",
   614  						Type: tc.pjType,
   615  						Refs: &prowapi.Refs{
   616  							Org:  "org",
   617  							Repo: "repo",
   618  							Pulls: []prowapi.Pull{
   619  								{
   620  									Number: 1,
   621  									Author: tc.login,
   622  								},
   623  							},
   624  							BaseSHA: "foo",
   625  							BaseRef: "master",
   626  						},
   627  						Report: tc.reported,
   628  						RerunAuthConfig: &prowapi.RerunAuthConfig{
   629  							AllowAnyone:   false,
   630  							GitHubUsers:   tc.authorized,
   631  							GitHubTeamIDs: []int{42},
   632  						},
   633  					},
   634  					Status: prowapi.ProwJobStatus{
   635  						State: prowapi.TriggeredState,
   636  					},
   637  				}
   638  
   639  				resp := rr.Result()
   640  				defer resp.Body.Close()
   641  				body, err := io.ReadAll(resp.Body)
   642  				if err != nil {
   643  					t.Fatalf("Error reading response body: %v", err)
   644  				}
   645  				var res prowapi.ProwJob
   646  				if err := yaml.Unmarshal(body, &res); err != nil {
   647  					t.Fatalf("Error unmarshaling: %v", err)
   648  				}
   649  				// These two fields are undeterministic so there are being set to the default
   650  				res.Status.StartTime = metav1.Time{}
   651  				res.ObjectMeta.Name = ""
   652  				if diff := cmp.Diff(expectedProwJob, res); diff != "" {
   653  					t.Fatalf("Job mismatch. Want: (-), got: (+). \n%s", diff)
   654  				}
   655  			}
   656  		})
   657  	}
   658  }
   659  
   660  func TestCanTriggerJob(t *testing.T) {
   661  	t.Parallel()
   662  	org := "org"
   663  	trustedUser := "trusted"
   664  	untrustedUser := "untrusted"
   665  
   666  	pcfg := &plugins.Configuration{
   667  		Triggers: []plugins.Trigger{{Repos: []string{org}}},
   668  	}
   669  	pcfgGetter := func() *plugins.Configuration { return pcfg }
   670  
   671  	ghc := fakegithub.NewFakeClient()
   672  	ghc.OrgMembers = map[string][]string{org: {trustedUser}}
   673  
   674  	pj := prowapi.ProwJob{
   675  		Spec: prowapi.ProwJobSpec{
   676  			Refs: &prowapi.Refs{
   677  				Org:   org,
   678  				Repo:  "repo",
   679  				Pulls: []prowapi.Pull{{Author: trustedUser}},
   680  			},
   681  			Type: prowapi.PresubmitJob,
   682  		},
   683  	}
   684  	testCases := []struct {
   685  		name          string
   686  		user          string
   687  		expectAllowed bool
   688  	}{
   689  		{
   690  			name:          "Unauthorized user can not rerun",
   691  			user:          untrustedUser,
   692  			expectAllowed: false,
   693  		},
   694  		{
   695  			name:          "Authorized user can re-run",
   696  			user:          trustedUser,
   697  			expectAllowed: true,
   698  		},
   699  	}
   700  
   701  	log := logrus.NewEntry(logrus.StandardLogger())
   702  	for _, tc := range testCases {
   703  		result, err := canTriggerJob(tc.user, pj, nil, ghc, pcfgGetter, log)
   704  		if err != nil {
   705  			t.Fatalf("error: %v", err)
   706  		}
   707  		if result != tc.expectAllowed {
   708  			t.Errorf("got result %t, expected %t", result, tc.expectAllowed)
   709  		}
   710  	}
   711  }