github.com/zppinho/prow@v0.0.0-20240510014325-1738badeb017/cmd/deck/abort_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  	"fmt"
    22  	"net/http"
    23  	"net/http/httptest"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/gorilla/sessions"
    28  	"github.com/sirupsen/logrus"
    29  	"golang.org/x/oauth2"
    30  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    31  	prowapi "sigs.k8s.io/prow/pkg/apis/prowjobs/v1"
    32  	"sigs.k8s.io/prow/pkg/client/clientset/versioned/fake"
    33  	"sigs.k8s.io/prow/pkg/github/fakegithub"
    34  	"sigs.k8s.io/prow/pkg/githuboauth"
    35  	"sigs.k8s.io/prow/pkg/plugins"
    36  )
    37  
    38  // TestAbort that an aborted job has an updated status and
    39  // that permissions were granted appropriately
    40  func TestAbort(t *testing.T) {
    41  	testCases := []struct {
    42  		name        string
    43  		login       string
    44  		authorized  []string
    45  		allowAnyone bool
    46  		jobState    prowapi.ProwJobState
    47  		httpCode    int
    48  		httpMethod  string
    49  	}{
    50  		{
    51  			name:        "Abort on triggered state",
    52  			login:       "authorized",
    53  			authorized:  []string{"authorized", "alsoauthorized"},
    54  			allowAnyone: false,
    55  			jobState:    prowapi.TriggeredState,
    56  			httpCode:    http.StatusOK,
    57  			httpMethod:  http.MethodPost,
    58  		},
    59  		{
    60  			name:        "Abort on pending state",
    61  			login:       "authorized",
    62  			authorized:  []string{"authorized", "alsoauthorized"},
    63  			allowAnyone: false,
    64  			jobState:    prowapi.PendingState,
    65  			httpCode:    http.StatusOK,
    66  			httpMethod:  http.MethodPost,
    67  		},
    68  		{
    69  			name:        "Attempt to abort on success state",
    70  			login:       "authorized",
    71  			authorized:  []string{"authorized", "alsoauthorized"},
    72  			allowAnyone: false,
    73  			jobState:    prowapi.SuccessState,
    74  			httpCode:    http.StatusBadRequest,
    75  			httpMethod:  http.MethodPost,
    76  		},
    77  		{
    78  			name:        "Attempt to abort on aborted state",
    79  			login:       "authorized",
    80  			authorized:  []string{"authorized", "alsoauthorized"},
    81  			allowAnyone: false,
    82  			jobState:    prowapi.AbortedState,
    83  			httpCode:    http.StatusBadRequest,
    84  			httpMethod:  http.MethodPost,
    85  		},
    86  		{
    87  			name:        "User not authorized to abort job",
    88  			login:       "random-dude",
    89  			authorized:  []string{"authorized", "alsoauthorized"},
    90  			allowAnyone: false,
    91  			jobState:    prowapi.PendingState,
    92  			httpCode:    http.StatusUnauthorized,
    93  			httpMethod:  http.MethodPost,
    94  		},
    95  		{
    96  			name:        "Allow anyone set to true, abort job",
    97  			login:       "ugh",
    98  			authorized:  []string{"authorized", "alsoauthorized"},
    99  			allowAnyone: true,
   100  			jobState:    prowapi.PendingState,
   101  			httpCode:    http.StatusOK,
   102  			httpMethod:  http.MethodPost,
   103  		},
   104  		{
   105  			name:        "User permitted to abort on specific job",
   106  			login:       "authorized",
   107  			authorized:  []string{},
   108  			allowAnyone: false,
   109  			jobState:    prowapi.PendingState,
   110  			httpCode:    http.StatusOK,
   111  			httpMethod:  http.MethodPost,
   112  		},
   113  		{
   114  			name:        "User on permitted team",
   115  			login:       "sig-lead",
   116  			authorized:  []string{},
   117  			allowAnyone: false,
   118  			jobState:    prowapi.PendingState,
   119  			httpCode:    http.StatusOK,
   120  			httpMethod:  http.MethodPost,
   121  		},
   122  	}
   123  
   124  	for _, tc := range testCases {
   125  		t.Run(tc.name, func(t *testing.T) {
   126  			fakeProwJobClient := fake.NewSimpleClientset(&prowapi.ProwJob{
   127  				ObjectMeta: metav1.ObjectMeta{
   128  					Name:      "wowsuch",
   129  					Namespace: "prowjobs",
   130  				},
   131  				Spec: prowapi.ProwJobSpec{
   132  					Job:  "whoa",
   133  					Type: prowapi.PresubmitJob,
   134  					Refs: &prowapi.Refs{
   135  						Org:  "org",
   136  						Repo: "repo",
   137  						Pulls: []prowapi.Pull{
   138  							{
   139  								Number: 1,
   140  								Author: tc.login,
   141  							},
   142  						},
   143  					},
   144  					RerunAuthConfig: &prowapi.RerunAuthConfig{
   145  						AllowAnyone:   false,
   146  						GitHubUsers:   []string{"authorized", "alsoauthorized"},
   147  						GitHubTeamIDs: []int{42},
   148  					},
   149  				},
   150  				Status: prowapi.ProwJobStatus{
   151  					State: tc.jobState,
   152  				},
   153  			})
   154  			authCfgGetter := func(refs *prowapi.ProwJobSpec) *prowapi.RerunAuthConfig {
   155  				return &prowapi.RerunAuthConfig{
   156  					AllowAnyone: tc.allowAnyone,
   157  					GitHubUsers: tc.authorized,
   158  				}
   159  			}
   160  
   161  			req, err := http.NewRequest(tc.httpMethod, "/abort?prowjob=wowsuch", nil)
   162  			if err != nil {
   163  				t.Fatalf("Error making request: %v", err)
   164  			}
   165  			req.AddCookie(&http.Cookie{
   166  				Name:    "github_login",
   167  				Value:   tc.login,
   168  				Path:    "/",
   169  				Expires: time.Now().Add(time.Hour * 24 * 30),
   170  				Secure:  true,
   171  			})
   172  			mockCookieStore := sessions.NewCookieStore([]byte("secret-key"))
   173  			session, err := sessions.GetRegistry(req).Get(mockCookieStore, "access-token-session")
   174  			if err != nil {
   175  				t.Fatalf("Error making access token session: %v", err)
   176  			}
   177  			session.Values["access-token"] = &oauth2.Token{AccessToken: "validtoken"}
   178  
   179  			rr := httptest.NewRecorder()
   180  			mockConfig := &githuboauth.Config{
   181  				CookieStore: mockCookieStore,
   182  			}
   183  			goa := githuboauth.NewAgent(mockConfig, &logrus.Entry{})
   184  			ghc := &fakeAuthenticatedUserIdentifier{login: tc.login}
   185  			rc := fakegithub.NewFakeClient()
   186  			rc.OrgMembers = map[string][]string{"org": {"org-member"}}
   187  			pca := plugins.NewFakeConfigAgent()
   188  			handler := handleAbort(fakeProwJobClient.ProwV1().ProwJobs("prowjobs"), authCfgGetter, goa, ghc, rc, &pca, logrus.WithField("handler", "/abort"))
   189  			handler.ServeHTTP(rr, req)
   190  			if rr.Code != tc.httpCode {
   191  				t.Fatalf("Bad error code: %d", rr.Code)
   192  			}
   193  
   194  			if tc.httpCode == http.StatusOK {
   195  				pj, err := fakeProwJobClient.ProwV1().ProwJobs("prowjobs").Get(context.TODO(), "wowsuch", metav1.GetOptions{})
   196  				if err != nil {
   197  					t.Fatalf("Job not found: %v", err)
   198  				}
   199  				if pj.Status.State != prowapi.AbortedState {
   200  					t.Errorf("Wrong state, expected \"%v\", got \"%v\"", prowapi.AbortedState, pj.Status.State)
   201  				}
   202  				if pj.Complete() {
   203  					t.Errorf("Did not expect to be complete, expected \"%v\", got \"%v\"", !pj.Complete(), pj.Complete())
   204  				}
   205  				expectedDescription := fmt.Sprintf("%v successfully aborted wowsuch.", tc.login)
   206  				if tc.allowAnyone {
   207  					expectedDescription = "Successfully aborted wowsuch."
   208  				}
   209  				if pj.Status.Description != expectedDescription {
   210  					t.Errorf("Wrong description, expected \"%v\", got \"%v\"", expectedDescription, pj.Status.Description)
   211  				}
   212  			}
   213  		})
   214  	}
   215  }