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.

action_test.go 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. package models
  2. import (
  3. "fmt"
  4. "path"
  5. "strings"
  6. "testing"
  7. "code.gitea.io/gitea/modules/setting"
  8. "github.com/stretchr/testify/assert"
  9. )
  10. func TestAction_GetRepoPath(t *testing.T) {
  11. assert.NoError(t, PrepareTestDatabase())
  12. repo := AssertExistsAndLoadBean(t, &Repository{}).(*Repository)
  13. owner := AssertExistsAndLoadBean(t, &User{ID: repo.OwnerID}).(*User)
  14. action := &Action{RepoID: repo.ID}
  15. assert.Equal(t, path.Join(owner.Name, repo.Name), action.GetRepoPath())
  16. }
  17. func TestAction_GetRepoLink(t *testing.T) {
  18. assert.NoError(t, PrepareTestDatabase())
  19. repo := AssertExistsAndLoadBean(t, &Repository{}).(*Repository)
  20. owner := AssertExistsAndLoadBean(t, &User{ID: repo.OwnerID}).(*User)
  21. action := &Action{RepoID: repo.ID}
  22. setting.AppSubURL = "/suburl/"
  23. expected := path.Join(setting.AppSubURL, owner.Name, repo.Name)
  24. assert.Equal(t, expected, action.GetRepoLink())
  25. }
  26. func TestNewRepoAction(t *testing.T) {
  27. assert.NoError(t, PrepareTestDatabase())
  28. user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
  29. repo := AssertExistsAndLoadBean(t, &Repository{OwnerID: user.ID}).(*Repository)
  30. repo.Owner = user
  31. actionBean := &Action{
  32. OpType: ActionCreateRepo,
  33. ActUserID: user.ID,
  34. RepoID: repo.ID,
  35. ActUser: user,
  36. Repo: repo,
  37. IsPrivate: repo.IsPrivate,
  38. }
  39. AssertNotExistsBean(t, actionBean)
  40. assert.NoError(t, NewRepoAction(user, repo))
  41. AssertExistsAndLoadBean(t, actionBean)
  42. CheckConsistencyFor(t, &Action{})
  43. }
  44. func TestRenameRepoAction(t *testing.T) {
  45. assert.NoError(t, PrepareTestDatabase())
  46. user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
  47. repo := AssertExistsAndLoadBean(t, &Repository{OwnerID: user.ID}).(*Repository)
  48. repo.Owner = user
  49. oldRepoName := repo.Name
  50. const newRepoName = "newRepoName"
  51. repo.Name = newRepoName
  52. repo.LowerName = strings.ToLower(newRepoName)
  53. actionBean := &Action{
  54. OpType: ActionRenameRepo,
  55. ActUserID: user.ID,
  56. ActUser: user,
  57. RepoID: repo.ID,
  58. Repo: repo,
  59. IsPrivate: repo.IsPrivate,
  60. Content: oldRepoName,
  61. }
  62. AssertNotExistsBean(t, actionBean)
  63. assert.NoError(t, RenameRepoAction(user, oldRepoName, repo))
  64. AssertExistsAndLoadBean(t, actionBean)
  65. _, err := x.ID(repo.ID).Cols("name", "lower_name").Update(repo)
  66. assert.NoError(t, err)
  67. CheckConsistencyFor(t, &Action{})
  68. }
  69. func TestPushCommits_ToAPIPayloadCommits(t *testing.T) {
  70. pushCommits := NewPushCommits()
  71. pushCommits.Commits = []*PushCommit{
  72. {
  73. Sha1: "69554a6",
  74. CommitterEmail: "user2@example.com",
  75. CommitterName: "User2",
  76. AuthorEmail: "user2@example.com",
  77. AuthorName: "User2",
  78. Message: "not signed commit",
  79. },
  80. {
  81. Sha1: "27566bd",
  82. CommitterEmail: "user2@example.com",
  83. CommitterName: "User2",
  84. AuthorEmail: "user2@example.com",
  85. AuthorName: "User2",
  86. Message: "good signed commit (with not yet validated email)",
  87. },
  88. {
  89. Sha1: "5099b81",
  90. CommitterEmail: "user2@example.com",
  91. CommitterName: "User2",
  92. AuthorEmail: "user2@example.com",
  93. AuthorName: "User2",
  94. Message: "good signed commit",
  95. },
  96. }
  97. pushCommits.Len = len(pushCommits.Commits)
  98. repo := AssertExistsAndLoadBean(t, &Repository{ID: 16}).(*Repository)
  99. payloadCommits, err := pushCommits.ToAPIPayloadCommits(repo.RepoPath(), "/user2/repo16")
  100. assert.NoError(t, err)
  101. assert.EqualValues(t, 3, len(payloadCommits))
  102. assert.Equal(t, "69554a6", payloadCommits[0].ID)
  103. assert.Equal(t, "not signed commit", payloadCommits[0].Message)
  104. assert.Equal(t, "/user2/repo16/commit/69554a6", payloadCommits[0].URL)
  105. assert.Equal(t, "User2", payloadCommits[0].Committer.Name)
  106. assert.Equal(t, "user2", payloadCommits[0].Committer.UserName)
  107. assert.Equal(t, "User2", payloadCommits[0].Author.Name)
  108. assert.Equal(t, "user2", payloadCommits[0].Author.UserName)
  109. assert.EqualValues(t, []string{}, payloadCommits[0].Added)
  110. assert.EqualValues(t, []string{}, payloadCommits[0].Removed)
  111. assert.EqualValues(t, []string{"readme.md"}, payloadCommits[0].Modified)
  112. assert.Equal(t, "27566bd", payloadCommits[1].ID)
  113. assert.Equal(t, "good signed commit (with not yet validated email)", payloadCommits[1].Message)
  114. assert.Equal(t, "/user2/repo16/commit/27566bd", payloadCommits[1].URL)
  115. assert.Equal(t, "User2", payloadCommits[1].Committer.Name)
  116. assert.Equal(t, "user2", payloadCommits[1].Committer.UserName)
  117. assert.Equal(t, "User2", payloadCommits[1].Author.Name)
  118. assert.Equal(t, "user2", payloadCommits[1].Author.UserName)
  119. assert.EqualValues(t, []string{}, payloadCommits[1].Added)
  120. assert.EqualValues(t, []string{}, payloadCommits[1].Removed)
  121. assert.EqualValues(t, []string{"readme.md"}, payloadCommits[1].Modified)
  122. assert.Equal(t, "5099b81", payloadCommits[2].ID)
  123. assert.Equal(t, "good signed commit", payloadCommits[2].Message)
  124. assert.Equal(t, "/user2/repo16/commit/5099b81", payloadCommits[2].URL)
  125. assert.Equal(t, "User2", payloadCommits[2].Committer.Name)
  126. assert.Equal(t, "user2", payloadCommits[2].Committer.UserName)
  127. assert.Equal(t, "User2", payloadCommits[2].Author.Name)
  128. assert.Equal(t, "user2", payloadCommits[2].Author.UserName)
  129. assert.EqualValues(t, []string{"readme.md"}, payloadCommits[2].Added)
  130. assert.EqualValues(t, []string{}, payloadCommits[2].Removed)
  131. assert.EqualValues(t, []string{}, payloadCommits[2].Modified)
  132. }
  133. func TestPushCommits_AvatarLink(t *testing.T) {
  134. pushCommits := NewPushCommits()
  135. pushCommits.Commits = []*PushCommit{
  136. {
  137. Sha1: "abcdef1",
  138. CommitterEmail: "user2@example.com",
  139. CommitterName: "User Two",
  140. AuthorEmail: "user4@example.com",
  141. AuthorName: "User Four",
  142. Message: "message1",
  143. },
  144. {
  145. Sha1: "abcdef2",
  146. CommitterEmail: "user2@example.com",
  147. CommitterName: "User Two",
  148. AuthorEmail: "user2@example.com",
  149. AuthorName: "User Two",
  150. Message: "message2",
  151. },
  152. }
  153. pushCommits.Len = len(pushCommits.Commits)
  154. assert.Equal(t,
  155. "https://secure.gravatar.com/avatar/ab53a2911ddf9b4817ac01ddcd3d975f?d=identicon",
  156. pushCommits.AvatarLink("user2@example.com"))
  157. assert.Equal(t,
  158. "https://secure.gravatar.com/avatar/19ade630b94e1e0535b3df7387434154?d=identicon",
  159. pushCommits.AvatarLink("nonexistent@example.com"))
  160. }
  161. func TestRegExp_issueReferenceKeywordsPat(t *testing.T) {
  162. trueTestCases := []string{
  163. "#2",
  164. "[#2]",
  165. "please see go-gitea/gitea#5",
  166. "#2:",
  167. }
  168. falseTestCases := []string{
  169. "kb#2",
  170. "#2xy",
  171. }
  172. for _, testCase := range trueTestCases {
  173. assert.True(t, issueReferenceKeywordsPat.MatchString(testCase))
  174. }
  175. for _, testCase := range falseTestCases {
  176. assert.False(t, issueReferenceKeywordsPat.MatchString(testCase))
  177. }
  178. }
  179. func Test_getIssueFromRef(t *testing.T) {
  180. assert.NoError(t, PrepareTestDatabase())
  181. repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
  182. for _, test := range []struct {
  183. Ref string
  184. ExpectedIssueID int64
  185. }{
  186. {"#2", 2},
  187. {"reopen #2", 2},
  188. {"user2/repo2#1", 4},
  189. {"fixes user2/repo2#1", 4},
  190. {"fixes: user2/repo2#1", 4},
  191. } {
  192. issue, err := getIssueFromRef(repo, test.Ref)
  193. assert.NoError(t, err)
  194. if assert.NotNil(t, issue) {
  195. assert.EqualValues(t, test.ExpectedIssueID, issue.ID)
  196. }
  197. }
  198. for _, badRef := range []string{
  199. "doesnotexist/doesnotexist#1",
  200. fmt.Sprintf("#%d", NonexistentID),
  201. } {
  202. issue, err := getIssueFromRef(repo, badRef)
  203. assert.NoError(t, err)
  204. assert.Nil(t, issue)
  205. }
  206. }
  207. func TestUpdateIssuesCommit(t *testing.T) {
  208. assert.NoError(t, PrepareTestDatabase())
  209. pushCommits := []*PushCommit{
  210. {
  211. Sha1: "abcdef1",
  212. CommitterEmail: "user2@example.com",
  213. CommitterName: "User Two",
  214. AuthorEmail: "user4@example.com",
  215. AuthorName: "User Four",
  216. Message: "start working on #FST-1, #1",
  217. },
  218. {
  219. Sha1: "abcdef2",
  220. CommitterEmail: "user2@example.com",
  221. CommitterName: "User Two",
  222. AuthorEmail: "user2@example.com",
  223. AuthorName: "User Two",
  224. Message: "a plain message",
  225. },
  226. {
  227. Sha1: "abcdef2",
  228. CommitterEmail: "user2@example.com",
  229. CommitterName: "User Two",
  230. AuthorEmail: "user2@example.com",
  231. AuthorName: "User Two",
  232. Message: "close #2",
  233. },
  234. }
  235. user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
  236. repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
  237. repo.Owner = user
  238. commentBean := &Comment{
  239. Type: CommentTypeCommitRef,
  240. CommitSHA: "abcdef1",
  241. PosterID: user.ID,
  242. IssueID: 1,
  243. }
  244. issueBean := &Issue{RepoID: repo.ID, Index: 2}
  245. AssertNotExistsBean(t, commentBean)
  246. AssertNotExistsBean(t, &Issue{RepoID: repo.ID, Index: 2}, "is_closed=1")
  247. assert.NoError(t, UpdateIssuesCommit(user, repo, pushCommits, repo.DefaultBranch))
  248. AssertExistsAndLoadBean(t, commentBean)
  249. AssertExistsAndLoadBean(t, issueBean, "is_closed=1")
  250. CheckConsistencyFor(t, &Action{})
  251. // Test that push to a non-default branch closes no issue.
  252. pushCommits = []*PushCommit{
  253. {
  254. Sha1: "abcdef1",
  255. CommitterEmail: "user2@example.com",
  256. CommitterName: "User Two",
  257. AuthorEmail: "user4@example.com",
  258. AuthorName: "User Four",
  259. Message: "close #1",
  260. },
  261. }
  262. repo = AssertExistsAndLoadBean(t, &Repository{ID: 3}).(*Repository)
  263. commentBean = &Comment{
  264. Type: CommentTypeCommitRef,
  265. CommitSHA: "abcdef1",
  266. PosterID: user.ID,
  267. IssueID: 6,
  268. }
  269. issueBean = &Issue{RepoID: repo.ID, Index: 1}
  270. AssertNotExistsBean(t, commentBean)
  271. AssertNotExistsBean(t, &Issue{RepoID: repo.ID, Index: 1}, "is_closed=1")
  272. assert.NoError(t, UpdateIssuesCommit(user, repo, pushCommits, "non-existing-branch"))
  273. AssertExistsAndLoadBean(t, commentBean)
  274. AssertNotExistsBean(t, issueBean, "is_closed=1")
  275. CheckConsistencyFor(t, &Action{})
  276. }
  277. func TestUpdateIssuesCommit_Colon(t *testing.T) {
  278. assert.NoError(t, PrepareTestDatabase())
  279. pushCommits := []*PushCommit{
  280. {
  281. Sha1: "abcdef2",
  282. CommitterEmail: "user2@example.com",
  283. CommitterName: "User Two",
  284. AuthorEmail: "user2@example.com",
  285. AuthorName: "User Two",
  286. Message: "close: #2",
  287. },
  288. }
  289. user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
  290. repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
  291. repo.Owner = user
  292. issueBean := &Issue{RepoID: repo.ID, Index: 2}
  293. AssertNotExistsBean(t, &Issue{RepoID: repo.ID, Index: 2}, "is_closed=1")
  294. assert.NoError(t, UpdateIssuesCommit(user, repo, pushCommits, repo.DefaultBranch))
  295. AssertExistsAndLoadBean(t, issueBean, "is_closed=1")
  296. CheckConsistencyFor(t, &Action{})
  297. }
  298. func TestUpdateIssuesCommit_Issue5957(t *testing.T) {
  299. assert.NoError(t, PrepareTestDatabase())
  300. user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
  301. // Test that push to a non-default branch closes an issue.
  302. pushCommits := []*PushCommit{
  303. {
  304. Sha1: "abcdef1",
  305. CommitterEmail: "user2@example.com",
  306. CommitterName: "User Two",
  307. AuthorEmail: "user4@example.com",
  308. AuthorName: "User Four",
  309. Message: "close #2",
  310. },
  311. }
  312. repo := AssertExistsAndLoadBean(t, &Repository{ID: 2}).(*Repository)
  313. commentBean := &Comment{
  314. Type: CommentTypeCommitRef,
  315. CommitSHA: "abcdef1",
  316. PosterID: user.ID,
  317. IssueID: 7,
  318. }
  319. issueBean := &Issue{RepoID: repo.ID, Index: 2, ID: 7}
  320. AssertNotExistsBean(t, commentBean)
  321. AssertNotExistsBean(t, issueBean, "is_closed=1")
  322. assert.NoError(t, UpdateIssuesCommit(user, repo, pushCommits, "non-existing-branch"))
  323. AssertExistsAndLoadBean(t, commentBean)
  324. AssertExistsAndLoadBean(t, issueBean, "is_closed=1")
  325. CheckConsistencyFor(t, &Action{})
  326. }
  327. func TestUpdateIssuesCommit_AnotherRepo(t *testing.T) {
  328. assert.NoError(t, PrepareTestDatabase())
  329. user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
  330. // Test that a push to default branch closes issue in another repo
  331. // If the user also has push permissions to that repo
  332. pushCommits := []*PushCommit{
  333. {
  334. Sha1: "abcdef1",
  335. CommitterEmail: "user2@example.com",
  336. CommitterName: "User Two",
  337. AuthorEmail: "user2@example.com",
  338. AuthorName: "User Two",
  339. Message: "close user2/repo1#1",
  340. },
  341. }
  342. repo := AssertExistsAndLoadBean(t, &Repository{ID: 2}).(*Repository)
  343. commentBean := &Comment{
  344. Type: CommentTypeCommitRef,
  345. CommitSHA: "abcdef1",
  346. PosterID: user.ID,
  347. IssueID: 1,
  348. }
  349. issueBean := &Issue{RepoID: 1, Index: 1, ID: 1}
  350. AssertNotExistsBean(t, commentBean)
  351. AssertNotExistsBean(t, issueBean, "is_closed=1")
  352. assert.NoError(t, UpdateIssuesCommit(user, repo, pushCommits, repo.DefaultBranch))
  353. AssertExistsAndLoadBean(t, commentBean)
  354. AssertExistsAndLoadBean(t, issueBean, "is_closed=1")
  355. CheckConsistencyFor(t, &Action{})
  356. }
  357. func TestUpdateIssuesCommit_AnotherRepoNoPermission(t *testing.T) {
  358. assert.NoError(t, PrepareTestDatabase())
  359. user := AssertExistsAndLoadBean(t, &User{ID: 10}).(*User)
  360. // Test that a push with close reference *can not* close issue
  361. // If the commiter doesn't have push rights in that repo
  362. pushCommits := []*PushCommit{
  363. {
  364. Sha1: "abcdef3",
  365. CommitterEmail: "user10@example.com",
  366. CommitterName: "User Ten",
  367. AuthorEmail: "user10@example.com",
  368. AuthorName: "User Ten",
  369. Message: "close user3/repo3#1",
  370. },
  371. }
  372. repo := AssertExistsAndLoadBean(t, &Repository{ID: 6}).(*Repository)
  373. commentBean := &Comment{
  374. Type: CommentTypeCommitRef,
  375. CommitSHA: "abcdef3",
  376. PosterID: user.ID,
  377. IssueID: 6,
  378. }
  379. issueBean := &Issue{RepoID: 3, Index: 1, ID: 6}
  380. AssertNotExistsBean(t, commentBean)
  381. AssertNotExistsBean(t, issueBean, "is_closed=1")
  382. assert.NoError(t, UpdateIssuesCommit(user, repo, pushCommits, repo.DefaultBranch))
  383. AssertExistsAndLoadBean(t, commentBean)
  384. AssertNotExistsBean(t, issueBean, "is_closed=1")
  385. CheckConsistencyFor(t, &Action{})
  386. }
  387. func TestTransferRepoAction(t *testing.T) {
  388. assert.NoError(t, PrepareTestDatabase())
  389. user2 := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
  390. user4 := AssertExistsAndLoadBean(t, &User{ID: 4}).(*User)
  391. repo := AssertExistsAndLoadBean(t, &Repository{ID: 1, OwnerID: user2.ID}).(*Repository)
  392. repo.OwnerID = user4.ID
  393. repo.Owner = user4
  394. actionBean := &Action{
  395. OpType: ActionTransferRepo,
  396. ActUserID: user2.ID,
  397. ActUser: user2,
  398. RepoID: repo.ID,
  399. Repo: repo,
  400. IsPrivate: repo.IsPrivate,
  401. }
  402. AssertNotExistsBean(t, actionBean)
  403. assert.NoError(t, TransferRepoAction(user2, user2, repo))
  404. AssertExistsAndLoadBean(t, actionBean)
  405. _, err := x.ID(repo.ID).Cols("owner_id").Update(repo)
  406. assert.NoError(t, err)
  407. CheckConsistencyFor(t, &Action{})
  408. }
  409. func TestMergePullRequestAction(t *testing.T) {
  410. assert.NoError(t, PrepareTestDatabase())
  411. user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
  412. repo := AssertExistsAndLoadBean(t, &Repository{ID: 1, OwnerID: user.ID}).(*Repository)
  413. repo.Owner = user
  414. issue := AssertExistsAndLoadBean(t, &Issue{ID: 3, RepoID: repo.ID}).(*Issue)
  415. actionBean := &Action{
  416. OpType: ActionMergePullRequest,
  417. ActUserID: user.ID,
  418. ActUser: user,
  419. RepoID: repo.ID,
  420. Repo: repo,
  421. IsPrivate: repo.IsPrivate,
  422. }
  423. AssertNotExistsBean(t, actionBean)
  424. assert.NoError(t, MergePullRequestAction(user, repo, issue))
  425. AssertExistsAndLoadBean(t, actionBean)
  426. CheckConsistencyFor(t, &Action{})
  427. }
  428. func TestGetFeeds(t *testing.T) {
  429. // test with an individual user
  430. assert.NoError(t, PrepareTestDatabase())
  431. user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
  432. actions, err := GetFeeds(GetFeedsOptions{
  433. RequestedUser: user,
  434. RequestingUserID: user.ID,
  435. IncludePrivate: true,
  436. OnlyPerformedBy: false,
  437. IncludeDeleted: true,
  438. })
  439. assert.NoError(t, err)
  440. if assert.Len(t, actions, 1) {
  441. assert.EqualValues(t, 1, actions[0].ID)
  442. assert.EqualValues(t, user.ID, actions[0].UserID)
  443. }
  444. actions, err = GetFeeds(GetFeedsOptions{
  445. RequestedUser: user,
  446. RequestingUserID: user.ID,
  447. IncludePrivate: false,
  448. OnlyPerformedBy: false,
  449. })
  450. assert.NoError(t, err)
  451. assert.Len(t, actions, 0)
  452. }
  453. func TestGetFeeds2(t *testing.T) {
  454. // test with an organization user
  455. assert.NoError(t, PrepareTestDatabase())
  456. org := AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
  457. const userID = 2 // user2 is an owner of the organization
  458. actions, err := GetFeeds(GetFeedsOptions{
  459. RequestedUser: org,
  460. RequestingUserID: userID,
  461. IncludePrivate: true,
  462. OnlyPerformedBy: false,
  463. IncludeDeleted: true,
  464. })
  465. assert.NoError(t, err)
  466. assert.Len(t, actions, 1)
  467. if assert.Len(t, actions, 1) {
  468. assert.EqualValues(t, 2, actions[0].ID)
  469. assert.EqualValues(t, org.ID, actions[0].UserID)
  470. }
  471. actions, err = GetFeeds(GetFeedsOptions{
  472. RequestedUser: org,
  473. RequestingUserID: userID,
  474. IncludePrivate: false,
  475. OnlyPerformedBy: false,
  476. IncludeDeleted: true,
  477. })
  478. assert.NoError(t, err)
  479. assert.Len(t, actions, 0)
  480. }