gitea源码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. // Copyright 2017 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package integration
  4. import (
  5. "fmt"
  6. "net/http"
  7. "net/http/httptest"
  8. "path"
  9. "sync"
  10. "testing"
  11. auth_model "code.gitea.io/gitea/models/auth"
  12. "code.gitea.io/gitea/modules/commitstatus"
  13. "code.gitea.io/gitea/modules/json"
  14. "code.gitea.io/gitea/modules/setting"
  15. api "code.gitea.io/gitea/modules/structs"
  16. "code.gitea.io/gitea/tests"
  17. "github.com/PuerkitoBio/goquery"
  18. "github.com/stretchr/testify/assert"
  19. )
  20. func TestRepoCommits(t *testing.T) {
  21. defer tests.PrepareTestEnv(t)()
  22. session := loginUser(t, "user2")
  23. t.Run("CommitList", func(t *testing.T) {
  24. req := NewRequest(t, "GET", "/user2/repo16/commits/branch/master")
  25. resp := session.MakeRequest(t, req, http.StatusOK)
  26. var commits, userHrefs []string
  27. doc := NewHTMLParser(t, resp.Body)
  28. doc.doc.Find("#commits-table .commit-id-short").Each(func(i int, s *goquery.Selection) {
  29. commits = append(commits, path.Base(s.AttrOr("href", "")))
  30. })
  31. doc.doc.Find("#commits-table .author-wrapper").Each(func(i int, s *goquery.Selection) {
  32. userHrefs = append(userHrefs, s.AttrOr("href", ""))
  33. })
  34. assert.Equal(t, []string{"69554a64c1e6030f051e5c3f94bfbd773cd6a324", "27566bd5738fc8b4e3fef3c5e72cce608537bd95", "5099b81332712fe655e34e8dd63574f503f61811"}, commits)
  35. assert.Equal(t, []string{"/user2", "/user21", "/user2"}, userHrefs)
  36. })
  37. t.Run("LastCommit", func(t *testing.T) {
  38. req := NewRequest(t, "GET", "/user2/repo16")
  39. resp := session.MakeRequest(t, req, http.StatusOK)
  40. doc := NewHTMLParser(t, resp.Body)
  41. commitHref := doc.doc.Find(".latest-commit .commit-id-short").AttrOr("href", "")
  42. authorHref := doc.doc.Find(".latest-commit .author-wrapper").AttrOr("href", "")
  43. assert.Equal(t, "/user2/repo16/commit/69554a64c1e6030f051e5c3f94bfbd773cd6a324", commitHref)
  44. assert.Equal(t, "/user2", authorHref)
  45. })
  46. t.Run("CommitListNonExistingCommiter", func(t *testing.T) {
  47. // check the commit list for a repository with no gitea user
  48. // * commit 985f0301dba5e7b34be866819cd15ad3d8f508ee (branch2)
  49. // * Author: 6543 <6543@obermui.de>
  50. req := NewRequest(t, "GET", "/user2/repo1/commits/branch/branch2")
  51. resp := session.MakeRequest(t, req, http.StatusOK)
  52. doc := NewHTMLParser(t, resp.Body)
  53. commitHref := doc.doc.Find("#commits-table tr:first-child .commit-id-short").AttrOr("href", "")
  54. assert.Equal(t, "/user2/repo1/commit/985f0301dba5e7b34be866819cd15ad3d8f508ee", commitHref)
  55. authorElem := doc.doc.Find("#commits-table tr:first-child .author-wrapper")
  56. assert.Equal(t, "6543", authorElem.Text())
  57. assert.Equal(t, "span", authorElem.Nodes[0].Data)
  58. })
  59. t.Run("LastCommitNonExistingCommiter", func(t *testing.T) {
  60. req := NewRequest(t, "GET", "/user2/repo1/src/branch/branch2")
  61. resp := session.MakeRequest(t, req, http.StatusOK)
  62. doc := NewHTMLParser(t, resp.Body)
  63. commitHref := doc.doc.Find(".latest-commit .commit-id-short").AttrOr("href", "")
  64. assert.Equal(t, "/user2/repo1/commit/985f0301dba5e7b34be866819cd15ad3d8f508ee", commitHref)
  65. authorElem := doc.doc.Find(".latest-commit .author-wrapper")
  66. assert.Equal(t, "6543", authorElem.Text())
  67. assert.Equal(t, "span", authorElem.Nodes[0].Data)
  68. })
  69. }
  70. func doTestRepoCommitWithStatus(t *testing.T, state string, classes ...string) {
  71. defer tests.PrepareTestEnv(t)()
  72. session := loginUser(t, "user2")
  73. // Request repository commits page
  74. req := NewRequest(t, "GET", "/user2/repo1/commits/branch/master")
  75. resp := session.MakeRequest(t, req, http.StatusOK)
  76. doc := NewHTMLParser(t, resp.Body)
  77. // Get first commit URL
  78. commitURL, exists := doc.doc.Find("#commits-table .commit-id-short").Attr("href")
  79. assert.True(t, exists)
  80. assert.NotEmpty(t, commitURL)
  81. // Call API to add status for commit
  82. ctx := NewAPITestContext(t, "user2", "repo1", auth_model.AccessTokenScopeWriteRepository)
  83. t.Run("CreateStatus", doAPICreateCommitStatus(ctx, path.Base(commitURL), api.CreateStatusOption{
  84. State: commitstatus.CommitStatusState(state),
  85. TargetURL: "http://test.ci/",
  86. Description: "",
  87. Context: "testci",
  88. }))
  89. req = NewRequest(t, "GET", "/user2/repo1/commits/branch/master")
  90. resp = session.MakeRequest(t, req, http.StatusOK)
  91. doc = NewHTMLParser(t, resp.Body)
  92. // Check if commit status is displayed in message column (.tippy-target to ignore the tippy trigger)
  93. sel := doc.doc.Find("#commits-table .message .tippy-target .commit-status")
  94. assert.Equal(t, 1, sel.Length())
  95. for _, class := range classes {
  96. assert.True(t, sel.HasClass(class))
  97. }
  98. // By SHA
  99. req = NewRequest(t, "GET", "/api/v1/repos/user2/repo1/commits/"+path.Base(commitURL)+"/statuses")
  100. reqOne := NewRequest(t, "GET", "/api/v1/repos/user2/repo1/commits/"+path.Base(commitURL)+"/status")
  101. testRepoCommitsWithStatus(t, session.MakeRequest(t, req, http.StatusOK), session.MakeRequest(t, reqOne, http.StatusOK), state)
  102. // By short SHA
  103. req = NewRequest(t, "GET", "/api/v1/repos/user2/repo1/commits/"+path.Base(commitURL)[:10]+"/statuses")
  104. reqOne = NewRequest(t, "GET", "/api/v1/repos/user2/repo1/commits/"+path.Base(commitURL)[:10]+"/status")
  105. testRepoCommitsWithStatus(t, session.MakeRequest(t, req, http.StatusOK), session.MakeRequest(t, reqOne, http.StatusOK), state)
  106. // By Ref
  107. req = NewRequest(t, "GET", "/api/v1/repos/user2/repo1/commits/master/statuses")
  108. reqOne = NewRequest(t, "GET", "/api/v1/repos/user2/repo1/commits/master/status")
  109. testRepoCommitsWithStatus(t, session.MakeRequest(t, req, http.StatusOK), session.MakeRequest(t, reqOne, http.StatusOK), state)
  110. req = NewRequest(t, "GET", "/api/v1/repos/user2/repo1/commits/v1.1/statuses")
  111. reqOne = NewRequest(t, "GET", "/api/v1/repos/user2/repo1/commits/v1.1/status")
  112. testRepoCommitsWithStatus(t, session.MakeRequest(t, req, http.StatusOK), session.MakeRequest(t, reqOne, http.StatusOK), state)
  113. }
  114. func testRepoCommitsWithStatus(t *testing.T, resp, respOne *httptest.ResponseRecorder, state string) {
  115. var statuses []*api.CommitStatus
  116. assert.NoError(t, json.Unmarshal(resp.Body.Bytes(), &statuses))
  117. var status api.CombinedStatus
  118. assert.NoError(t, json.Unmarshal(respOne.Body.Bytes(), &status))
  119. assert.NotNil(t, status)
  120. if assert.Len(t, statuses, 1) {
  121. assert.Equal(t, commitstatus.CommitStatusState(state), statuses[0].State)
  122. assert.Equal(t, setting.AppURL+"api/v1/repos/user2/repo1/statuses/65f1bf27bc3bf70f64657658635e66094edbcb4d", statuses[0].URL)
  123. assert.Equal(t, "http://test.ci/", statuses[0].TargetURL)
  124. assert.Empty(t, statuses[0].Description)
  125. assert.Equal(t, "testci", statuses[0].Context)
  126. assert.Len(t, status.Statuses, 1)
  127. assert.Equal(t, statuses[0], status.Statuses[0])
  128. assert.Equal(t, "65f1bf27bc3bf70f64657658635e66094edbcb4d", status.SHA)
  129. }
  130. }
  131. func TestRepoCommitsWithStatusPending(t *testing.T) {
  132. doTestRepoCommitWithStatus(t, "pending", "octicon-dot-fill", "yellow")
  133. }
  134. func TestRepoCommitsWithStatusSuccess(t *testing.T) {
  135. doTestRepoCommitWithStatus(t, "success", "octicon-check", "green")
  136. }
  137. func TestRepoCommitsWithStatusError(t *testing.T) {
  138. doTestRepoCommitWithStatus(t, "error", "gitea-exclamation", "red")
  139. }
  140. func TestRepoCommitsWithStatusFailure(t *testing.T) {
  141. doTestRepoCommitWithStatus(t, "failure", "octicon-x", "red")
  142. }
  143. func TestRepoCommitsWithStatusWarning(t *testing.T) {
  144. doTestRepoCommitWithStatus(t, "warning", "gitea-exclamation", "yellow")
  145. }
  146. func TestRepoCommitsStatusParallel(t *testing.T) {
  147. defer tests.PrepareTestEnv(t)()
  148. session := loginUser(t, "user2")
  149. // Request repository commits page
  150. req := NewRequest(t, "GET", "/user2/repo1/commits/branch/master")
  151. resp := session.MakeRequest(t, req, http.StatusOK)
  152. doc := NewHTMLParser(t, resp.Body)
  153. // Get first commit URL
  154. commitURL, exists := doc.doc.Find("#commits-table .commit-id-short").Attr("href")
  155. assert.True(t, exists)
  156. assert.NotEmpty(t, commitURL)
  157. var wg sync.WaitGroup
  158. for i := range 10 {
  159. wg.Add(1)
  160. go func(parentT *testing.T, i int) {
  161. parentT.Run(fmt.Sprintf("ParallelCreateStatus_%d", i), func(t *testing.T) {
  162. ctx := NewAPITestContext(t, "user2", "repo1", auth_model.AccessTokenScopeWriteRepository)
  163. runBody := doAPICreateCommitStatus(ctx, path.Base(commitURL), api.CreateStatusOption{
  164. State: commitstatus.CommitStatusPending,
  165. TargetURL: "http://test.ci/",
  166. Description: "",
  167. Context: "testci",
  168. })
  169. runBody(t)
  170. wg.Done()
  171. })
  172. }(t, i)
  173. }
  174. wg.Wait()
  175. }
  176. func TestRepoCommitsStatusMultiple(t *testing.T) {
  177. defer tests.PrepareTestEnv(t)()
  178. session := loginUser(t, "user2")
  179. // Request repository commits page
  180. req := NewRequest(t, "GET", "/user2/repo1/commits/branch/master")
  181. resp := session.MakeRequest(t, req, http.StatusOK)
  182. doc := NewHTMLParser(t, resp.Body)
  183. // Get first commit URL
  184. commitURL, exists := doc.doc.Find("#commits-table .commit-id-short").Attr("href")
  185. assert.True(t, exists)
  186. assert.NotEmpty(t, commitURL)
  187. // Call API to add status for commit
  188. ctx := NewAPITestContext(t, "user2", "repo1", auth_model.AccessTokenScopeWriteRepository)
  189. t.Run("CreateStatus", doAPICreateCommitStatus(ctx, path.Base(commitURL), api.CreateStatusOption{
  190. State: commitstatus.CommitStatusSuccess,
  191. TargetURL: "http://test.ci/",
  192. Description: "",
  193. Context: "testci",
  194. }))
  195. t.Run("CreateStatus", doAPICreateCommitStatus(ctx, path.Base(commitURL), api.CreateStatusOption{
  196. State: commitstatus.CommitStatusSuccess,
  197. TargetURL: "http://test.ci/",
  198. Description: "",
  199. Context: "other_context",
  200. }))
  201. req = NewRequest(t, "GET", "/user2/repo1/commits/branch/master")
  202. resp = session.MakeRequest(t, req, http.StatusOK)
  203. doc = NewHTMLParser(t, resp.Body)
  204. // Check that the data-global-init="initCommitStatuses" (for trigger) and commit-status (svg) are present
  205. sel := doc.doc.Find(`#commits-table .message [data-global-init="initCommitStatuses"] .commit-status`)
  206. assert.Equal(t, 1, sel.Length())
  207. }