You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

api_helper_for_declarative_test.go 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. // Copyright 2019 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package integrations
  5. import (
  6. "context"
  7. "fmt"
  8. "io/ioutil"
  9. "net/http"
  10. "net/url"
  11. "testing"
  12. "time"
  13. "code.gitea.io/gitea/models"
  14. "code.gitea.io/gitea/modules/queue"
  15. api "code.gitea.io/gitea/modules/structs"
  16. "code.gitea.io/gitea/services/forms"
  17. jsoniter "github.com/json-iterator/go"
  18. "github.com/stretchr/testify/assert"
  19. )
  20. type APITestContext struct {
  21. Reponame string
  22. Session *TestSession
  23. Token string
  24. Username string
  25. ExpectedCode int
  26. }
  27. func NewAPITestContext(t *testing.T, username, reponame string) APITestContext {
  28. session := loginUser(t, username)
  29. token := getTokenForLoggedInUser(t, session)
  30. return APITestContext{
  31. Session: session,
  32. Token: token,
  33. Username: username,
  34. Reponame: reponame,
  35. }
  36. }
  37. func (ctx APITestContext) GitPath() string {
  38. return fmt.Sprintf("%s/%s.git", ctx.Username, ctx.Reponame)
  39. }
  40. func doAPICreateRepository(ctx APITestContext, empty bool, callback ...func(*testing.T, api.Repository)) func(*testing.T) {
  41. return func(t *testing.T) {
  42. createRepoOption := &api.CreateRepoOption{
  43. AutoInit: !empty,
  44. Description: "Temporary repo",
  45. Name: ctx.Reponame,
  46. Private: true,
  47. Template: true,
  48. Gitignores: "",
  49. License: "WTFPL",
  50. Readme: "Default",
  51. }
  52. req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos?token="+ctx.Token, createRepoOption)
  53. if ctx.ExpectedCode != 0 {
  54. ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
  55. return
  56. }
  57. resp := ctx.Session.MakeRequest(t, req, http.StatusCreated)
  58. var repository api.Repository
  59. DecodeJSON(t, resp, &repository)
  60. if len(callback) > 0 {
  61. callback[0](t, repository)
  62. }
  63. }
  64. }
  65. func doAPIEditRepository(ctx APITestContext, editRepoOption *api.EditRepoOption, callback ...func(*testing.T, api.Repository)) func(*testing.T) {
  66. return func(t *testing.T) {
  67. req := NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", url.PathEscape(ctx.Username), url.PathEscape(ctx.Reponame), ctx.Token), editRepoOption)
  68. if ctx.ExpectedCode != 0 {
  69. ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
  70. return
  71. }
  72. resp := ctx.Session.MakeRequest(t, req, http.StatusOK)
  73. var repository api.Repository
  74. DecodeJSON(t, resp, &repository)
  75. if len(callback) > 0 {
  76. callback[0](t, repository)
  77. }
  78. }
  79. }
  80. func doAPIAddCollaborator(ctx APITestContext, username string, mode models.AccessMode) func(*testing.T) {
  81. return func(t *testing.T) {
  82. permission := "read"
  83. if mode == models.AccessModeAdmin {
  84. permission = "admin"
  85. } else if mode > models.AccessModeRead {
  86. permission = "write"
  87. }
  88. addCollaboratorOption := &api.AddCollaboratorOption{
  89. Permission: &permission,
  90. }
  91. req := NewRequestWithJSON(t, "PUT", fmt.Sprintf("/api/v1/repos/%s/%s/collaborators/%s?token=%s", ctx.Username, ctx.Reponame, username, ctx.Token), addCollaboratorOption)
  92. if ctx.ExpectedCode != 0 {
  93. ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
  94. return
  95. }
  96. ctx.Session.MakeRequest(t, req, http.StatusNoContent)
  97. }
  98. }
  99. func doAPIForkRepository(ctx APITestContext, username string, callback ...func(*testing.T, api.Repository)) func(*testing.T) {
  100. return func(t *testing.T) {
  101. createForkOption := &api.CreateForkOption{}
  102. req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/forks?token=%s", username, ctx.Reponame, ctx.Token), createForkOption)
  103. if ctx.ExpectedCode != 0 {
  104. ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
  105. return
  106. }
  107. resp := ctx.Session.MakeRequest(t, req, http.StatusAccepted)
  108. var repository api.Repository
  109. DecodeJSON(t, resp, &repository)
  110. if len(callback) > 0 {
  111. callback[0](t, repository)
  112. }
  113. }
  114. }
  115. func doAPIGetRepository(ctx APITestContext, callback ...func(*testing.T, api.Repository)) func(*testing.T) {
  116. return func(t *testing.T) {
  117. urlStr := fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", ctx.Username, ctx.Reponame, ctx.Token)
  118. req := NewRequest(t, "GET", urlStr)
  119. if ctx.ExpectedCode != 0 {
  120. ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
  121. return
  122. }
  123. resp := ctx.Session.MakeRequest(t, req, http.StatusOK)
  124. var repository api.Repository
  125. DecodeJSON(t, resp, &repository)
  126. if len(callback) > 0 {
  127. callback[0](t, repository)
  128. }
  129. }
  130. }
  131. func doAPIDeleteRepository(ctx APITestContext) func(*testing.T) {
  132. return func(t *testing.T) {
  133. urlStr := fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", ctx.Username, ctx.Reponame, ctx.Token)
  134. req := NewRequest(t, "DELETE", urlStr)
  135. if ctx.ExpectedCode != 0 {
  136. ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
  137. return
  138. }
  139. ctx.Session.MakeRequest(t, req, http.StatusNoContent)
  140. }
  141. }
  142. func doAPICreateUserKey(ctx APITestContext, keyname, keyFile string, callback ...func(*testing.T, api.PublicKey)) func(*testing.T) {
  143. return func(t *testing.T) {
  144. urlStr := fmt.Sprintf("/api/v1/user/keys?token=%s", ctx.Token)
  145. dataPubKey, err := ioutil.ReadFile(keyFile + ".pub")
  146. assert.NoError(t, err)
  147. req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateKeyOption{
  148. Title: keyname,
  149. Key: string(dataPubKey),
  150. })
  151. if ctx.ExpectedCode != 0 {
  152. ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
  153. return
  154. }
  155. resp := ctx.Session.MakeRequest(t, req, http.StatusCreated)
  156. var publicKey api.PublicKey
  157. DecodeJSON(t, resp, &publicKey)
  158. if len(callback) > 0 {
  159. callback[0](t, publicKey)
  160. }
  161. }
  162. }
  163. func doAPIDeleteUserKey(ctx APITestContext, keyID int64) func(*testing.T) {
  164. return func(t *testing.T) {
  165. urlStr := fmt.Sprintf("/api/v1/user/keys/%d?token=%s", keyID, ctx.Token)
  166. req := NewRequest(t, "DELETE", urlStr)
  167. if ctx.ExpectedCode != 0 {
  168. ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
  169. return
  170. }
  171. ctx.Session.MakeRequest(t, req, http.StatusNoContent)
  172. }
  173. }
  174. func doAPICreateDeployKey(ctx APITestContext, keyname, keyFile string, readOnly bool) func(*testing.T) {
  175. return func(t *testing.T) {
  176. urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/keys?token=%s", ctx.Username, ctx.Reponame, ctx.Token)
  177. dataPubKey, err := ioutil.ReadFile(keyFile + ".pub")
  178. assert.NoError(t, err)
  179. req := NewRequestWithJSON(t, "POST", urlStr, api.CreateKeyOption{
  180. Title: keyname,
  181. Key: string(dataPubKey),
  182. ReadOnly: readOnly,
  183. })
  184. if ctx.ExpectedCode != 0 {
  185. ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
  186. return
  187. }
  188. ctx.Session.MakeRequest(t, req, http.StatusCreated)
  189. }
  190. }
  191. func doAPICreatePullRequest(ctx APITestContext, owner, repo, baseBranch, headBranch string) func(*testing.T) (api.PullRequest, error) {
  192. return func(t *testing.T) (api.PullRequest, error) {
  193. urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/pulls?token=%s",
  194. owner, repo, ctx.Token)
  195. req := NewRequestWithJSON(t, http.MethodPost, urlStr, &api.CreatePullRequestOption{
  196. Head: headBranch,
  197. Base: baseBranch,
  198. Title: fmt.Sprintf("create a pr from %s to %s", headBranch, baseBranch),
  199. })
  200. expected := 201
  201. if ctx.ExpectedCode != 0 {
  202. expected = ctx.ExpectedCode
  203. }
  204. resp := ctx.Session.MakeRequest(t, req, expected)
  205. json := jsoniter.ConfigCompatibleWithStandardLibrary
  206. decoder := json.NewDecoder(resp.Body)
  207. pr := api.PullRequest{}
  208. err := decoder.Decode(&pr)
  209. return pr, err
  210. }
  211. }
  212. func doAPIGetPullRequest(ctx APITestContext, owner, repo string, index int64) func(*testing.T) (api.PullRequest, error) {
  213. return func(t *testing.T) (api.PullRequest, error) {
  214. urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d?token=%s",
  215. owner, repo, index, ctx.Token)
  216. req := NewRequest(t, http.MethodGet, urlStr)
  217. expected := 200
  218. if ctx.ExpectedCode != 0 {
  219. expected = ctx.ExpectedCode
  220. }
  221. resp := ctx.Session.MakeRequest(t, req, expected)
  222. json := jsoniter.ConfigCompatibleWithStandardLibrary
  223. decoder := json.NewDecoder(resp.Body)
  224. pr := api.PullRequest{}
  225. err := decoder.Decode(&pr)
  226. return pr, err
  227. }
  228. }
  229. func doAPIMergePullRequest(ctx APITestContext, owner, repo string, index int64) func(*testing.T) {
  230. return func(t *testing.T) {
  231. urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/merge?token=%s",
  232. owner, repo, index, ctx.Token)
  233. req := NewRequestWithJSON(t, http.MethodPost, urlStr, &forms.MergePullRequestForm{
  234. MergeMessageField: "doAPIMergePullRequest Merge",
  235. Do: string(models.MergeStyleMerge),
  236. })
  237. resp := ctx.Session.MakeRequest(t, req, NoExpectedStatus)
  238. if resp.Code == http.StatusMethodNotAllowed {
  239. err := api.APIError{}
  240. DecodeJSON(t, resp, &err)
  241. assert.EqualValues(t, "Please try again later", err.Message)
  242. queue.GetManager().FlushAll(context.Background(), 5*time.Second)
  243. req = NewRequestWithJSON(t, http.MethodPost, urlStr, &forms.MergePullRequestForm{
  244. MergeMessageField: "doAPIMergePullRequest Merge",
  245. Do: string(models.MergeStyleMerge),
  246. })
  247. resp = ctx.Session.MakeRequest(t, req, NoExpectedStatus)
  248. }
  249. expected := ctx.ExpectedCode
  250. if expected == 0 {
  251. expected = 200
  252. }
  253. if !assert.EqualValues(t, expected, resp.Code,
  254. "Request: %s %s", req.Method, req.URL.String()) {
  255. logUnexpectedResponse(t, resp)
  256. }
  257. }
  258. }
  259. func doAPIManuallyMergePullRequest(ctx APITestContext, owner, repo, commitID string, index int64) func(*testing.T) {
  260. return func(t *testing.T) {
  261. urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/merge?token=%s",
  262. owner, repo, index, ctx.Token)
  263. req := NewRequestWithJSON(t, http.MethodPost, urlStr, &forms.MergePullRequestForm{
  264. Do: string(models.MergeStyleManuallyMerged),
  265. MergeCommitID: commitID,
  266. })
  267. if ctx.ExpectedCode != 0 {
  268. ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
  269. return
  270. }
  271. ctx.Session.MakeRequest(t, req, 200)
  272. }
  273. }
  274. func doAPIGetBranch(ctx APITestContext, branch string, callback ...func(*testing.T, api.Branch)) func(*testing.T) {
  275. return func(t *testing.T) {
  276. req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/branches/%s?token=%s", ctx.Username, ctx.Reponame, branch, ctx.Token)
  277. if ctx.ExpectedCode != 0 {
  278. ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
  279. return
  280. }
  281. resp := ctx.Session.MakeRequest(t, req, http.StatusOK)
  282. var branch api.Branch
  283. DecodeJSON(t, resp, &branch)
  284. if len(callback) > 0 {
  285. callback[0](t, branch)
  286. }
  287. }
  288. }
  289. func doAPICreateFile(ctx APITestContext, treepath string, options *api.CreateFileOptions, callback ...func(*testing.T, api.FileResponse)) func(*testing.T) {
  290. return func(t *testing.T) {
  291. url := fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", ctx.Username, ctx.Reponame, treepath, ctx.Token)
  292. req := NewRequestWithJSON(t, "POST", url, &options)
  293. if ctx.ExpectedCode != 0 {
  294. ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
  295. return
  296. }
  297. resp := ctx.Session.MakeRequest(t, req, http.StatusCreated)
  298. var contents api.FileResponse
  299. DecodeJSON(t, resp, &contents)
  300. if len(callback) > 0 {
  301. callback[0](t, contents)
  302. }
  303. }
  304. }
  305. func doAPICreateOrganization(ctx APITestContext, options *api.CreateOrgOption, callback ...func(*testing.T, api.Organization)) func(t *testing.T) {
  306. return func(t *testing.T) {
  307. url := fmt.Sprintf("/api/v1/orgs?token=%s", ctx.Token)
  308. req := NewRequestWithJSON(t, "POST", url, &options)
  309. if ctx.ExpectedCode != 0 {
  310. ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
  311. return
  312. }
  313. resp := ctx.Session.MakeRequest(t, req, http.StatusCreated)
  314. var contents api.Organization
  315. DecodeJSON(t, resp, &contents)
  316. if len(callback) > 0 {
  317. callback[0](t, contents)
  318. }
  319. }
  320. }
  321. func doAPICreateOrganizationRepository(ctx APITestContext, orgName string, options *api.CreateRepoOption, callback ...func(*testing.T, api.Repository)) func(t *testing.T) {
  322. return func(t *testing.T) {
  323. url := fmt.Sprintf("/api/v1/orgs/%s/repos?token=%s", orgName, ctx.Token)
  324. req := NewRequestWithJSON(t, "POST", url, &options)
  325. if ctx.ExpectedCode != 0 {
  326. ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
  327. return
  328. }
  329. resp := ctx.Session.MakeRequest(t, req, http.StatusCreated)
  330. var contents api.Repository
  331. DecodeJSON(t, resp, &contents)
  332. if len(callback) > 0 {
  333. callback[0](t, contents)
  334. }
  335. }
  336. }
  337. func doAPICreateOrganizationTeam(ctx APITestContext, orgName string, options *api.CreateTeamOption, callback ...func(*testing.T, api.Team)) func(t *testing.T) {
  338. return func(t *testing.T) {
  339. url := fmt.Sprintf("/api/v1/orgs/%s/teams?token=%s", orgName, ctx.Token)
  340. req := NewRequestWithJSON(t, "POST", url, &options)
  341. if ctx.ExpectedCode != 0 {
  342. ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
  343. return
  344. }
  345. resp := ctx.Session.MakeRequest(t, req, http.StatusCreated)
  346. var contents api.Team
  347. DecodeJSON(t, resp, &contents)
  348. if len(callback) > 0 {
  349. callback[0](t, contents)
  350. }
  351. }
  352. }
  353. func doAPIAddUserToOrganizationTeam(ctx APITestContext, teamID int64, username string) func(t *testing.T) {
  354. return func(t *testing.T) {
  355. url := fmt.Sprintf("/api/v1/teams/%d/members/%s?token=%s", teamID, username, ctx.Token)
  356. req := NewRequest(t, "PUT", url)
  357. if ctx.ExpectedCode != 0 {
  358. ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
  359. return
  360. }
  361. ctx.Session.MakeRequest(t, req, http.StatusNoContent)
  362. }
  363. }
  364. func doAPIAddRepoToOrganizationTeam(ctx APITestContext, teamID int64, orgName, repoName string) func(t *testing.T) {
  365. return func(t *testing.T) {
  366. url := fmt.Sprintf("/api/v1/teams/%d/repos/%s/%s?token=%s", teamID, orgName, repoName, ctx.Token)
  367. req := NewRequest(t, "PUT", url)
  368. if ctx.ExpectedCode != 0 {
  369. ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
  370. return
  371. }
  372. ctx.Session.MakeRequest(t, req, http.StatusNoContent)
  373. }
  374. }