actions_test.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898
  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. t.Parallel()
  90. tables := []any{new(Action), new(User), new(Repository), new(EmailAddress), new(Watch)}
  91. db := &actions{
  92. DB: dbtest.NewDB(t, "actions", tables...),
  93. }
  94. for _, tc := range []struct {
  95. name string
  96. test func(t *testing.T, db *actions)
  97. }{
  98. {"CommitRepo", actionsCommitRepo},
  99. {"ListByOrganization", actionsListByOrganization},
  100. {"ListByUser", actionsListByUser},
  101. {"MergePullRequest", actionsMergePullRequest},
  102. {"MirrorSyncCreate", actionsMirrorSyncCreate},
  103. {"MirrorSyncDelete", actionsMirrorSyncDelete},
  104. {"MirrorSyncPush", actionsMirrorSyncPush},
  105. {"NewRepo", actionsNewRepo},
  106. {"PushTag", actionsPushTag},
  107. {"RenameRepo", actionsRenameRepo},
  108. {"TransferRepo", actionsTransferRepo},
  109. } {
  110. t.Run(tc.name, func(t *testing.T) {
  111. t.Cleanup(func() {
  112. err := clearTables(t, db.DB, tables...)
  113. require.NoError(t, err)
  114. })
  115. tc.test(t, db)
  116. })
  117. if t.Failed() {
  118. break
  119. }
  120. }
  121. }
  122. func actionsCommitRepo(t *testing.T, db *actions) {
  123. ctx := context.Background()
  124. alice, err := NewUsersStore(db.DB).Create(ctx, "alice", "[email protected]", CreateUserOptions{})
  125. require.NoError(t, err)
  126. repo, err := NewReposStore(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: "[email protected]",
  155. When: now,
  156. },
  157. Committer: &git.Signature{
  158. Name: "alice",
  159. Email: "[email protected]",
  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":"[email protected]","AuthorName":"alice","CommitterEmail":"[email protected]","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: "[email protected]",
  211. When: now,
  212. },
  213. Committer: &git.Signature{
  214. Name: "alice",
  215. Email: "[email protected]",
  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":"[email protected]","AuthorName":"alice","CommitterEmail":"[email protected]","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":"[email protected]","AuthorName":"alice","CommitterEmail":"[email protected]","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, db *actions) {
  301. if os.Getenv("GOGS_DATABASE_TYPE") != "postgres" {
  302. t.Skip("Skipping testing with not using PostgreSQL")
  303. return
  304. }
  305. ctx := context.Background()
  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 := db.DB.ToSQL(func(tx *gorm.DB) *gorm.DB {
  338. return NewActionsStore(tx).(*actions).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, db *actions) {
  345. if os.Getenv("GOGS_DATABASE_TYPE") != "postgres" {
  346. t.Skip("Skipping testing with not using PostgreSQL")
  347. return
  348. }
  349. ctx := context.Background()
  350. conf.SetMockUI(t,
  351. conf.UIOpts{
  352. User: conf.UIUserOpts{
  353. NewsFeedPagingNum: 20,
  354. },
  355. },
  356. )
  357. tests := []struct {
  358. name string
  359. userID int64
  360. actorID int64
  361. afterID int64
  362. isProfile bool
  363. want string
  364. }{
  365. {
  366. name: "same user no afterID not in profile",
  367. userID: 1,
  368. actorID: 1,
  369. afterID: 0,
  370. isProfile: false,
  371. 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`,
  372. },
  373. {
  374. name: "same user no afterID in profile",
  375. userID: 1,
  376. actorID: 1,
  377. afterID: 0,
  378. isProfile: true,
  379. 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`,
  380. },
  381. {
  382. name: "same user has afterID not in profile",
  383. userID: 1,
  384. actorID: 1,
  385. afterID: 5,
  386. isProfile: false,
  387. 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`,
  388. },
  389. {
  390. name: "different user no afterID in profile",
  391. userID: 1,
  392. actorID: 2,
  393. afterID: 0,
  394. isProfile: true,
  395. 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`,
  396. },
  397. }
  398. for _, test := range tests {
  399. t.Run(test.name, func(t *testing.T) {
  400. got := db.DB.ToSQL(func(tx *gorm.DB) *gorm.DB {
  401. return NewActionsStore(tx).(*actions).listByUser(ctx, test.userID, test.actorID, test.afterID, test.isProfile).Find(new(Action))
  402. })
  403. assert.Equal(t, test.want, got)
  404. })
  405. }
  406. }
  407. func actionsMergePullRequest(t *testing.T, db *actions) {
  408. ctx := context.Background()
  409. alice, err := NewUsersStore(db.DB).Create(ctx, "alice", "[email protected]", CreateUserOptions{})
  410. require.NoError(t, err)
  411. repo, err := NewReposStore(db.DB).Create(ctx,
  412. alice.ID,
  413. CreateRepoOptions{
  414. Name: "example",
  415. },
  416. )
  417. require.NoError(t, err)
  418. err = db.MergePullRequest(ctx,
  419. alice,
  420. alice,
  421. repo,
  422. &Issue{
  423. Index: 1,
  424. Title: "Fix issue 1",
  425. },
  426. )
  427. require.NoError(t, err)
  428. got, err := db.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  429. require.NoError(t, err)
  430. require.Len(t, got, 1)
  431. got[0].ID = 0
  432. want := []*Action{
  433. {
  434. UserID: alice.ID,
  435. OpType: ActionMergePullRequest,
  436. ActUserID: alice.ID,
  437. ActUserName: alice.Name,
  438. RepoID: repo.ID,
  439. RepoUserName: alice.Name,
  440. RepoName: repo.Name,
  441. IsPrivate: false,
  442. Content: `1|Fix issue 1`,
  443. CreatedUnix: db.NowFunc().Unix(),
  444. },
  445. }
  446. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  447. assert.Equal(t, want, got)
  448. }
  449. func actionsMirrorSyncCreate(t *testing.T, db *actions) {
  450. ctx := context.Background()
  451. alice, err := NewUsersStore(db.DB).Create(ctx, "alice", "[email protected]", CreateUserOptions{})
  452. require.NoError(t, err)
  453. repo, err := NewReposStore(db.DB).Create(ctx,
  454. alice.ID,
  455. CreateRepoOptions{
  456. Name: "example",
  457. },
  458. )
  459. require.NoError(t, err)
  460. err = db.MirrorSyncCreate(ctx,
  461. alice,
  462. repo,
  463. "main",
  464. )
  465. require.NoError(t, err)
  466. got, err := db.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  467. require.NoError(t, err)
  468. require.Len(t, got, 1)
  469. got[0].ID = 0
  470. want := []*Action{
  471. {
  472. UserID: alice.ID,
  473. OpType: ActionMirrorSyncCreate,
  474. ActUserID: alice.ID,
  475. ActUserName: alice.Name,
  476. RepoID: repo.ID,
  477. RepoUserName: alice.Name,
  478. RepoName: repo.Name,
  479. RefName: "main",
  480. IsPrivate: false,
  481. CreatedUnix: db.NowFunc().Unix(),
  482. },
  483. }
  484. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  485. assert.Equal(t, want, got)
  486. }
  487. func actionsMirrorSyncDelete(t *testing.T, db *actions) {
  488. ctx := context.Background()
  489. alice, err := NewUsersStore(db.DB).Create(ctx, "alice", "[email protected]", CreateUserOptions{})
  490. require.NoError(t, err)
  491. repo, err := NewReposStore(db.DB).Create(ctx,
  492. alice.ID,
  493. CreateRepoOptions{
  494. Name: "example",
  495. },
  496. )
  497. require.NoError(t, err)
  498. err = db.MirrorSyncDelete(ctx,
  499. alice,
  500. repo,
  501. "main",
  502. )
  503. require.NoError(t, err)
  504. got, err := db.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  505. require.NoError(t, err)
  506. require.Len(t, got, 1)
  507. got[0].ID = 0
  508. want := []*Action{
  509. {
  510. UserID: alice.ID,
  511. OpType: ActionMirrorSyncDelete,
  512. ActUserID: alice.ID,
  513. ActUserName: alice.Name,
  514. RepoID: repo.ID,
  515. RepoUserName: alice.Name,
  516. RepoName: repo.Name,
  517. RefName: "main",
  518. IsPrivate: false,
  519. CreatedUnix: db.NowFunc().Unix(),
  520. },
  521. }
  522. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  523. assert.Equal(t, want, got)
  524. }
  525. func actionsMirrorSyncPush(t *testing.T, db *actions) {
  526. ctx := context.Background()
  527. alice, err := NewUsersStore(db.DB).Create(ctx, "alice", "[email protected]", CreateUserOptions{})
  528. require.NoError(t, err)
  529. repo, err := NewReposStore(db.DB).Create(ctx,
  530. alice.ID,
  531. CreateRepoOptions{
  532. Name: "example",
  533. },
  534. )
  535. require.NoError(t, err)
  536. now := time.Unix(1588568886, 0).UTC()
  537. err = db.MirrorSyncPush(ctx,
  538. MirrorSyncPushOptions{
  539. Owner: alice,
  540. Repo: repo,
  541. RefName: "main",
  542. OldCommitID: "ca82a6dff817ec66f44342007202690a93763949",
  543. NewCommitID: "085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7",
  544. Commits: CommitsToPushCommits(
  545. []*git.Commit{
  546. {
  547. ID: git.MustIDFromString("085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7"),
  548. Author: &git.Signature{
  549. Name: "alice",
  550. Email: "[email protected]",
  551. When: now,
  552. },
  553. Committer: &git.Signature{
  554. Name: "alice",
  555. Email: "[email protected]",
  556. When: now,
  557. },
  558. Message: "A random commit",
  559. },
  560. },
  561. ),
  562. },
  563. )
  564. require.NoError(t, err)
  565. got, err := db.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  566. require.NoError(t, err)
  567. require.Len(t, got, 1)
  568. got[0].ID = 0
  569. want := []*Action{
  570. {
  571. UserID: alice.ID,
  572. OpType: ActionMirrorSyncPush,
  573. ActUserID: alice.ID,
  574. ActUserName: alice.Name,
  575. RepoID: repo.ID,
  576. RepoUserName: alice.Name,
  577. RepoName: repo.Name,
  578. RefName: "main",
  579. IsPrivate: false,
  580. Content: `{"Len":1,"Commits":[{"Sha1":"085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7","Message":"A random commit","AuthorEmail":"[email protected]","AuthorName":"alice","CommitterEmail":"[email protected]","CommitterName":"alice","Timestamp":"2020-05-04T05:08:06Z"}],"CompareURL":"alice/example/compare/ca82a6dff817ec66f44342007202690a93763949...085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7"}`,
  581. CreatedUnix: db.NowFunc().Unix(),
  582. },
  583. }
  584. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  585. assert.Equal(t, want, got)
  586. }
  587. func actionsNewRepo(t *testing.T, db *actions) {
  588. ctx := context.Background()
  589. alice, err := NewUsersStore(db.DB).Create(ctx, "alice", "[email protected]", CreateUserOptions{})
  590. require.NoError(t, err)
  591. repo, err := NewReposStore(db.DB).Create(ctx,
  592. alice.ID,
  593. CreateRepoOptions{
  594. Name: "example",
  595. },
  596. )
  597. require.NoError(t, err)
  598. t.Run("new repo", func(t *testing.T) {
  599. t.Cleanup(func() {
  600. err := db.Session(&gorm.Session{AllowGlobalUpdate: true}).WithContext(ctx).Delete(new(Action)).Error
  601. require.NoError(t, err)
  602. })
  603. err = db.NewRepo(ctx, alice, alice, repo)
  604. require.NoError(t, err)
  605. got, err := db.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  606. require.NoError(t, err)
  607. require.Len(t, got, 1)
  608. got[0].ID = 0
  609. want := []*Action{
  610. {
  611. UserID: alice.ID,
  612. OpType: ActionCreateRepo,
  613. ActUserID: alice.ID,
  614. ActUserName: alice.Name,
  615. RepoID: repo.ID,
  616. RepoUserName: alice.Name,
  617. RepoName: repo.Name,
  618. IsPrivate: false,
  619. CreatedUnix: db.NowFunc().Unix(),
  620. },
  621. }
  622. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  623. assert.Equal(t, want, got)
  624. })
  625. t.Run("fork repo", func(t *testing.T) {
  626. t.Cleanup(func() {
  627. err := db.Session(&gorm.Session{AllowGlobalUpdate: true}).WithContext(ctx).Delete(new(Action)).Error
  628. require.NoError(t, err)
  629. })
  630. repo.IsFork = true
  631. err = db.NewRepo(ctx, alice, alice, repo)
  632. require.NoError(t, err)
  633. got, err := db.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  634. require.NoError(t, err)
  635. require.Len(t, got, 1)
  636. got[0].ID = 0
  637. want := []*Action{
  638. {
  639. UserID: alice.ID,
  640. OpType: ActionForkRepo,
  641. ActUserID: alice.ID,
  642. ActUserName: alice.Name,
  643. RepoID: repo.ID,
  644. RepoUserName: alice.Name,
  645. RepoName: repo.Name,
  646. IsPrivate: false,
  647. CreatedUnix: db.NowFunc().Unix(),
  648. },
  649. }
  650. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  651. assert.Equal(t, want, got)
  652. })
  653. }
  654. func actionsPushTag(t *testing.T, db *actions) {
  655. ctx := context.Background()
  656. // NOTE: We set a noop mock here to avoid data race with other tests that writes
  657. // to the mock server because this function holds a lock.
  658. conf.SetMockServer(t, conf.ServerOpts{})
  659. alice, err := NewUsersStore(db.DB).Create(ctx, "alice", "[email protected]", CreateUserOptions{})
  660. require.NoError(t, err)
  661. repo, err := NewReposStore(db.DB).Create(ctx,
  662. alice.ID,
  663. CreateRepoOptions{
  664. Name: "example",
  665. },
  666. )
  667. require.NoError(t, err)
  668. t.Run("new tag", func(t *testing.T) {
  669. t.Cleanup(func() {
  670. err := db.Session(&gorm.Session{AllowGlobalUpdate: true}).WithContext(ctx).Delete(new(Action)).Error
  671. require.NoError(t, err)
  672. })
  673. err = db.PushTag(ctx,
  674. PushTagOptions{
  675. Owner: alice,
  676. Repo: repo,
  677. PusherName: alice.Name,
  678. RefFullName: "refs/tags/v1.0.0",
  679. NewCommitID: "085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7",
  680. },
  681. )
  682. require.NoError(t, err)
  683. got, err := db.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  684. require.NoError(t, err)
  685. require.Len(t, got, 1)
  686. got[0].ID = 0
  687. want := []*Action{
  688. {
  689. UserID: alice.ID,
  690. OpType: ActionPushTag,
  691. ActUserID: alice.ID,
  692. ActUserName: alice.Name,
  693. RepoID: repo.ID,
  694. RepoUserName: alice.Name,
  695. RepoName: repo.Name,
  696. RefName: "v1.0.0",
  697. IsPrivate: false,
  698. CreatedUnix: db.NowFunc().Unix(),
  699. },
  700. }
  701. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  702. assert.Equal(t, want, got)
  703. })
  704. t.Run("delete tag", func(t *testing.T) {
  705. t.Cleanup(func() {
  706. err := db.Session(&gorm.Session{AllowGlobalUpdate: true}).WithContext(ctx).Delete(new(Action)).Error
  707. require.NoError(t, err)
  708. })
  709. err = db.PushTag(ctx,
  710. PushTagOptions{
  711. Owner: alice,
  712. Repo: repo,
  713. PusherName: alice.Name,
  714. RefFullName: "refs/tags/v1.0.0",
  715. NewCommitID: git.EmptyID,
  716. },
  717. )
  718. require.NoError(t, err)
  719. got, err := db.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  720. require.NoError(t, err)
  721. require.Len(t, got, 1)
  722. got[0].ID = 0
  723. want := []*Action{
  724. {
  725. UserID: alice.ID,
  726. OpType: ActionDeleteTag,
  727. ActUserID: alice.ID,
  728. ActUserName: alice.Name,
  729. RepoID: repo.ID,
  730. RepoUserName: alice.Name,
  731. RepoName: repo.Name,
  732. RefName: "v1.0.0",
  733. IsPrivate: false,
  734. CreatedUnix: db.NowFunc().Unix(),
  735. },
  736. }
  737. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  738. assert.Equal(t, want, got)
  739. })
  740. }
  741. func actionsRenameRepo(t *testing.T, db *actions) {
  742. ctx := context.Background()
  743. alice, err := NewUsersStore(db.DB).Create(ctx, "alice", "[email protected]", CreateUserOptions{})
  744. require.NoError(t, err)
  745. repo, err := NewReposStore(db.DB).Create(ctx,
  746. alice.ID,
  747. CreateRepoOptions{
  748. Name: "example",
  749. },
  750. )
  751. require.NoError(t, err)
  752. err = db.RenameRepo(ctx, alice, alice, "oldExample", repo)
  753. require.NoError(t, err)
  754. got, err := db.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  755. require.NoError(t, err)
  756. require.Len(t, got, 1)
  757. got[0].ID = 0
  758. want := []*Action{
  759. {
  760. UserID: alice.ID,
  761. OpType: ActionRenameRepo,
  762. ActUserID: alice.ID,
  763. ActUserName: alice.Name,
  764. RepoID: repo.ID,
  765. RepoUserName: alice.Name,
  766. RepoName: repo.Name,
  767. IsPrivate: false,
  768. Content: "oldExample",
  769. CreatedUnix: db.NowFunc().Unix(),
  770. },
  771. }
  772. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  773. assert.Equal(t, want, got)
  774. }
  775. func actionsTransferRepo(t *testing.T, db *actions) {
  776. ctx := context.Background()
  777. alice, err := NewUsersStore(db.DB).Create(ctx, "alice", "[email protected]", CreateUserOptions{})
  778. require.NoError(t, err)
  779. bob, err := NewUsersStore(db.DB).Create(ctx, "bob", "[email protected]", CreateUserOptions{})
  780. require.NoError(t, err)
  781. repo, err := NewReposStore(db.DB).Create(ctx,
  782. alice.ID,
  783. CreateRepoOptions{
  784. Name: "example",
  785. },
  786. )
  787. require.NoError(t, err)
  788. err = db.TransferRepo(ctx, alice, alice, bob, repo)
  789. require.NoError(t, err)
  790. got, err := db.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  791. require.NoError(t, err)
  792. require.Len(t, got, 1)
  793. got[0].ID = 0
  794. want := []*Action{
  795. {
  796. UserID: alice.ID,
  797. OpType: ActionTransferRepo,
  798. ActUserID: alice.ID,
  799. ActUserName: alice.Name,
  800. RepoID: repo.ID,
  801. RepoUserName: bob.Name,
  802. RepoName: repo.Name,
  803. IsPrivate: false,
  804. Content: "alice/example",
  805. CreatedUnix: db.NowFunc().Unix(),
  806. },
  807. }
  808. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  809. assert.Equal(t, want, got)
  810. }