github.com/munnerz/test-infra@v0.0.0-20190108210205-ce3d181dc989/prow/prstatus/prstatus_test.go (about) 1 /* 2 Copyright 2018 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 prstatus 18 19 import ( 20 "context" 21 "encoding/gob" 22 "io/ioutil" 23 "net/http" 24 "net/http/httptest" 25 "reflect" 26 "testing" 27 "time" 28 29 "golang.org/x/oauth2" 30 31 gogithub "github.com/google/go-github/github" 32 "github.com/gorilla/sessions" 33 "github.com/sirupsen/logrus" 34 "sigs.k8s.io/yaml" 35 36 "k8s.io/test-infra/pkg/ghclient" 37 "k8s.io/test-infra/prow/config" 38 "k8s.io/test-infra/prow/github" 39 ) 40 41 type MockQueryHandler struct { 42 prs []PullRequest 43 contextMap map[int][]Context 44 } 45 46 func (mh *MockQueryHandler) QueryPullRequests(ctx context.Context, ghc githubClient, query string) ([]PullRequest, error) { 47 return mh.prs, nil 48 } 49 50 func (mh *MockQueryHandler) GetHeadContexts(ghc githubClient, pr PullRequest) ([]Context, error) { 51 return mh.contextMap[int(pr.Number)], nil 52 } 53 54 func (mh *MockQueryHandler) GetUser(*ghclient.Client) (*gogithub.User, error) { 55 login := "random_user" 56 return &gogithub.User{ 57 Login: &login, 58 }, nil 59 } 60 61 type fgc struct { 62 combinedStatus *github.CombinedStatus 63 } 64 65 func (c *fgc) Query(context.Context, interface{}, map[string]interface{}) error { 66 return nil 67 } 68 69 func (c *fgc) GetCombinedStatus(org, repo, ref string) (*github.CombinedStatus, error) { 70 return c.combinedStatus, nil 71 } 72 73 func newMockQueryHandler(prs []PullRequest, contextMap map[int][]Context) *MockQueryHandler { 74 return &MockQueryHandler{ 75 prs: prs, 76 contextMap: contextMap, 77 } 78 } 79 80 func createMockAgent(repos []string, config *config.GithubOAuthConfig) *DashboardAgent { 81 return &DashboardAgent{ 82 repos: repos, 83 goac: config, 84 log: logrus.WithField("unit-test", "dashboard-agent"), 85 } 86 } 87 88 func TestHandlePrStatusWithoutLogin(t *testing.T) { 89 repos := []string{"mock/repo", "kubernetes/test-infra", "foo/bar"} 90 mockCookieStore := sessions.NewCookieStore([]byte("secret-key")) 91 mockConfig := &config.GithubOAuthConfig{ 92 CookieStore: mockCookieStore, 93 } 94 mockAgent := createMockAgent(repos, mockConfig) 95 mockData := UserData{ 96 Login: false, 97 } 98 99 rr := httptest.NewRecorder() 100 request := httptest.NewRequest(http.MethodGet, "/pr-data.js", nil) 101 102 mockQueryHandler := newMockQueryHandler(nil, nil) 103 prHandler := mockAgent.HandlePrStatus(mockQueryHandler) 104 prHandler.ServeHTTP(rr, request) 105 if rr.Code != http.StatusOK { 106 t.Fatalf("Bad status code: %d", rr.Code) 107 } 108 response := rr.Result() 109 defer response.Body.Close() 110 body, err := ioutil.ReadAll(response.Body) 111 if err != nil { 112 t.Fatalf("Error with reading response body: %v", err) 113 } 114 var dataReturned UserData 115 if err := yaml.Unmarshal(body, &dataReturned); err != nil { 116 t.Errorf("Error with unmarshaling response: %v", err) 117 } 118 if !reflect.DeepEqual(dataReturned, mockData) { 119 t.Errorf("Invalid user data. Got %v, expected %v", dataReturned, mockData) 120 } 121 } 122 123 func TestHandlePrStatusWithInvalidToken(t *testing.T) { 124 logrus.SetLevel(logrus.ErrorLevel) 125 repos := []string{"mock/repo", "kubernetes/test-infra", "foo/bar"} 126 mockCookieStore := sessions.NewCookieStore([]byte("secret-key")) 127 mockConfig := &config.GithubOAuthConfig{ 128 CookieStore: mockCookieStore, 129 } 130 mockAgent := createMockAgent(repos, mockConfig) 131 mockQueryHandler := newMockQueryHandler([]PullRequest{}, map[int][]Context{}) 132 133 rr := httptest.NewRecorder() 134 request := httptest.NewRequest(http.MethodGet, "/pr-data.js", nil) 135 request.AddCookie(&http.Cookie{Name: tokenSession, Value: "garbage"}) 136 prHandler := mockAgent.HandlePrStatus(mockQueryHandler) 137 prHandler.ServeHTTP(rr, request) 138 if rr.Code != http.StatusOK { 139 t.Fatalf("Bad status code: %d", rr.Code) 140 } 141 response := rr.Result() 142 defer response.Body.Close() 143 144 body, err := ioutil.ReadAll(response.Body) 145 if err != nil { 146 t.Fatalf("Error with reading response body: %v", err) 147 } 148 149 var dataReturned UserData 150 if err := yaml.Unmarshal(body, &dataReturned); err != nil { 151 t.Errorf("Error with unmarshaling response: %v", err) 152 } 153 154 expectedData := UserData{Login: false} 155 if !reflect.DeepEqual(dataReturned, expectedData) { 156 t.Fatalf("Invalid user data. Got %v, expected %v.", dataReturned, expectedData) 157 } 158 } 159 160 func TestHandlePrStatusWithLogin(t *testing.T) { 161 repos := []string{"mock/repo", "kubernetes/test-infra", "foo/bar"} 162 mockCookieStore := sessions.NewCookieStore([]byte("secret-key")) 163 mockConfig := &config.GithubOAuthConfig{ 164 CookieStore: mockCookieStore, 165 } 166 mockAgent := createMockAgent(repos, mockConfig) 167 168 testCases := []struct { 169 prs []PullRequest 170 contextMap map[int][]Context 171 expectedData UserData 172 }{ 173 { 174 prs: []PullRequest{}, 175 contextMap: map[int][]Context{}, 176 expectedData: UserData{ 177 Login: true, 178 }, 179 }, 180 { 181 prs: []PullRequest{ 182 { 183 Number: 0, 184 Title: "random pull request", 185 }, 186 { 187 Number: 1, 188 Title: "This is a test", 189 }, 190 { 191 Number: 2, 192 Title: "test pull request", 193 }, 194 }, 195 contextMap: map[int][]Context{ 196 0: { 197 { 198 Context: "gofmt-job", 199 Description: "job succeed", 200 State: "SUCCESS", 201 }, 202 }, 203 1: { 204 { 205 Context: "verify-bazel-job", 206 Description: "job failed", 207 State: "FAILURE", 208 }, 209 }, 210 2: { 211 { 212 Context: "gofmt-job", 213 Description: "job succeed", 214 State: "SUCCESS", 215 }, 216 { 217 Context: "verify-bazel-job", 218 Description: "job failed", 219 State: "FAILURE", 220 }, 221 }, 222 }, 223 expectedData: UserData{ 224 Login: true, 225 PullRequestsWithContexts: []PullRequestWithContexts{ 226 { 227 PullRequest: PullRequest{ 228 Number: 0, 229 Title: "random pull request", 230 }, 231 Contexts: []Context{ 232 { 233 Context: "gofmt-job", 234 Description: "job succeed", 235 State: "SUCCESS", 236 }, 237 }, 238 }, 239 { 240 PullRequest: PullRequest{ 241 Number: 1, 242 Title: "This is a test", 243 }, 244 Contexts: []Context{ 245 { 246 Context: "verify-bazel-job", 247 Description: "job failed", 248 State: "FAILURE", 249 }, 250 }, 251 }, 252 { 253 PullRequest: PullRequest{ 254 Number: 2, 255 Title: "test pull request", 256 }, 257 Contexts: []Context{ 258 { 259 Context: "gofmt-job", 260 Description: "job succeed", 261 State: "SUCCESS", 262 }, 263 { 264 Context: "verify-bazel-job", 265 Description: "job failed", 266 State: "FAILURE", 267 }, 268 }, 269 }, 270 }, 271 }, 272 }, 273 } 274 for id, testcase := range testCases { 275 t.Logf("Test %d:", id) 276 rr := httptest.NewRecorder() 277 request := httptest.NewRequest(http.MethodGet, "/pr-data.js", nil) 278 mockSession, err := sessions.GetRegistry(request).Get(mockCookieStore, tokenSession) 279 if err != nil { 280 t.Errorf("Error with creating mock session: %v", err) 281 } 282 gob.Register(oauth2.Token{}) 283 token := &oauth2.Token{AccessToken: "secret-token", Expiry: time.Now().Add(time.Duration(24*365) * time.Hour)} 284 mockSession.Values[tokenKey] = token 285 mockSession.Values[loginKey] = "random_user" 286 mockQueryHandler := newMockQueryHandler(testcase.prs, testcase.contextMap) 287 prHandler := mockAgent.HandlePrStatus(mockQueryHandler) 288 prHandler.ServeHTTP(rr, request) 289 if rr.Code != http.StatusOK { 290 t.Fatalf("Bad status code: %d", rr.Code) 291 } 292 response := rr.Result() 293 body, err := ioutil.ReadAll(response.Body) 294 if err != nil { 295 t.Fatalf("Error with reading response body: %v", err) 296 } 297 var dataReturned UserData 298 if err := yaml.Unmarshal(body, &dataReturned); err != nil { 299 t.Errorf("Error with unmarshaling response: %v", err) 300 } 301 if !reflect.DeepEqual(dataReturned, testcase.expectedData) { 302 t.Fatalf("Invalid user data. Got %v, expected %v.", dataReturned, testcase.expectedData) 303 } 304 t.Logf("Passed") 305 response.Body.Close() 306 } 307 } 308 309 func TestGetHeadContexts(t *testing.T) { 310 repos := []string{"mock/repo", "kubernetes/test-infra", "foo/bar"} 311 mockCookieStore := sessions.NewCookieStore([]byte("secret-key")) 312 mockConfig := &config.GithubOAuthConfig{ 313 CookieStore: mockCookieStore, 314 } 315 mockAgent := createMockAgent(repos, mockConfig) 316 testCases := []struct { 317 combinedStatus *github.CombinedStatus 318 pr PullRequest 319 expectedContexts []Context 320 }{ 321 { 322 combinedStatus: &github.CombinedStatus{}, 323 pr: PullRequest{}, 324 expectedContexts: []Context{}, 325 }, 326 { 327 combinedStatus: &github.CombinedStatus{ 328 Statuses: []github.Status{ 329 { 330 State: "FAILURE", 331 Description: "job failed", 332 Context: "gofmt-job", 333 }, 334 { 335 State: "SUCCESS", 336 Description: "job succeed", 337 Context: "k8s-job", 338 }, 339 { 340 State: "PENDING", 341 Description: "triggered", 342 Context: "test-job", 343 }, 344 }, 345 }, 346 pr: PullRequest{}, 347 expectedContexts: []Context{ 348 { 349 Context: "gofmt-job", 350 Description: "job failed", 351 State: "FAILURE", 352 }, 353 { 354 State: "SUCCESS", 355 Description: "job succeed", 356 Context: "k8s-job", 357 }, 358 { 359 State: "PENDING", 360 Description: "triggered", 361 Context: "test-job", 362 }, 363 }, 364 }, 365 } 366 for id, testcase := range testCases { 367 t.Logf("Test %d:", id) 368 contexts, err := mockAgent.GetHeadContexts(&fgc{ 369 combinedStatus: testcase.combinedStatus, 370 }, testcase.pr) 371 if err != nil { 372 t.Fatalf("Error with getting head contexts") 373 } 374 if !reflect.DeepEqual(contexts, testcase.expectedContexts) { 375 t.Fatalf("Invalid user data. Got %v, expected %v.", contexts, testcase.expectedContexts) 376 } 377 t.Logf("Passed") 378 } 379 } 380 381 func TestConstructSearchQuery(t *testing.T) { 382 repos := []string{"mock/repo", "kubernetes/test-infra", "foo/bar"} 383 mockCookieStore := sessions.NewCookieStore([]byte("secret-key")) 384 mockConfig := &config.GithubOAuthConfig{ 385 CookieStore: mockCookieStore, 386 } 387 mockAgent := createMockAgent(repos, mockConfig) 388 query := mockAgent.ConstructSearchQuery("random_username") 389 mockQuery := "is:pr state:open author:random_username repo:\"mock/repo\" repo:\"kubernetes/test-infra\" repo:\"foo/bar\"" 390 if query != mockQuery { 391 t.Errorf("Invalid query. Got: %v, expected %v", query, mockQuery) 392 } 393 }