actions_test.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880
  1. // Copyright 2022 The Gogs 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 and LICENSE.gogs file.
  4. // Copyright 2025 Huan-Gogs Authors. All rights reserved.
  5. // Use of this source code is governed by a MIT-style
  6. // license that can be found in the LICENSE file.
  7. package database
  8. import (
  9. "context"
  10. "os"
  11. "testing"
  12. "time"
  13. "github.com/gogs/git-module"
  14. "github.com/stretchr/testify/assert"
  15. "github.com/stretchr/testify/require"
  16. "gorm.io/gorm"
  17. "github.com/SongZihuan/huan-gogs/internal/conf"
  18. )
  19. func TestIssueReferencePattern(t *testing.T) {
  20. tests := []struct {
  21. name string
  22. message string
  23. want []string
  24. }{
  25. {
  26. name: "no match",
  27. message: "Hello world!",
  28. want: nil,
  29. },
  30. {
  31. name: "contains issue numbers",
  32. message: "#123 is fixed, and #456 is WIP",
  33. want: []string{"#123", " #456"},
  34. },
  35. {
  36. name: "contains full issue references",
  37. message: "#123 is fixed, and user/repo#456 is WIP",
  38. want: []string{"#123", " user/repo#456"},
  39. },
  40. }
  41. for _, test := range tests {
  42. t.Run(test.name, func(t *testing.T) {
  43. got := issueReferencePattern.FindAllString(test.message, -1)
  44. assert.Equal(t, test.want, got)
  45. })
  46. }
  47. }
  48. func TestAction_BeforeCreate(t *testing.T) {
  49. now := time.Now()
  50. db := &gorm.DB{
  51. Config: &gorm.Config{
  52. SkipDefaultTransaction: true,
  53. NowFunc: func() time.Time {
  54. return now
  55. },
  56. },
  57. }
  58. t.Run("CreatedUnix has been set", func(t *testing.T) {
  59. action := &Action{
  60. CreatedUnix: 1,
  61. }
  62. _ = action.BeforeCreate(db)
  63. assert.Equal(t, int64(1), action.CreatedUnix)
  64. })
  65. t.Run("CreatedUnix has not been set", func(t *testing.T) {
  66. action := &Action{}
  67. _ = action.BeforeCreate(db)
  68. assert.Equal(t, db.NowFunc().Unix(), action.CreatedUnix)
  69. })
  70. }
  71. func TestAction_AfterFind(t *testing.T) {
  72. now := time.Now()
  73. db := &gorm.DB{
  74. Config: &gorm.Config{
  75. SkipDefaultTransaction: true,
  76. NowFunc: func() time.Time {
  77. return now
  78. },
  79. },
  80. }
  81. action := &Action{
  82. CreatedUnix: now.Unix(),
  83. }
  84. _ = action.AfterFind(db)
  85. assert.Equal(t, action.CreatedUnix, action.Created.Unix())
  86. }
  87. func TestActions(t *testing.T) {
  88. if testing.Short() {
  89. t.Skip()
  90. }
  91. ctx := context.Background()
  92. t.Parallel()
  93. s := &ActionsStore{
  94. db: newTestDB(t, "ActionsStore"),
  95. }
  96. for _, tc := range []struct {
  97. name string
  98. test func(t *testing.T, ctx context.Context, s *ActionsStore)
  99. }{
  100. {"CommitRepo", actionsCommitRepo},
  101. {"ListByOrganization", actionsListByOrganization},
  102. {"ListByUser", actionsListByUser},
  103. {"MergePullRequest", actionsMergePullRequest},
  104. {"MirrorSyncCreate", actionsMirrorSyncCreate},
  105. {"MirrorSyncDelete", actionsMirrorSyncDelete},
  106. {"MirrorSyncPush", actionsMirrorSyncPush},
  107. {"NewRepo", actionsNewRepo},
  108. {"PushTag", actionsPushTag},
  109. {"RenameRepo", actionsRenameRepo},
  110. {"TransferRepo", actionsTransferRepo},
  111. } {
  112. t.Run(tc.name, func(t *testing.T) {
  113. t.Cleanup(func() {
  114. err := clearTables(t, s.db)
  115. require.NoError(t, err)
  116. })
  117. tc.test(t, ctx, s)
  118. })
  119. if t.Failed() {
  120. break
  121. }
  122. }
  123. }
  124. func actionsCommitRepo(t *testing.T, ctx context.Context, s *ActionsStore) {
  125. alice, err := newUsersStore(s.db).Create(ctx, "alice", "alice@example.com", CreateUserOptions{})
  126. require.NoError(t, err)
  127. repo, err := newReposStore(s.db).Create(ctx,
  128. alice.ID,
  129. CreateRepoOptions{
  130. Name: "example",
  131. },
  132. )
  133. require.NoError(t, err)
  134. now := time.Unix(1588568886, 0).UTC()
  135. conf.SetMockSSH(t, conf.SSHOpts{})
  136. t.Run("new commit", func(t *testing.T) {
  137. t.Cleanup(func() {
  138. err := s.db.Session(&gorm.Session{AllowGlobalUpdate: true}).WithContext(ctx).Delete(new(Action)).Error
  139. require.NoError(t, err)
  140. })
  141. err = s.CommitRepo(ctx,
  142. CommitRepoOptions{
  143. PusherName: alice.Name,
  144. Owner: alice,
  145. Repo: repo,
  146. RefFullName: "refs/heads/main",
  147. OldCommitID: "ca82a6dff817ec66f44342007202690a93763949",
  148. NewCommitID: "085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7",
  149. Commits: CommitsToPushCommits(
  150. []*git.Commit{
  151. {
  152. ID: git.MustIDFromString("085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7"),
  153. Author: &git.Signature{
  154. Name: "alice",
  155. Email: "alice@example.com",
  156. When: now,
  157. },
  158. Committer: &git.Signature{
  159. Name: "alice",
  160. Email: "alice@example.com",
  161. When: now,
  162. },
  163. Message: "A random commit",
  164. },
  165. },
  166. ),
  167. },
  168. )
  169. require.NoError(t, err)
  170. got, err := s.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  171. require.NoError(t, err)
  172. require.Len(t, got, 1)
  173. got[0].ID = 0
  174. want := []*Action{
  175. {
  176. UserID: alice.ID,
  177. OpType: ActionCommitRepo,
  178. ActUserID: alice.ID,
  179. ActUserName: alice.Name,
  180. RepoID: repo.ID,
  181. RepoUserName: alice.Name,
  182. RepoName: repo.Name,
  183. RefName: "main",
  184. IsPrivate: false,
  185. Content: `{"Len":1,"Commits":[{"Sha1":"085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7","Message":"A random commit","AuthorEmail":"alice@example.com","AuthorName":"alice","CommitterEmail":"alice@example.com","CommitterName":"alice","Timestamp":"2020-05-04T05:08:06Z"}],"CompareURL":"alice/example/compare/ca82a6dff817ec66f44342007202690a93763949...085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7"}`,
  186. CreatedUnix: s.db.NowFunc().Unix(),
  187. },
  188. }
  189. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  190. assert.Equal(t, want, got)
  191. })
  192. t.Run("new ref", func(t *testing.T) {
  193. t.Cleanup(func() {
  194. err := s.db.Session(&gorm.Session{AllowGlobalUpdate: true}).WithContext(ctx).Delete(new(Action)).Error
  195. require.NoError(t, err)
  196. })
  197. err = s.CommitRepo(ctx,
  198. CommitRepoOptions{
  199. PusherName: alice.Name,
  200. Owner: alice,
  201. Repo: repo,
  202. RefFullName: "refs/heads/main",
  203. OldCommitID: git.EmptyID,
  204. NewCommitID: "085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7",
  205. Commits: CommitsToPushCommits(
  206. []*git.Commit{
  207. {
  208. ID: git.MustIDFromString("085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7"),
  209. Author: &git.Signature{
  210. Name: "alice",
  211. Email: "alice@example.com",
  212. When: now,
  213. },
  214. Committer: &git.Signature{
  215. Name: "alice",
  216. Email: "alice@example.com",
  217. When: now,
  218. },
  219. Message: "A random commit",
  220. },
  221. },
  222. ),
  223. },
  224. )
  225. require.NoError(t, err)
  226. got, err := s.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  227. require.NoError(t, err)
  228. require.Len(t, got, 2)
  229. got[0].ID = 0
  230. got[1].ID = 0
  231. want := []*Action{
  232. {
  233. UserID: alice.ID,
  234. OpType: ActionCommitRepo,
  235. ActUserID: alice.ID,
  236. ActUserName: alice.Name,
  237. RepoID: repo.ID,
  238. RepoUserName: alice.Name,
  239. RepoName: repo.Name,
  240. RefName: "main",
  241. IsPrivate: false,
  242. Content: `{"Len":1,"Commits":[{"Sha1":"085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7","Message":"A random commit","AuthorEmail":"alice@example.com","AuthorName":"alice","CommitterEmail":"alice@example.com","CommitterName":"alice","Timestamp":"2020-05-04T05:08:06Z"}],"CompareURL":""}`,
  243. CreatedUnix: s.db.NowFunc().Unix(),
  244. },
  245. {
  246. UserID: alice.ID,
  247. OpType: ActionCreateBranch,
  248. ActUserID: alice.ID,
  249. ActUserName: alice.Name,
  250. RepoID: repo.ID,
  251. RepoUserName: alice.Name,
  252. RepoName: repo.Name,
  253. RefName: "main",
  254. IsPrivate: false,
  255. Content: `{"Len":1,"Commits":[{"Sha1":"085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7","Message":"A random commit","AuthorEmail":"alice@example.com","AuthorName":"alice","CommitterEmail":"alice@example.com","CommitterName":"alice","Timestamp":"2020-05-04T05:08:06Z"}],"CompareURL":""}`,
  256. CreatedUnix: s.db.NowFunc().Unix(),
  257. },
  258. }
  259. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  260. want[1].Created = time.Unix(want[1].CreatedUnix, 0)
  261. assert.Equal(t, want, got)
  262. })
  263. t.Run("delete ref", func(t *testing.T) {
  264. t.Cleanup(func() {
  265. err := s.db.Session(&gorm.Session{AllowGlobalUpdate: true}).WithContext(ctx).Delete(new(Action)).Error
  266. require.NoError(t, err)
  267. })
  268. err = s.CommitRepo(ctx,
  269. CommitRepoOptions{
  270. PusherName: alice.Name,
  271. Owner: alice,
  272. Repo: repo,
  273. RefFullName: "refs/heads/main",
  274. OldCommitID: "ca82a6dff817ec66f44342007202690a93763949",
  275. NewCommitID: git.EmptyID,
  276. },
  277. )
  278. require.NoError(t, err)
  279. got, err := s.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  280. require.NoError(t, err)
  281. require.Len(t, got, 1)
  282. got[0].ID = 0
  283. want := []*Action{
  284. {
  285. UserID: alice.ID,
  286. OpType: ActionDeleteBranch,
  287. ActUserID: alice.ID,
  288. ActUserName: alice.Name,
  289. RepoID: repo.ID,
  290. RepoUserName: alice.Name,
  291. RepoName: repo.Name,
  292. RefName: "main",
  293. IsPrivate: false,
  294. CreatedUnix: s.db.NowFunc().Unix(),
  295. },
  296. }
  297. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  298. assert.Equal(t, want, got)
  299. })
  300. }
  301. func actionsListByOrganization(t *testing.T, ctx context.Context, s *ActionsStore) {
  302. if os.Getenv("GOGS_DATABASE_TYPE") != "postgres" {
  303. t.Skip("Skipping testing with not using PostgreSQL")
  304. return
  305. }
  306. conf.SetMockUI(t,
  307. conf.UIOpts{
  308. User: conf.UIUserOpts{
  309. NewsFeedPagingNum: 20,
  310. },
  311. },
  312. )
  313. tests := []struct {
  314. name string
  315. orgID int64
  316. actorID int64
  317. afterID int64
  318. want string
  319. }{
  320. {
  321. name: "no afterID",
  322. orgID: 1,
  323. actorID: 1,
  324. afterID: 0,
  325. want: `SELECT * FROM "action" WHERE user_id = 1 AND (true OR id < 0) AND repo_id IN (SELECT repository.id FROM "repository" JOIN team_repo ON repository.id = team_repo.repo_id WHERE team_repo.team_id IN (SELECT team_id FROM "team_user" WHERE team_user.org_id = 1 AND uid = 1) OR (repository.is_private = false AND repository.is_unlisted = false)) ORDER BY id DESC LIMIT 20`,
  326. },
  327. {
  328. name: "has afterID",
  329. orgID: 1,
  330. actorID: 1,
  331. afterID: 5,
  332. want: `SELECT * FROM "action" WHERE user_id = 1 AND (false OR id < 5) AND repo_id IN (SELECT repository.id FROM "repository" JOIN team_repo ON repository.id = team_repo.repo_id WHERE team_repo.team_id IN (SELECT team_id FROM "team_user" WHERE team_user.org_id = 1 AND uid = 1) OR (repository.is_private = false AND repository.is_unlisted = false)) ORDER BY id DESC LIMIT 20`,
  333. },
  334. }
  335. for _, test := range tests {
  336. t.Run(test.name, func(t *testing.T) {
  337. got := s.db.ToSQL(func(tx *gorm.DB) *gorm.DB {
  338. return newActionsStore(tx).listByOrganization(ctx, test.orgID, test.actorID, test.afterID).Find(new(Action))
  339. })
  340. assert.Equal(t, test.want, got)
  341. })
  342. }
  343. }
  344. func actionsListByUser(t *testing.T, ctx context.Context, s *ActionsStore) {
  345. if os.Getenv("GOGS_DATABASE_TYPE") != "postgres" {
  346. t.Skip("Skipping testing with not using PostgreSQL")
  347. return
  348. }
  349. conf.SetMockUI(t,
  350. conf.UIOpts{
  351. User: conf.UIUserOpts{
  352. NewsFeedPagingNum: 20,
  353. },
  354. },
  355. )
  356. tests := []struct {
  357. name string
  358. userID int64
  359. actorID int64
  360. afterID int64
  361. isProfile bool
  362. want string
  363. }{
  364. {
  365. name: "same user no afterID not in profile",
  366. userID: 1,
  367. actorID: 1,
  368. afterID: 0,
  369. isProfile: false,
  370. want: `SELECT * FROM "action" WHERE user_id = 1 AND (true OR id < 0) AND (true OR (is_private = false AND act_user_id = 1)) ORDER BY id DESC LIMIT 20`,
  371. },
  372. {
  373. name: "same user no afterID in profile",
  374. userID: 1,
  375. actorID: 1,
  376. afterID: 0,
  377. isProfile: true,
  378. want: `SELECT * FROM "action" WHERE user_id = 1 AND (true OR id < 0) AND (true OR (is_private = false AND act_user_id = 1)) ORDER BY id DESC LIMIT 20`,
  379. },
  380. {
  381. name: "same user has afterID not in profile",
  382. userID: 1,
  383. actorID: 1,
  384. afterID: 5,
  385. isProfile: false,
  386. want: `SELECT * FROM "action" WHERE user_id = 1 AND (false OR id < 5) AND (true OR (is_private = false AND act_user_id = 1)) ORDER BY id DESC LIMIT 20`,
  387. },
  388. {
  389. name: "different user no afterID in profile",
  390. userID: 1,
  391. actorID: 2,
  392. afterID: 0,
  393. isProfile: true,
  394. want: `SELECT * FROM "action" WHERE user_id = 1 AND (true OR id < 0) AND (false OR (is_private = false AND act_user_id = 1)) ORDER BY id DESC LIMIT 20`,
  395. },
  396. }
  397. for _, test := range tests {
  398. t.Run(test.name, func(t *testing.T) {
  399. got := s.db.ToSQL(func(tx *gorm.DB) *gorm.DB {
  400. return newActionsStore(tx).listByUser(ctx, test.userID, test.actorID, test.afterID, test.isProfile).Find(new(Action))
  401. })
  402. assert.Equal(t, test.want, got)
  403. })
  404. }
  405. }
  406. func actionsMergePullRequest(t *testing.T, ctx context.Context, s *ActionsStore) {
  407. alice, err := newUsersStore(s.db).Create(ctx, "alice", "alice@example.com", CreateUserOptions{})
  408. require.NoError(t, err)
  409. repo, err := newReposStore(s.db).Create(ctx,
  410. alice.ID,
  411. CreateRepoOptions{
  412. Name: "example",
  413. },
  414. )
  415. require.NoError(t, err)
  416. err = s.MergePullRequest(ctx,
  417. alice,
  418. alice,
  419. repo,
  420. &Issue{
  421. Index: 1,
  422. Title: "Fix issue 1",
  423. },
  424. )
  425. require.NoError(t, err)
  426. got, err := s.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  427. require.NoError(t, err)
  428. require.Len(t, got, 1)
  429. got[0].ID = 0
  430. want := []*Action{
  431. {
  432. UserID: alice.ID,
  433. OpType: ActionMergePullRequest,
  434. ActUserID: alice.ID,
  435. ActUserName: alice.Name,
  436. RepoID: repo.ID,
  437. RepoUserName: alice.Name,
  438. RepoName: repo.Name,
  439. IsPrivate: false,
  440. Content: `1|Fix issue 1`,
  441. CreatedUnix: s.db.NowFunc().Unix(),
  442. },
  443. }
  444. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  445. assert.Equal(t, want, got)
  446. }
  447. func actionsMirrorSyncCreate(t *testing.T, ctx context.Context, s *ActionsStore) {
  448. alice, err := newUsersStore(s.db).Create(ctx, "alice", "alice@example.com", CreateUserOptions{})
  449. require.NoError(t, err)
  450. repo, err := newReposStore(s.db).Create(ctx,
  451. alice.ID,
  452. CreateRepoOptions{
  453. Name: "example",
  454. },
  455. )
  456. require.NoError(t, err)
  457. err = s.MirrorSyncCreate(ctx,
  458. alice,
  459. repo,
  460. "main",
  461. )
  462. require.NoError(t, err)
  463. got, err := s.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  464. require.NoError(t, err)
  465. require.Len(t, got, 1)
  466. got[0].ID = 0
  467. want := []*Action{
  468. {
  469. UserID: alice.ID,
  470. OpType: ActionMirrorSyncCreate,
  471. ActUserID: alice.ID,
  472. ActUserName: alice.Name,
  473. RepoID: repo.ID,
  474. RepoUserName: alice.Name,
  475. RepoName: repo.Name,
  476. RefName: "main",
  477. IsPrivate: false,
  478. CreatedUnix: s.db.NowFunc().Unix(),
  479. },
  480. }
  481. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  482. assert.Equal(t, want, got)
  483. }
  484. func actionsMirrorSyncDelete(t *testing.T, ctx context.Context, s *ActionsStore) {
  485. alice, err := newUsersStore(s.db).Create(ctx, "alice", "alice@example.com", CreateUserOptions{})
  486. require.NoError(t, err)
  487. repo, err := newReposStore(s.db).Create(ctx,
  488. alice.ID,
  489. CreateRepoOptions{
  490. Name: "example",
  491. },
  492. )
  493. require.NoError(t, err)
  494. err = s.MirrorSyncDelete(ctx,
  495. alice,
  496. repo,
  497. "main",
  498. )
  499. require.NoError(t, err)
  500. got, err := s.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  501. require.NoError(t, err)
  502. require.Len(t, got, 1)
  503. got[0].ID = 0
  504. want := []*Action{
  505. {
  506. UserID: alice.ID,
  507. OpType: ActionMirrorSyncDelete,
  508. ActUserID: alice.ID,
  509. ActUserName: alice.Name,
  510. RepoID: repo.ID,
  511. RepoUserName: alice.Name,
  512. RepoName: repo.Name,
  513. RefName: "main",
  514. IsPrivate: false,
  515. CreatedUnix: s.db.NowFunc().Unix(),
  516. },
  517. }
  518. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  519. assert.Equal(t, want, got)
  520. }
  521. func actionsMirrorSyncPush(t *testing.T, ctx context.Context, s *ActionsStore) {
  522. alice, err := newUsersStore(s.db).Create(ctx, "alice", "alice@example.com", CreateUserOptions{})
  523. require.NoError(t, err)
  524. repo, err := newReposStore(s.db).Create(ctx,
  525. alice.ID,
  526. CreateRepoOptions{
  527. Name: "example",
  528. },
  529. )
  530. require.NoError(t, err)
  531. now := time.Unix(1588568886, 0).UTC()
  532. err = s.MirrorSyncPush(ctx,
  533. MirrorSyncPushOptions{
  534. Owner: alice,
  535. Repo: repo,
  536. RefName: "main",
  537. OldCommitID: "ca82a6dff817ec66f44342007202690a93763949",
  538. NewCommitID: "085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7",
  539. Commits: CommitsToPushCommits(
  540. []*git.Commit{
  541. {
  542. ID: git.MustIDFromString("085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7"),
  543. Author: &git.Signature{
  544. Name: "alice",
  545. Email: "alice@example.com",
  546. When: now,
  547. },
  548. Committer: &git.Signature{
  549. Name: "alice",
  550. Email: "alice@example.com",
  551. When: now,
  552. },
  553. Message: "A random commit",
  554. },
  555. },
  556. ),
  557. },
  558. )
  559. require.NoError(t, err)
  560. got, err := s.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  561. require.NoError(t, err)
  562. require.Len(t, got, 1)
  563. got[0].ID = 0
  564. want := []*Action{
  565. {
  566. UserID: alice.ID,
  567. OpType: ActionMirrorSyncPush,
  568. ActUserID: alice.ID,
  569. ActUserName: alice.Name,
  570. RepoID: repo.ID,
  571. RepoUserName: alice.Name,
  572. RepoName: repo.Name,
  573. RefName: "main",
  574. IsPrivate: false,
  575. Content: `{"Len":1,"Commits":[{"Sha1":"085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7","Message":"A random commit","AuthorEmail":"alice@example.com","AuthorName":"alice","CommitterEmail":"alice@example.com","CommitterName":"alice","Timestamp":"2020-05-04T05:08:06Z"}],"CompareURL":"alice/example/compare/ca82a6dff817ec66f44342007202690a93763949...085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7"}`,
  576. CreatedUnix: s.db.NowFunc().Unix(),
  577. },
  578. }
  579. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  580. assert.Equal(t, want, got)
  581. }
  582. func actionsNewRepo(t *testing.T, ctx context.Context, s *ActionsStore) {
  583. alice, err := newUsersStore(s.db).Create(ctx, "alice", "alice@example.com", CreateUserOptions{})
  584. require.NoError(t, err)
  585. repo, err := newReposStore(s.db).Create(ctx,
  586. alice.ID,
  587. CreateRepoOptions{
  588. Name: "example",
  589. },
  590. )
  591. require.NoError(t, err)
  592. t.Run("new repo", func(t *testing.T) {
  593. t.Cleanup(func() {
  594. err := s.db.Session(&gorm.Session{AllowGlobalUpdate: true}).WithContext(ctx).Delete(new(Action)).Error
  595. require.NoError(t, err)
  596. })
  597. err = s.NewRepo(ctx, alice, alice, repo)
  598. require.NoError(t, err)
  599. got, err := s.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  600. require.NoError(t, err)
  601. require.Len(t, got, 1)
  602. got[0].ID = 0
  603. want := []*Action{
  604. {
  605. UserID: alice.ID,
  606. OpType: ActionCreateRepo,
  607. ActUserID: alice.ID,
  608. ActUserName: alice.Name,
  609. RepoID: repo.ID,
  610. RepoUserName: alice.Name,
  611. RepoName: repo.Name,
  612. IsPrivate: false,
  613. CreatedUnix: s.db.NowFunc().Unix(),
  614. },
  615. }
  616. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  617. assert.Equal(t, want, got)
  618. })
  619. t.Run("fork repo", func(t *testing.T) {
  620. t.Cleanup(func() {
  621. err := s.db.Session(&gorm.Session{AllowGlobalUpdate: true}).WithContext(ctx).Delete(new(Action)).Error
  622. require.NoError(t, err)
  623. })
  624. repo.IsFork = true
  625. err = s.NewRepo(ctx, alice, alice, repo)
  626. require.NoError(t, err)
  627. got, err := s.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  628. require.NoError(t, err)
  629. require.Len(t, got, 1)
  630. got[0].ID = 0
  631. want := []*Action{
  632. {
  633. UserID: alice.ID,
  634. OpType: ActionForkRepo,
  635. ActUserID: alice.ID,
  636. ActUserName: alice.Name,
  637. RepoID: repo.ID,
  638. RepoUserName: alice.Name,
  639. RepoName: repo.Name,
  640. IsPrivate: false,
  641. CreatedUnix: s.db.NowFunc().Unix(),
  642. },
  643. }
  644. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  645. assert.Equal(t, want, got)
  646. })
  647. }
  648. func actionsPushTag(t *testing.T, ctx context.Context, s *ActionsStore) {
  649. // NOTE: We set a noop mock here to avoid data race with other tests that writes
  650. // to the mock server because this function holds a lock.
  651. conf.SetMockServer(t, conf.ServerOpts{})
  652. conf.SetMockSSH(t, conf.SSHOpts{})
  653. alice, err := newUsersStore(s.db).Create(ctx, "alice", "alice@example.com", CreateUserOptions{})
  654. require.NoError(t, err)
  655. repo, err := newReposStore(s.db).Create(ctx,
  656. alice.ID,
  657. CreateRepoOptions{
  658. Name: "example",
  659. },
  660. )
  661. require.NoError(t, err)
  662. t.Run("new tag", func(t *testing.T) {
  663. t.Cleanup(func() {
  664. err := s.db.Session(&gorm.Session{AllowGlobalUpdate: true}).WithContext(ctx).Delete(new(Action)).Error
  665. require.NoError(t, err)
  666. })
  667. err = s.PushTag(ctx,
  668. PushTagOptions{
  669. Owner: alice,
  670. Repo: repo,
  671. PusherName: alice.Name,
  672. RefFullName: "refs/tags/v1.0.0",
  673. NewCommitID: "085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7",
  674. },
  675. )
  676. require.NoError(t, err)
  677. got, err := s.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  678. require.NoError(t, err)
  679. require.Len(t, got, 1)
  680. got[0].ID = 0
  681. want := []*Action{
  682. {
  683. UserID: alice.ID,
  684. OpType: ActionPushTag,
  685. ActUserID: alice.ID,
  686. ActUserName: alice.Name,
  687. RepoID: repo.ID,
  688. RepoUserName: alice.Name,
  689. RepoName: repo.Name,
  690. RefName: "v1.0.0",
  691. IsPrivate: false,
  692. CreatedUnix: s.db.NowFunc().Unix(),
  693. },
  694. }
  695. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  696. assert.Equal(t, want, got)
  697. })
  698. t.Run("delete tag", func(t *testing.T) {
  699. t.Cleanup(func() {
  700. err := s.db.Session(&gorm.Session{AllowGlobalUpdate: true}).WithContext(ctx).Delete(new(Action)).Error
  701. require.NoError(t, err)
  702. })
  703. err = s.PushTag(ctx,
  704. PushTagOptions{
  705. Owner: alice,
  706. Repo: repo,
  707. PusherName: alice.Name,
  708. RefFullName: "refs/tags/v1.0.0",
  709. NewCommitID: git.EmptyID,
  710. },
  711. )
  712. require.NoError(t, err)
  713. got, err := s.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  714. require.NoError(t, err)
  715. require.Len(t, got, 1)
  716. got[0].ID = 0
  717. want := []*Action{
  718. {
  719. UserID: alice.ID,
  720. OpType: ActionDeleteTag,
  721. ActUserID: alice.ID,
  722. ActUserName: alice.Name,
  723. RepoID: repo.ID,
  724. RepoUserName: alice.Name,
  725. RepoName: repo.Name,
  726. RefName: "v1.0.0",
  727. IsPrivate: false,
  728. CreatedUnix: s.db.NowFunc().Unix(),
  729. },
  730. }
  731. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  732. assert.Equal(t, want, got)
  733. })
  734. }
  735. func actionsRenameRepo(t *testing.T, ctx context.Context, s *ActionsStore) {
  736. alice, err := newUsersStore(s.db).Create(ctx, "alice", "alice@example.com", CreateUserOptions{})
  737. require.NoError(t, err)
  738. repo, err := newReposStore(s.db).Create(ctx,
  739. alice.ID,
  740. CreateRepoOptions{
  741. Name: "example",
  742. },
  743. )
  744. require.NoError(t, err)
  745. err = s.RenameRepo(ctx, alice, alice, "oldExample", repo)
  746. require.NoError(t, err)
  747. got, err := s.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  748. require.NoError(t, err)
  749. require.Len(t, got, 1)
  750. got[0].ID = 0
  751. want := []*Action{
  752. {
  753. UserID: alice.ID,
  754. OpType: ActionRenameRepo,
  755. ActUserID: alice.ID,
  756. ActUserName: alice.Name,
  757. RepoID: repo.ID,
  758. RepoUserName: alice.Name,
  759. RepoName: repo.Name,
  760. IsPrivate: false,
  761. Content: "oldExample",
  762. CreatedUnix: s.db.NowFunc().Unix(),
  763. },
  764. }
  765. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  766. assert.Equal(t, want, got)
  767. }
  768. func actionsTransferRepo(t *testing.T, ctx context.Context, s *ActionsStore) {
  769. alice, err := newUsersStore(s.db).Create(ctx, "alice", "alice@example.com", CreateUserOptions{})
  770. require.NoError(t, err)
  771. bob, err := newUsersStore(s.db).Create(ctx, "bob", "bob@example.com", CreateUserOptions{})
  772. require.NoError(t, err)
  773. repo, err := newReposStore(s.db).Create(ctx,
  774. alice.ID,
  775. CreateRepoOptions{
  776. Name: "example",
  777. },
  778. )
  779. require.NoError(t, err)
  780. err = s.TransferRepo(ctx, alice, alice, bob, repo)
  781. require.NoError(t, err)
  782. got, err := s.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  783. require.NoError(t, err)
  784. require.Len(t, got, 1)
  785. got[0].ID = 0
  786. want := []*Action{
  787. {
  788. UserID: alice.ID,
  789. OpType: ActionTransferRepo,
  790. ActUserID: alice.ID,
  791. ActUserName: alice.Name,
  792. RepoID: repo.ID,
  793. RepoUserName: bob.Name,
  794. RepoName: repo.Name,
  795. IsPrivate: false,
  796. Content: "alice/example",
  797. CreatedUnix: s.db.NowFunc().Unix(),
  798. },
  799. }
  800. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  801. assert.Equal(t, want, got)
  802. }