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_repo_test.go 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. // Copyright 2017 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. "fmt"
  7. "net/http"
  8. "net/url"
  9. "os"
  10. "testing"
  11. "code.gitea.io/gitea/models"
  12. "code.gitea.io/gitea/models/unittest"
  13. user_model "code.gitea.io/gitea/models/user"
  14. "code.gitea.io/gitea/modules/setting"
  15. api "code.gitea.io/gitea/modules/structs"
  16. "code.gitea.io/gitea/modules/util"
  17. "github.com/stretchr/testify/assert"
  18. )
  19. func TestAPIUserReposNotLogin(t *testing.T) {
  20. defer prepareTestEnv(t)()
  21. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
  22. req := NewRequestf(t, "GET", "/api/v1/users/%s/repos", user.Name)
  23. resp := MakeRequest(t, req, http.StatusOK)
  24. var apiRepos []api.Repository
  25. DecodeJSON(t, resp, &apiRepos)
  26. expectedLen := unittest.GetCount(t, models.Repository{OwnerID: user.ID},
  27. unittest.Cond("is_private = ?", false))
  28. assert.Len(t, apiRepos, expectedLen)
  29. for _, repo := range apiRepos {
  30. assert.EqualValues(t, user.ID, repo.Owner.ID)
  31. assert.False(t, repo.Private)
  32. }
  33. }
  34. func TestAPISearchRepo(t *testing.T) {
  35. defer prepareTestEnv(t)()
  36. const keyword = "test"
  37. req := NewRequestf(t, "GET", "/api/v1/repos/search?q=%s", keyword)
  38. resp := MakeRequest(t, req, http.StatusOK)
  39. var body api.SearchResults
  40. DecodeJSON(t, resp, &body)
  41. assert.NotEmpty(t, body.Data)
  42. for _, repo := range body.Data {
  43. assert.Contains(t, repo.Name, keyword)
  44. assert.False(t, repo.Private)
  45. }
  46. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15}).(*user_model.User)
  47. user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 16}).(*user_model.User)
  48. user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 18}).(*user_model.User)
  49. user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 20}).(*user_model.User)
  50. orgUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 17}).(*user_model.User)
  51. oldAPIDefaultNum := setting.API.DefaultPagingNum
  52. defer func() {
  53. setting.API.DefaultPagingNum = oldAPIDefaultNum
  54. }()
  55. setting.API.DefaultPagingNum = 10
  56. // Map of expected results, where key is user for login
  57. type expectedResults map[*user_model.User]struct {
  58. count int
  59. repoOwnerID int64
  60. repoName string
  61. includesPrivate bool
  62. }
  63. testCases := []struct {
  64. name, requestURL string
  65. expectedResults
  66. }{
  67. {name: "RepositoriesMax50", requestURL: "/api/v1/repos/search?limit=50&private=false", expectedResults: expectedResults{
  68. nil: {count: 30},
  69. user: {count: 30},
  70. user2: {count: 30}},
  71. },
  72. {name: "RepositoriesMax10", requestURL: "/api/v1/repos/search?limit=10&private=false", expectedResults: expectedResults{
  73. nil: {count: 10},
  74. user: {count: 10},
  75. user2: {count: 10}},
  76. },
  77. {name: "RepositoriesDefault", requestURL: "/api/v1/repos/search?default&private=false", expectedResults: expectedResults{
  78. nil: {count: 10},
  79. user: {count: 10},
  80. user2: {count: 10}},
  81. },
  82. {name: "RepositoriesByName", requestURL: fmt.Sprintf("/api/v1/repos/search?q=%s&private=false", "big_test_"), expectedResults: expectedResults{
  83. nil: {count: 7, repoName: "big_test_"},
  84. user: {count: 7, repoName: "big_test_"},
  85. user2: {count: 7, repoName: "big_test_"}},
  86. },
  87. {name: "RepositoriesAccessibleAndRelatedToUser", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", user.ID), expectedResults: expectedResults{
  88. nil: {count: 5},
  89. user: {count: 9, includesPrivate: true},
  90. user2: {count: 6, includesPrivate: true}},
  91. },
  92. {name: "RepositoriesAccessibleAndRelatedToUser2", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", user2.ID), expectedResults: expectedResults{
  93. nil: {count: 1},
  94. user: {count: 2, includesPrivate: true},
  95. user2: {count: 2, includesPrivate: true},
  96. user4: {count: 1}},
  97. },
  98. {name: "RepositoriesAccessibleAndRelatedToUser3", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", user3.ID), expectedResults: expectedResults{
  99. nil: {count: 1},
  100. user: {count: 4, includesPrivate: true},
  101. user2: {count: 3, includesPrivate: true},
  102. user3: {count: 4, includesPrivate: true}},
  103. },
  104. {name: "RepositoriesOwnedByOrganization", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", orgUser.ID), expectedResults: expectedResults{
  105. nil: {count: 1, repoOwnerID: orgUser.ID},
  106. user: {count: 2, repoOwnerID: orgUser.ID, includesPrivate: true},
  107. user2: {count: 1, repoOwnerID: orgUser.ID}},
  108. },
  109. {name: "RepositoriesAccessibleAndRelatedToUser4", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", user4.ID), expectedResults: expectedResults{
  110. nil: {count: 3},
  111. user: {count: 4, includesPrivate: true},
  112. user4: {count: 7, includesPrivate: true}}},
  113. {name: "RepositoriesAccessibleAndRelatedToUser4/SearchModeSource", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d&mode=%s", user4.ID, "source"), expectedResults: expectedResults{
  114. nil: {count: 0},
  115. user: {count: 1, includesPrivate: true},
  116. user4: {count: 1, includesPrivate: true}}},
  117. {name: "RepositoriesAccessibleAndRelatedToUser4/SearchModeFork", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d&mode=%s", user4.ID, "fork"), expectedResults: expectedResults{
  118. nil: {count: 1},
  119. user: {count: 1},
  120. user4: {count: 2, includesPrivate: true}}},
  121. {name: "RepositoriesAccessibleAndRelatedToUser4/SearchModeFork/Exclusive", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d&mode=%s&exclusive=1", user4.ID, "fork"), expectedResults: expectedResults{
  122. nil: {count: 1},
  123. user: {count: 1},
  124. user4: {count: 2, includesPrivate: true}}},
  125. {name: "RepositoriesAccessibleAndRelatedToUser4/SearchModeMirror", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d&mode=%s", user4.ID, "mirror"), expectedResults: expectedResults{
  126. nil: {count: 2},
  127. user: {count: 2},
  128. user4: {count: 4, includesPrivate: true}}},
  129. {name: "RepositoriesAccessibleAndRelatedToUser4/SearchModeMirror/Exclusive", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d&mode=%s&exclusive=1", user4.ID, "mirror"), expectedResults: expectedResults{
  130. nil: {count: 1},
  131. user: {count: 1},
  132. user4: {count: 2, includesPrivate: true}}},
  133. {name: "RepositoriesAccessibleAndRelatedToUser4/SearchModeCollaborative", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d&mode=%s", user4.ID, "collaborative"), expectedResults: expectedResults{
  134. nil: {count: 0},
  135. user: {count: 1, includesPrivate: true},
  136. user4: {count: 1, includesPrivate: true}}},
  137. }
  138. for _, testCase := range testCases {
  139. t.Run(testCase.name, func(t *testing.T) {
  140. for userToLogin, expected := range testCase.expectedResults {
  141. var session *TestSession
  142. var testName string
  143. var userID int64
  144. var token string
  145. if userToLogin != nil && userToLogin.ID > 0 {
  146. testName = fmt.Sprintf("LoggedUser%d", userToLogin.ID)
  147. session = loginUser(t, userToLogin.Name)
  148. token = getTokenForLoggedInUser(t, session)
  149. userID = userToLogin.ID
  150. } else {
  151. testName = "AnonymousUser"
  152. session = emptyTestSession(t)
  153. }
  154. t.Run(testName, func(t *testing.T) {
  155. request := NewRequest(t, "GET", testCase.requestURL+"&token="+token)
  156. response := session.MakeRequest(t, request, http.StatusOK)
  157. var body api.SearchResults
  158. DecodeJSON(t, response, &body)
  159. repoNames := make([]string, 0, len(body.Data))
  160. for _, repo := range body.Data {
  161. repoNames = append(repoNames, fmt.Sprintf("%d:%s:%t", repo.ID, repo.FullName, repo.Private))
  162. }
  163. assert.Len(t, repoNames, expected.count)
  164. for _, repo := range body.Data {
  165. r := getRepo(t, repo.ID)
  166. hasAccess, err := models.HasAccess(userID, r)
  167. assert.NoError(t, err, "Error when checking if User: %d has access to %s: %v", userID, repo.FullName, err)
  168. assert.True(t, hasAccess, "User: %d does not have access to %s", userID, repo.FullName)
  169. assert.NotEmpty(t, repo.Name)
  170. assert.Equal(t, repo.Name, r.Name)
  171. if len(expected.repoName) > 0 {
  172. assert.Contains(t, repo.Name, expected.repoName)
  173. }
  174. if expected.repoOwnerID > 0 {
  175. assert.Equal(t, expected.repoOwnerID, repo.Owner.ID)
  176. }
  177. if !expected.includesPrivate {
  178. assert.False(t, repo.Private, "User: %d not expecting private repository: %s", userID, repo.FullName)
  179. }
  180. }
  181. })
  182. }
  183. })
  184. }
  185. }
  186. var repoCache = make(map[int64]*models.Repository)
  187. func getRepo(t *testing.T, repoID int64) *models.Repository {
  188. if _, ok := repoCache[repoID]; !ok {
  189. repoCache[repoID] = unittest.AssertExistsAndLoadBean(t, &models.Repository{ID: repoID}).(*models.Repository)
  190. }
  191. return repoCache[repoID]
  192. }
  193. func TestAPIViewRepo(t *testing.T) {
  194. defer prepareTestEnv(t)()
  195. var repo api.Repository
  196. req := NewRequest(t, "GET", "/api/v1/repos/user2/repo1")
  197. resp := MakeRequest(t, req, http.StatusOK)
  198. DecodeJSON(t, resp, &repo)
  199. assert.EqualValues(t, 1, repo.ID)
  200. assert.EqualValues(t, "repo1", repo.Name)
  201. assert.EqualValues(t, 2, repo.Releases)
  202. assert.EqualValues(t, 1, repo.OpenIssues)
  203. assert.EqualValues(t, 3, repo.OpenPulls)
  204. req = NewRequest(t, "GET", "/api/v1/repos/user12/repo10")
  205. resp = MakeRequest(t, req, http.StatusOK)
  206. DecodeJSON(t, resp, &repo)
  207. assert.EqualValues(t, 10, repo.ID)
  208. assert.EqualValues(t, "repo10", repo.Name)
  209. assert.EqualValues(t, 1, repo.OpenPulls)
  210. assert.EqualValues(t, 1, repo.Forks)
  211. req = NewRequest(t, "GET", "/api/v1/repos/user5/repo4")
  212. resp = MakeRequest(t, req, http.StatusOK)
  213. DecodeJSON(t, resp, &repo)
  214. assert.EqualValues(t, 4, repo.ID)
  215. assert.EqualValues(t, "repo4", repo.Name)
  216. assert.EqualValues(t, 1, repo.Stars)
  217. }
  218. func TestAPIOrgRepos(t *testing.T) {
  219. defer prepareTestEnv(t)()
  220. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
  221. user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
  222. user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User)
  223. // User3 is an Org. Check their repos.
  224. sourceOrg := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User)
  225. expectedResults := map[*user_model.User]struct {
  226. count int
  227. includesPrivate bool
  228. }{
  229. nil: {count: 1},
  230. user: {count: 3, includesPrivate: true},
  231. user2: {count: 3, includesPrivate: true},
  232. user3: {count: 1},
  233. }
  234. for userToLogin, expected := range expectedResults {
  235. var session *TestSession
  236. var testName string
  237. var token string
  238. if userToLogin != nil && userToLogin.ID > 0 {
  239. testName = fmt.Sprintf("LoggedUser%d", userToLogin.ID)
  240. session = loginUser(t, userToLogin.Name)
  241. token = getTokenForLoggedInUser(t, session)
  242. } else {
  243. testName = "AnonymousUser"
  244. session = emptyTestSession(t)
  245. }
  246. t.Run(testName, func(t *testing.T) {
  247. req := NewRequestf(t, "GET", "/api/v1/orgs/%s/repos?token="+token, sourceOrg.Name)
  248. resp := session.MakeRequest(t, req, http.StatusOK)
  249. var apiRepos []*api.Repository
  250. DecodeJSON(t, resp, &apiRepos)
  251. assert.Len(t, apiRepos, expected.count)
  252. for _, repo := range apiRepos {
  253. if !expected.includesPrivate {
  254. assert.False(t, repo.Private)
  255. }
  256. }
  257. })
  258. }
  259. }
  260. func TestAPIGetRepoByIDUnauthorized(t *testing.T) {
  261. defer prepareTestEnv(t)()
  262. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User)
  263. session := loginUser(t, user.Name)
  264. token := getTokenForLoggedInUser(t, session)
  265. req := NewRequestf(t, "GET", "/api/v1/repositories/2?token="+token)
  266. session.MakeRequest(t, req, http.StatusNotFound)
  267. }
  268. func TestAPIRepoMigrate(t *testing.T) {
  269. testCases := []struct {
  270. ctxUserID, userID int64
  271. cloneURL, repoName string
  272. expectedStatus int
  273. }{
  274. {ctxUserID: 1, userID: 2, cloneURL: "https://github.com/go-gitea/test_repo.git", repoName: "git-admin", expectedStatus: http.StatusCreated},
  275. {ctxUserID: 2, userID: 2, cloneURL: "https://github.com/go-gitea/test_repo.git", repoName: "git-own", expectedStatus: http.StatusCreated},
  276. {ctxUserID: 2, userID: 1, cloneURL: "https://github.com/go-gitea/test_repo.git", repoName: "git-bad", expectedStatus: http.StatusForbidden},
  277. {ctxUserID: 2, userID: 3, cloneURL: "https://github.com/go-gitea/test_repo.git", repoName: "git-org", expectedStatus: http.StatusCreated},
  278. {ctxUserID: 2, userID: 6, cloneURL: "https://github.com/go-gitea/test_repo.git", repoName: "git-bad-org", expectedStatus: http.StatusForbidden},
  279. {ctxUserID: 2, userID: 3, cloneURL: "https://localhost:3000/user/test_repo.git", repoName: "private-ip", expectedStatus: http.StatusUnprocessableEntity},
  280. {ctxUserID: 2, userID: 3, cloneURL: "https://10.0.0.1/user/test_repo.git", repoName: "private-ip", expectedStatus: http.StatusUnprocessableEntity},
  281. }
  282. defer prepareTestEnv(t)()
  283. for _, testCase := range testCases {
  284. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: testCase.ctxUserID}).(*user_model.User)
  285. session := loginUser(t, user.Name)
  286. token := getTokenForLoggedInUser(t, session)
  287. req := NewRequestWithJSON(t, "POST", "/api/v1/repos/migrate?token="+token, &api.MigrateRepoOptions{
  288. CloneAddr: testCase.cloneURL,
  289. RepoOwnerID: testCase.userID,
  290. RepoName: testCase.repoName,
  291. })
  292. resp := MakeRequest(t, req, NoExpectedStatus)
  293. if resp.Code == http.StatusUnprocessableEntity {
  294. respJSON := map[string]string{}
  295. DecodeJSON(t, resp, &respJSON)
  296. switch respJSON["message"] {
  297. case "Remote visit addressed rate limitation.":
  298. t.Log("test hit github rate limitation")
  299. case "You can not import from disallowed hosts.":
  300. assert.EqualValues(t, "private-ip", testCase.repoName)
  301. default:
  302. assert.Failf(t, "unexpected error '%v' on url '%s'", respJSON["message"], testCase.cloneURL)
  303. }
  304. } else {
  305. assert.EqualValues(t, testCase.expectedStatus, resp.Code)
  306. }
  307. }
  308. }
  309. func TestAPIRepoMigrateConflict(t *testing.T) {
  310. onGiteaRun(t, testAPIRepoMigrateConflict)
  311. }
  312. func testAPIRepoMigrateConflict(t *testing.T, u *url.URL) {
  313. username := "user2"
  314. baseAPITestContext := NewAPITestContext(t, username, "repo1")
  315. u.Path = baseAPITestContext.GitPath()
  316. t.Run("Existing", func(t *testing.T) {
  317. httpContext := baseAPITestContext
  318. httpContext.Reponame = "repo-tmp-17"
  319. dstPath, err := os.MkdirTemp("", httpContext.Reponame)
  320. assert.NoError(t, err)
  321. defer util.RemoveAll(dstPath)
  322. t.Run("CreateRepo", doAPICreateRepository(httpContext, false))
  323. user, err := user_model.GetUserByName(httpContext.Username)
  324. assert.NoError(t, err)
  325. userID := user.ID
  326. cloneURL := "https://github.com/go-gitea/test_repo.git"
  327. req := NewRequestWithJSON(t, "POST", "/api/v1/repos/migrate?token="+httpContext.Token,
  328. &api.MigrateRepoOptions{
  329. CloneAddr: cloneURL,
  330. RepoOwnerID: userID,
  331. RepoName: httpContext.Reponame,
  332. })
  333. resp := httpContext.Session.MakeRequest(t, req, http.StatusConflict)
  334. respJSON := map[string]string{}
  335. DecodeJSON(t, resp, &respJSON)
  336. assert.Equal(t, "The repository with the same name already exists.", respJSON["message"])
  337. })
  338. }
  339. func TestAPIOrgRepoCreate(t *testing.T) {
  340. testCases := []struct {
  341. ctxUserID int64
  342. orgName, repoName string
  343. expectedStatus int
  344. }{
  345. {ctxUserID: 1, orgName: "user3", repoName: "repo-admin", expectedStatus: http.StatusCreated},
  346. {ctxUserID: 2, orgName: "user3", repoName: "repo-own", expectedStatus: http.StatusCreated},
  347. {ctxUserID: 2, orgName: "user6", repoName: "repo-bad-org", expectedStatus: http.StatusForbidden},
  348. {ctxUserID: 28, orgName: "user3", repoName: "repo-creator", expectedStatus: http.StatusCreated},
  349. {ctxUserID: 28, orgName: "user6", repoName: "repo-not-creator", expectedStatus: http.StatusForbidden},
  350. }
  351. defer prepareTestEnv(t)()
  352. for _, testCase := range testCases {
  353. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: testCase.ctxUserID}).(*user_model.User)
  354. session := loginUser(t, user.Name)
  355. token := getTokenForLoggedInUser(t, session)
  356. req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/org/%s/repos?token="+token, testCase.orgName), &api.CreateRepoOption{
  357. Name: testCase.repoName,
  358. })
  359. session.MakeRequest(t, req, testCase.expectedStatus)
  360. }
  361. }
  362. func TestAPIRepoCreateConflict(t *testing.T) {
  363. onGiteaRun(t, testAPIRepoCreateConflict)
  364. }
  365. func testAPIRepoCreateConflict(t *testing.T, u *url.URL) {
  366. username := "user2"
  367. baseAPITestContext := NewAPITestContext(t, username, "repo1")
  368. u.Path = baseAPITestContext.GitPath()
  369. t.Run("Existing", func(t *testing.T) {
  370. httpContext := baseAPITestContext
  371. httpContext.Reponame = "repo-tmp-17"
  372. dstPath, err := os.MkdirTemp("", httpContext.Reponame)
  373. assert.NoError(t, err)
  374. defer util.RemoveAll(dstPath)
  375. t.Run("CreateRepo", doAPICreateRepository(httpContext, false))
  376. req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos?token="+httpContext.Token,
  377. &api.CreateRepoOption{
  378. Name: httpContext.Reponame,
  379. })
  380. resp := httpContext.Session.MakeRequest(t, req, http.StatusConflict)
  381. respJSON := map[string]string{}
  382. DecodeJSON(t, resp, &respJSON)
  383. assert.Equal(t, respJSON["message"], "The repository with the same name already exists.")
  384. })
  385. }
  386. func TestAPIRepoTransfer(t *testing.T) {
  387. testCases := []struct {
  388. ctxUserID int64
  389. newOwner string
  390. teams *[]int64
  391. expectedStatus int
  392. }{
  393. // Disclaimer for test story: "user1" is an admin, "user2" is normal user and part of in owner team of org "user3"
  394. // Transfer to a user with teams in another org should fail
  395. {ctxUserID: 1, newOwner: "user3", teams: &[]int64{5}, expectedStatus: http.StatusForbidden},
  396. // Transfer to a user with non-existent team IDs should fail
  397. {ctxUserID: 1, newOwner: "user2", teams: &[]int64{2}, expectedStatus: http.StatusUnprocessableEntity},
  398. // Transfer should go through
  399. {ctxUserID: 1, newOwner: "user3", teams: &[]int64{2}, expectedStatus: http.StatusAccepted},
  400. // Let user transfer it back to himself
  401. {ctxUserID: 2, newOwner: "user2", expectedStatus: http.StatusAccepted},
  402. // And revert transfer
  403. {ctxUserID: 2, newOwner: "user3", teams: &[]int64{2}, expectedStatus: http.StatusAccepted},
  404. // Cannot start transfer to an existing repo
  405. {ctxUserID: 2, newOwner: "user3", teams: nil, expectedStatus: http.StatusUnprocessableEntity},
  406. // Start transfer, repo is now in pending transfer mode
  407. {ctxUserID: 2, newOwner: "user6", teams: nil, expectedStatus: http.StatusCreated},
  408. }
  409. defer prepareTestEnv(t)()
  410. //create repo to move
  411. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
  412. session := loginUser(t, user.Name)
  413. token := getTokenForLoggedInUser(t, session)
  414. repoName := "moveME"
  415. apiRepo := new(api.Repository)
  416. req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/user/repos?token=%s", token), &api.CreateRepoOption{
  417. Name: repoName,
  418. Description: "repo move around",
  419. Private: false,
  420. Readme: "Default",
  421. AutoInit: true,
  422. })
  423. resp := session.MakeRequest(t, req, http.StatusCreated)
  424. DecodeJSON(t, resp, apiRepo)
  425. //start testing
  426. for _, testCase := range testCases {
  427. user = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: testCase.ctxUserID}).(*user_model.User)
  428. repo := unittest.AssertExistsAndLoadBean(t, &models.Repository{ID: apiRepo.ID}).(*models.Repository)
  429. session = loginUser(t, user.Name)
  430. token = getTokenForLoggedInUser(t, session)
  431. req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/transfer?token=%s", repo.OwnerName, repo.Name, token), &api.TransferRepoOption{
  432. NewOwner: testCase.newOwner,
  433. TeamIDs: testCase.teams,
  434. })
  435. session.MakeRequest(t, req, testCase.expectedStatus)
  436. }
  437. //cleanup
  438. repo := unittest.AssertExistsAndLoadBean(t, &models.Repository{ID: apiRepo.ID}).(*models.Repository)
  439. _ = models.DeleteRepository(user, repo.OwnerID, repo.ID)
  440. }
  441. func TestAPIGenerateRepo(t *testing.T) {
  442. defer prepareTestEnv(t)()
  443. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
  444. session := loginUser(t, user.Name)
  445. token := getTokenForLoggedInUser(t, session)
  446. templateRepo := unittest.AssertExistsAndLoadBean(t, &models.Repository{ID: 44}).(*models.Repository)
  447. // user
  448. repo := new(api.Repository)
  449. req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/generate?token=%s", templateRepo.OwnerName, templateRepo.Name, token), &api.GenerateRepoOption{
  450. Owner: user.Name,
  451. Name: "new-repo",
  452. Description: "test generate repo",
  453. Private: false,
  454. GitContent: true,
  455. })
  456. resp := session.MakeRequest(t, req, http.StatusCreated)
  457. DecodeJSON(t, resp, repo)
  458. assert.Equal(t, "new-repo", repo.Name)
  459. // org
  460. req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/generate?token=%s", templateRepo.OwnerName, templateRepo.Name, token), &api.GenerateRepoOption{
  461. Owner: "user3",
  462. Name: "new-repo",
  463. Description: "test generate repo",
  464. Private: false,
  465. GitContent: true,
  466. })
  467. resp = session.MakeRequest(t, req, http.StatusCreated)
  468. DecodeJSON(t, resp, repo)
  469. assert.Equal(t, "new-repo", repo.Name)
  470. }
  471. func TestAPIRepoGetReviewers(t *testing.T) {
  472. defer prepareTestEnv(t)()
  473. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
  474. session := loginUser(t, user.Name)
  475. token := getTokenForLoggedInUser(t, session)
  476. repo := unittest.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository)
  477. req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/reviewers?token=%s", user.Name, repo.Name, token)
  478. resp := session.MakeRequest(t, req, http.StatusOK)
  479. var reviewers []*api.User
  480. DecodeJSON(t, resp, &reviewers)
  481. assert.Len(t, reviewers, 4)
  482. }
  483. func TestAPIRepoGetAssignees(t *testing.T) {
  484. defer prepareTestEnv(t)()
  485. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
  486. session := loginUser(t, user.Name)
  487. token := getTokenForLoggedInUser(t, session)
  488. repo := unittest.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository)
  489. req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/assignees?token=%s", user.Name, repo.Name, token)
  490. resp := session.MakeRequest(t, req, http.StatusOK)
  491. var assignees []*api.User
  492. DecodeJSON(t, resp, &assignees)
  493. assert.Len(t, assignees, 1)
  494. }