loading up the forgejo repo on tangled to test page performance
at forgejo 622 lines 24 kB view raw
1// Copyright 2017 The Gitea Authors. All rights reserved. 2// SPDX-License-Identifier: MIT 3 4package integration 5 6import ( 7 "fmt" 8 "net/http" 9 "net/url" 10 "strconv" 11 "sync" 12 "testing" 13 "time" 14 15 auth_model "forgejo.org/models/auth" 16 "forgejo.org/models/db" 17 issues_model "forgejo.org/models/issues" 18 repo_model "forgejo.org/models/repo" 19 "forgejo.org/models/unittest" 20 user_model "forgejo.org/models/user" 21 "forgejo.org/modules/setting" 22 api "forgejo.org/modules/structs" 23 "forgejo.org/tests" 24 25 "github.com/stretchr/testify/assert" 26 "github.com/stretchr/testify/require" 27) 28 29func TestAPIListIssues(t *testing.T) { 30 defer tests.PrepareTestEnv(t)() 31 32 repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) 33 owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) 34 35 session := loginUser(t, owner.Name) 36 token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadIssue) 37 link, _ := url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/issues", owner.Name, repo.Name)) 38 39 link.RawQuery = url.Values{"token": {token}, "state": {"all"}}.Encode() 40 resp := MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK) 41 var apiIssues []*api.Issue 42 DecodeJSON(t, resp, &apiIssues) 43 assert.Len(t, apiIssues, unittest.GetCount(t, &issues_model.Issue{RepoID: repo.ID})) 44 for _, apiIssue := range apiIssues { 45 unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: apiIssue.ID, RepoID: repo.ID}) 46 } 47 48 // test milestone filter 49 link.RawQuery = url.Values{"token": {token}, "state": {"all"}, "type": {"all"}, "milestones": {"ignore,milestone1,3,4"}}.Encode() 50 resp = MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK) 51 DecodeJSON(t, resp, &apiIssues) 52 if assert.Len(t, apiIssues, 2) { 53 assert.EqualValues(t, 3, apiIssues[0].Milestone.ID) 54 assert.EqualValues(t, 1, apiIssues[1].Milestone.ID) 55 } 56 57 link.RawQuery = url.Values{"token": {token}, "state": {"all"}, "created_by": {"user2"}}.Encode() 58 resp = MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK) 59 DecodeJSON(t, resp, &apiIssues) 60 if assert.Len(t, apiIssues, 1) { 61 assert.EqualValues(t, 5, apiIssues[0].ID) 62 } 63 64 link.RawQuery = url.Values{"token": {token}, "state": {"all"}, "assigned_by": {"user1"}}.Encode() 65 resp = MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK) 66 DecodeJSON(t, resp, &apiIssues) 67 if assert.Len(t, apiIssues, 1) { 68 assert.EqualValues(t, 1, apiIssues[0].ID) 69 } 70 71 link.RawQuery = url.Values{"token": {token}, "state": {"all"}, "mentioned_by": {"user4"}}.Encode() 72 resp = MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK) 73 DecodeJSON(t, resp, &apiIssues) 74 if assert.Len(t, apiIssues, 1) { 75 assert.EqualValues(t, 1, apiIssues[0].ID) 76 } 77 78 t.Run("Sort", func(t *testing.T) { 79 defer tests.PrintCurrentTest(t)() 80 81 link.RawQuery = url.Values{"token": {token}, "sort": {"oldest"}}.Encode() 82 resp = MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK) 83 DecodeJSON(t, resp, &apiIssues) 84 if assert.Len(t, apiIssues, 4) { 85 assert.EqualValues(t, 1, apiIssues[0].ID) 86 assert.EqualValues(t, 2, apiIssues[1].ID) 87 assert.EqualValues(t, 3, apiIssues[2].ID) 88 assert.EqualValues(t, 11, apiIssues[3].ID) 89 } 90 91 link.RawQuery = url.Values{"token": {token}, "sort": {"newest"}}.Encode() 92 resp = MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK) 93 DecodeJSON(t, resp, &apiIssues) 94 if assert.Len(t, apiIssues, 4) { 95 assert.EqualValues(t, 11, apiIssues[0].ID) 96 assert.EqualValues(t, 3, apiIssues[1].ID) 97 assert.EqualValues(t, 2, apiIssues[2].ID) 98 assert.EqualValues(t, 1, apiIssues[3].ID) 99 } 100 101 link.RawQuery = url.Values{"token": {token}, "sort": {"recentupdate"}}.Encode() 102 resp = MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK) 103 DecodeJSON(t, resp, &apiIssues) 104 if assert.Len(t, apiIssues, 4) { 105 assert.EqualValues(t, 11, apiIssues[0].ID) 106 assert.EqualValues(t, 1, apiIssues[1].ID) 107 assert.EqualValues(t, 2, apiIssues[2].ID) 108 assert.EqualValues(t, 3, apiIssues[3].ID) 109 } 110 111 link.RawQuery = url.Values{"token": {token}, "sort": {"leastupdate"}}.Encode() 112 resp = MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK) 113 DecodeJSON(t, resp, &apiIssues) 114 if assert.Len(t, apiIssues, 4) { 115 assert.EqualValues(t, 3, apiIssues[0].ID) 116 assert.EqualValues(t, 2, apiIssues[1].ID) 117 assert.EqualValues(t, 1, apiIssues[2].ID) 118 assert.EqualValues(t, 11, apiIssues[3].ID) 119 } 120 }) 121} 122 123func TestAPIListIssuesPublicOnly(t *testing.T) { 124 defer tests.PrepareTestEnv(t)() 125 126 repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) 127 owner1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo1.OwnerID}) 128 129 session := loginUser(t, owner1.Name) 130 token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadIssue) 131 link, _ := url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/issues", owner1.Name, repo1.Name)) 132 link.RawQuery = url.Values{"state": {"all"}}.Encode() 133 req := NewRequest(t, "GET", link.String()).AddTokenAuth(token) 134 MakeRequest(t, req, http.StatusOK) 135 136 repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) 137 owner2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo2.OwnerID}) 138 139 session = loginUser(t, owner2.Name) 140 token = getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadIssue) 141 link, _ = url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/issues", owner2.Name, repo2.Name)) 142 link.RawQuery = url.Values{"state": {"all"}}.Encode() 143 req = NewRequest(t, "GET", link.String()).AddTokenAuth(token) 144 MakeRequest(t, req, http.StatusOK) 145 146 publicOnlyToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadIssue, auth_model.AccessTokenScopePublicOnly) 147 req = NewRequest(t, "GET", link.String()).AddTokenAuth(publicOnlyToken) 148 MakeRequest(t, req, http.StatusForbidden) 149} 150 151func TestAPICreateIssue(t *testing.T) { 152 defer tests.PrepareTestEnv(t)() 153 const body, title = "apiTestBody", "apiTestTitle" 154 155 repoBefore := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) 156 owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repoBefore.OwnerID}) 157 158 session := loginUser(t, owner.Name) 159 token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteIssue) 160 urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues?state=all", owner.Name, repoBefore.Name) 161 req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateIssueOption{ 162 Body: body, 163 Title: title, 164 Assignee: owner.Name, 165 }).AddTokenAuth(token) 166 resp := MakeRequest(t, req, http.StatusCreated) 167 var apiIssue api.Issue 168 DecodeJSON(t, resp, &apiIssue) 169 assert.Equal(t, body, apiIssue.Body) 170 assert.Equal(t, title, apiIssue.Title) 171 172 unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ 173 RepoID: repoBefore.ID, 174 AssigneeID: owner.ID, 175 Content: body, 176 Title: title, 177 }) 178 179 repoAfter := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) 180 assert.Equal(t, repoBefore.NumIssues+1, repoAfter.NumIssues) 181 assert.Equal(t, repoBefore.NumClosedIssues, repoAfter.NumClosedIssues) 182} 183 184func TestAPICreateIssueParallel(t *testing.T) { 185 defer tests.PrepareTestEnv(t)() 186 const body, title = "apiTestBody", "apiTestTitle" 187 188 repoBefore := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) 189 owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repoBefore.OwnerID}) 190 191 session := loginUser(t, owner.Name) 192 token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteIssue) 193 urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues?state=all", owner.Name, repoBefore.Name) 194 195 var wg sync.WaitGroup 196 for i := 0; i < 10; i++ { 197 wg.Add(1) 198 go func(parentT *testing.T, i int) { 199 parentT.Run(fmt.Sprintf("ParallelCreateIssue_%d", i), func(t *testing.T) { 200 newTitle := title + strconv.Itoa(i) 201 newBody := body + strconv.Itoa(i) 202 req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateIssueOption{ 203 Body: newBody, 204 Title: newTitle, 205 Assignee: owner.Name, 206 }).AddTokenAuth(token) 207 resp := MakeRequest(t, req, http.StatusCreated) 208 var apiIssue api.Issue 209 DecodeJSON(t, resp, &apiIssue) 210 assert.Equal(t, newBody, apiIssue.Body) 211 assert.Equal(t, newTitle, apiIssue.Title) 212 213 unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ 214 RepoID: repoBefore.ID, 215 AssigneeID: owner.ID, 216 Content: newBody, 217 Title: newTitle, 218 }) 219 220 wg.Done() 221 }) 222 }(t, i) 223 } 224 wg.Wait() 225} 226 227func TestAPIEditIssue(t *testing.T) { 228 defer tests.PrepareTestEnv(t)() 229 230 issueBefore := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 10}) 231 repoBefore := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issueBefore.RepoID}) 232 owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repoBefore.OwnerID}) 233 require.NoError(t, issueBefore.LoadAttributes(db.DefaultContext)) 234 assert.Equal(t, int64(1019307200), int64(issueBefore.DeadlineUnix)) 235 assert.Equal(t, api.StateOpen, issueBefore.State()) 236 237 session := loginUser(t, owner.Name) 238 token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteIssue) 239 240 // update values of issue 241 issueState := "closed" 242 removeDeadline := true 243 milestone := int64(4) 244 body := "new content!" 245 title := "new title from api set" 246 247 urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d", owner.Name, repoBefore.Name, issueBefore.Index) 248 req := NewRequestWithJSON(t, "PATCH", urlStr, api.EditIssueOption{ 249 State: &issueState, 250 RemoveDeadline: &removeDeadline, 251 Milestone: &milestone, 252 Body: &body, 253 Title: title, 254 255 // ToDo change more 256 }).AddTokenAuth(token) 257 resp := MakeRequest(t, req, http.StatusCreated) 258 var apiIssue api.Issue 259 DecodeJSON(t, resp, &apiIssue) 260 261 issueAfter := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 10}) 262 repoAfter := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issueBefore.RepoID}) 263 264 // check comment history 265 unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: issueAfter.ID, OldTitle: issueBefore.Title, NewTitle: title}) 266 unittest.AssertExistsAndLoadBean(t, &issues_model.ContentHistory{IssueID: issueAfter.ID, ContentText: body, IsFirstCreated: false}) 267 268 // check deleted user 269 assert.Equal(t, int64(500), issueAfter.PosterID) 270 require.NoError(t, issueAfter.LoadAttributes(db.DefaultContext)) 271 assert.Equal(t, int64(-1), issueAfter.PosterID) 272 assert.Equal(t, int64(-1), issueBefore.PosterID) 273 assert.Equal(t, int64(-1), apiIssue.Poster.ID) 274 275 // check repo change 276 assert.Equal(t, repoBefore.NumClosedIssues+1, repoAfter.NumClosedIssues) 277 278 // API response 279 assert.Equal(t, api.StateClosed, apiIssue.State) 280 assert.Equal(t, milestone, apiIssue.Milestone.ID) 281 assert.Equal(t, body, apiIssue.Body) 282 assert.Nil(t, apiIssue.Deadline) 283 assert.Equal(t, title, apiIssue.Title) 284 285 // in database 286 assert.Equal(t, api.StateClosed, issueAfter.State()) 287 assert.Equal(t, milestone, issueAfter.MilestoneID) 288 assert.Equal(t, int64(0), int64(issueAfter.DeadlineUnix)) 289 assert.Equal(t, body, issueAfter.Content) 290 assert.Equal(t, title, issueAfter.Title) 291 292 // verify the idempotency of state, milestone, body and title changes 293 req = NewRequestWithJSON(t, "PATCH", urlStr, api.EditIssueOption{ 294 State: &issueState, 295 Milestone: &milestone, 296 Body: &body, 297 Title: title, 298 }).AddTokenAuth(token) 299 resp = MakeRequest(t, req, http.StatusCreated) 300 var apiIssueIdempotent api.Issue 301 DecodeJSON(t, resp, &apiIssueIdempotent) 302 assert.Equal(t, apiIssue.State, apiIssueIdempotent.State) 303 assert.Equal(t, apiIssue.Milestone.Title, apiIssueIdempotent.Milestone.Title) 304 assert.Equal(t, apiIssue.Body, apiIssueIdempotent.Body) 305 assert.Equal(t, apiIssue.Title, apiIssueIdempotent.Title) 306} 307 308func TestAPIEditIssueAutoDate(t *testing.T) { 309 defer tests.PrepareTestEnv(t)() 310 311 issueBefore := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 13}) 312 repoBefore := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issueBefore.RepoID}) 313 owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repoBefore.OwnerID}) 314 require.NoError(t, issueBefore.LoadAttributes(db.DefaultContext)) 315 316 t.Run("WithAutoDate", func(t *testing.T) { 317 defer tests.PrintCurrentTest(t)() 318 319 // User2 is not owner, but can update the 'public' issue with auto date 320 session := loginUser(t, "user2") 321 token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteIssue) 322 urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d", owner.Name, repoBefore.Name, issueBefore.Index) 323 324 body := "new content!" 325 req := NewRequestWithJSON(t, "PATCH", urlStr, api.EditIssueOption{ 326 Body: &body, 327 }).AddTokenAuth(token) 328 resp := MakeRequest(t, req, http.StatusCreated) 329 var apiIssue api.Issue 330 DecodeJSON(t, resp, &apiIssue) 331 332 // the execution of the API call supposedly lasted less than one minute 333 updatedSince := time.Since(apiIssue.Updated) 334 assert.LessOrEqual(t, updatedSince, time.Minute) 335 336 issueAfter := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: issueBefore.ID}) 337 updatedSince = time.Since(issueAfter.UpdatedUnix.AsTime()) 338 assert.LessOrEqual(t, updatedSince, time.Minute) 339 }) 340 341 t.Run("WithUpdateDate", func(t *testing.T) { 342 defer tests.PrintCurrentTest(t)() 343 344 // User1 is admin, and so can update the issue without auto date 345 session := loginUser(t, "user1") 346 token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteIssue) 347 urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d", owner.Name, repoBefore.Name, issueBefore.Index) 348 349 body := "new content, with updated time" 350 updatedAt := time.Now().Add(-time.Hour).Truncate(time.Second) 351 req := NewRequestWithJSON(t, "PATCH", urlStr, api.EditIssueOption{ 352 Body: &body, 353 Updated: &updatedAt, 354 }).AddTokenAuth(token) 355 resp := MakeRequest(t, req, http.StatusCreated) 356 var apiIssue api.Issue 357 DecodeJSON(t, resp, &apiIssue) 358 359 // dates are converted into the same tz, in order to compare them 360 utcTZ, _ := time.LoadLocation("UTC") 361 assert.Equal(t, updatedAt.In(utcTZ), apiIssue.Updated.In(utcTZ)) 362 363 issueAfter := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: issueBefore.ID}) 364 assert.Equal(t, updatedAt.In(utcTZ), issueAfter.UpdatedUnix.AsTime().In(utcTZ)) 365 }) 366 367 t.Run("WithoutPermission", func(t *testing.T) { 368 defer tests.PrintCurrentTest(t)() 369 370 // User2 is not owner nor admin, and so can't update the issue without auto date 371 session := loginUser(t, "user2") 372 token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteIssue) 373 urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d", owner.Name, repoBefore.Name, issueBefore.Index) 374 375 body := "new content, with updated time" 376 updatedAt := time.Now().Add(-time.Hour).Truncate(time.Second) 377 req := NewRequestWithJSON(t, "PATCH", urlStr, api.EditIssueOption{ 378 Body: &body, 379 Updated: &updatedAt, 380 }).AddTokenAuth(token) 381 resp := MakeRequest(t, req, http.StatusForbidden) 382 var apiError api.APIError 383 DecodeJSON(t, resp, &apiError) 384 385 assert.Equal(t, "user needs to have admin or owner right", apiError.Message) 386 }) 387} 388 389func TestAPIEditIssueMilestoneAutoDate(t *testing.T) { 390 defer tests.PrepareTestEnv(t)() 391 392 issueBefore := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}) 393 repoBefore := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issueBefore.RepoID}) 394 395 owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repoBefore.OwnerID}) 396 require.NoError(t, issueBefore.LoadAttributes(db.DefaultContext)) 397 398 session := loginUser(t, owner.Name) 399 token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteIssue) 400 urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d", owner.Name, repoBefore.Name, issueBefore.Index) 401 402 t.Run("WithAutoDate", func(t *testing.T) { 403 defer tests.PrintCurrentTest(t)() 404 405 milestone := int64(1) 406 req := NewRequestWithJSON(t, "PATCH", urlStr, api.EditIssueOption{ 407 Milestone: &milestone, 408 }).AddTokenAuth(token) 409 MakeRequest(t, req, http.StatusCreated) 410 411 // the execution of the API call supposedly lasted less than one minute 412 milestoneAfter := unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: milestone}) 413 updatedSince := time.Since(milestoneAfter.UpdatedUnix.AsTime()) 414 assert.LessOrEqual(t, updatedSince, time.Minute) 415 }) 416 417 t.Run("WithPostUpdateDate", func(t *testing.T) { 418 defer tests.PrintCurrentTest(t)() 419 420 // Note: the updated_unix field of the test Milestones is set to NULL 421 // Hence, any date is higher than the Milestone's updated date 422 updatedAt := time.Now().Add(-time.Hour).Truncate(time.Second) 423 milestone := int64(2) 424 req := NewRequestWithJSON(t, "PATCH", urlStr, api.EditIssueOption{ 425 Milestone: &milestone, 426 Updated: &updatedAt, 427 }).AddTokenAuth(token) 428 MakeRequest(t, req, http.StatusCreated) 429 430 // the milestone date should be set to 'updatedAt' 431 // dates are converted into the same tz, in order to compare them 432 utcTZ, _ := time.LoadLocation("UTC") 433 milestoneAfter := unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: milestone}) 434 assert.Equal(t, updatedAt.In(utcTZ), milestoneAfter.UpdatedUnix.AsTime().In(utcTZ)) 435 }) 436 437 t.Run("WithPastUpdateDate", func(t *testing.T) { 438 defer tests.PrintCurrentTest(t)() 439 440 // Note: This Milestone's updated_unix has been set to Now() by the first subtest 441 milestone := int64(1) 442 milestoneBefore := unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: milestone}) 443 444 updatedAt := time.Now().Add(-time.Hour).Truncate(time.Second) 445 req := NewRequestWithJSON(t, "PATCH", urlStr, api.EditIssueOption{ 446 Milestone: &milestone, 447 Updated: &updatedAt, 448 }).AddTokenAuth(token) 449 MakeRequest(t, req, http.StatusCreated) 450 451 // the milestone date should not change 452 // dates are converted into the same tz, in order to compare them 453 utcTZ, _ := time.LoadLocation("UTC") 454 milestoneAfter := unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: milestone}) 455 assert.Equal(t, milestoneAfter.UpdatedUnix.AsTime().In(utcTZ), milestoneBefore.UpdatedUnix.AsTime().In(utcTZ)) 456 }) 457} 458 459func TestAPISearchIssues(t *testing.T) { 460 defer tests.PrepareTestEnv(t)() 461 462 // as this API was used in the frontend, it uses UI page size 463 expectedIssueCount := 20 // from the fixtures 464 if expectedIssueCount > setting.UI.IssuePagingNum { 465 expectedIssueCount = setting.UI.IssuePagingNum 466 } 467 468 link, _ := url.Parse("/api/v1/repos/issues/search") 469 token := getUserToken(t, "user1", auth_model.AccessTokenScopeReadIssue) 470 query := url.Values{} 471 var apiIssues []*api.Issue 472 473 link.RawQuery = query.Encode() 474 req := NewRequest(t, "GET", link.String()).AddTokenAuth(token) 475 resp := MakeRequest(t, req, http.StatusOK) 476 DecodeJSON(t, resp, &apiIssues) 477 assert.Len(t, apiIssues, expectedIssueCount) 478 479 publicOnlyToken := getUserToken(t, "user1", auth_model.AccessTokenScopeReadIssue, auth_model.AccessTokenScopePublicOnly) 480 req = NewRequest(t, "GET", link.String()).AddTokenAuth(publicOnlyToken) 481 resp = MakeRequest(t, req, http.StatusOK) 482 DecodeJSON(t, resp, &apiIssues) 483 assert.Len(t, apiIssues, 15) // 15 public issues 484 485 since := "2000-01-01T00:50:01+00:00" // 946687801 486 before := time.Unix(999307200, 0).Format(time.RFC3339) 487 query.Add("since", since) 488 query.Add("before", before) 489 link.RawQuery = query.Encode() 490 req = NewRequest(t, "GET", link.String()).AddTokenAuth(token) 491 resp = MakeRequest(t, req, http.StatusOK) 492 DecodeJSON(t, resp, &apiIssues) 493 assert.Len(t, apiIssues, 11) 494 query.Del("since") 495 query.Del("before") 496 497 query.Add("state", "closed") 498 link.RawQuery = query.Encode() 499 req = NewRequest(t, "GET", link.String()).AddTokenAuth(token) 500 resp = MakeRequest(t, req, http.StatusOK) 501 DecodeJSON(t, resp, &apiIssues) 502 assert.Len(t, apiIssues, 2) 503 504 query.Set("state", "all") 505 link.RawQuery = query.Encode() 506 req = NewRequest(t, "GET", link.String()).AddTokenAuth(token) 507 resp = MakeRequest(t, req, http.StatusOK) 508 DecodeJSON(t, resp, &apiIssues) 509 assert.Equal(t, "22", resp.Header().Get("X-Total-Count")) 510 assert.Len(t, apiIssues, 20) 511 512 query.Add("limit", "10") 513 link.RawQuery = query.Encode() 514 req = NewRequest(t, "GET", link.String()).AddTokenAuth(token) 515 resp = MakeRequest(t, req, http.StatusOK) 516 DecodeJSON(t, resp, &apiIssues) 517 assert.Equal(t, "22", resp.Header().Get("X-Total-Count")) 518 assert.Len(t, apiIssues, 10) 519 520 query = url.Values{"assigned": {"true"}, "state": {"all"}} 521 link.RawQuery = query.Encode() 522 req = NewRequest(t, "GET", link.String()).AddTokenAuth(token) 523 resp = MakeRequest(t, req, http.StatusOK) 524 DecodeJSON(t, resp, &apiIssues) 525 assert.Len(t, apiIssues, 2) 526 527 query = url.Values{"milestones": {"milestone1"}, "state": {"all"}} 528 link.RawQuery = query.Encode() 529 req = NewRequest(t, "GET", link.String()).AddTokenAuth(token) 530 resp = MakeRequest(t, req, http.StatusOK) 531 DecodeJSON(t, resp, &apiIssues) 532 assert.Len(t, apiIssues, 1) 533 534 query = url.Values{"milestones": {"milestone1,milestone3"}, "state": {"all"}} 535 link.RawQuery = query.Encode() 536 req = NewRequest(t, "GET", link.String()).AddTokenAuth(token) 537 resp = MakeRequest(t, req, http.StatusOK) 538 DecodeJSON(t, resp, &apiIssues) 539 assert.Len(t, apiIssues, 2) 540 541 query = url.Values{"owner": {"user2"}} // user 542 link.RawQuery = query.Encode() 543 req = NewRequest(t, "GET", link.String()).AddTokenAuth(token) 544 resp = MakeRequest(t, req, http.StatusOK) 545 DecodeJSON(t, resp, &apiIssues) 546 assert.Len(t, apiIssues, 8) 547 548 query = url.Values{"owner": {"org3"}} // organization 549 link.RawQuery = query.Encode() 550 req = NewRequest(t, "GET", link.String()).AddTokenAuth(token) 551 resp = MakeRequest(t, req, http.StatusOK) 552 DecodeJSON(t, resp, &apiIssues) 553 assert.Len(t, apiIssues, 5) 554 555 query = url.Values{"owner": {"org3"}, "team": {"team1"}} // organization + team 556 link.RawQuery = query.Encode() 557 req = NewRequest(t, "GET", link.String()).AddTokenAuth(token) 558 resp = MakeRequest(t, req, http.StatusOK) 559 DecodeJSON(t, resp, &apiIssues) 560 assert.Len(t, apiIssues, 2) 561} 562 563func TestAPISearchIssuesWithLabels(t *testing.T) { 564 defer tests.PrepareTestEnv(t)() 565 566 // as this API was used in the frontend, it uses UI page size 567 expectedIssueCount := 20 // from the fixtures 568 if expectedIssueCount > setting.UI.IssuePagingNum { 569 expectedIssueCount = setting.UI.IssuePagingNum 570 } 571 572 link, _ := url.Parse("/api/v1/repos/issues/search") 573 token := getUserToken(t, "user1", auth_model.AccessTokenScopeReadIssue) 574 query := url.Values{} 575 var apiIssues []*api.Issue 576 577 link.RawQuery = query.Encode() 578 req := NewRequest(t, "GET", link.String()).AddTokenAuth(token) 579 resp := MakeRequest(t, req, http.StatusOK) 580 DecodeJSON(t, resp, &apiIssues) 581 assert.Len(t, apiIssues, expectedIssueCount) 582 583 query.Add("labels", "label1") 584 link.RawQuery = query.Encode() 585 req = NewRequest(t, "GET", link.String()).AddTokenAuth(token) 586 resp = MakeRequest(t, req, http.StatusOK) 587 DecodeJSON(t, resp, &apiIssues) 588 assert.Len(t, apiIssues, 2) 589 590 // multiple labels 591 query.Set("labels", "label1,label2") 592 link.RawQuery = query.Encode() 593 req = NewRequest(t, "GET", link.String()).AddTokenAuth(token) 594 resp = MakeRequest(t, req, http.StatusOK) 595 DecodeJSON(t, resp, &apiIssues) 596 assert.Len(t, apiIssues, 2) 597 598 // an org label 599 query.Set("labels", "orglabel4") 600 link.RawQuery = query.Encode() 601 req = NewRequest(t, "GET", link.String()).AddTokenAuth(token) 602 resp = MakeRequest(t, req, http.StatusOK) 603 DecodeJSON(t, resp, &apiIssues) 604 assert.Len(t, apiIssues, 1) 605 606 // org and repo label 607 query.Set("labels", "label2,orglabel4") 608 query.Add("state", "all") 609 link.RawQuery = query.Encode() 610 req = NewRequest(t, "GET", link.String()).AddTokenAuth(token) 611 resp = MakeRequest(t, req, http.StatusOK) 612 DecodeJSON(t, resp, &apiIssues) 613 assert.Len(t, apiIssues, 2) 614 615 // org and repo label which share the same issue 616 query.Set("labels", "label1,orglabel4") 617 link.RawQuery = query.Encode() 618 req = NewRequest(t, "GET", link.String()).AddTokenAuth(token) 619 resp = MakeRequest(t, req, http.StatusOK) 620 DecodeJSON(t, resp, &apiIssues) 621 assert.Len(t, apiIssues, 2) 622}