actions_test.go 23 KB

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