actions_test.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896
  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. t.Run("new commit", func(t *testing.T) {
  135. t.Cleanup(func() {
  136. err := db.Session(&gorm.Session{AllowGlobalUpdate: true}).WithContext(ctx).Delete(new(Action)).Error
  137. require.NoError(t, err)
  138. })
  139. err = db.CommitRepo(ctx,
  140. CommitRepoOptions{
  141. PusherName: alice.Name,
  142. Owner: alice,
  143. Repo: repo,
  144. RefFullName: "refs/heads/main",
  145. OldCommitID: "ca82a6dff817ec66f44342007202690a93763949",
  146. NewCommitID: "085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7",
  147. Commits: CommitsToPushCommits(
  148. []*git.Commit{
  149. {
  150. ID: git.MustIDFromString("085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7"),
  151. Author: &git.Signature{
  152. Name: "alice",
  153. Email: "[email protected]",
  154. When: now,
  155. },
  156. Committer: &git.Signature{
  157. Name: "alice",
  158. Email: "[email protected]",
  159. When: now,
  160. },
  161. Message: "A random commit",
  162. },
  163. },
  164. ),
  165. },
  166. )
  167. require.NoError(t, err)
  168. got, err := db.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  169. require.NoError(t, err)
  170. require.Len(t, got, 1)
  171. got[0].ID = 0
  172. want := []*Action{
  173. {
  174. UserID: alice.ID,
  175. OpType: ActionCommitRepo,
  176. ActUserID: alice.ID,
  177. ActUserName: alice.Name,
  178. RepoID: repo.ID,
  179. RepoUserName: alice.Name,
  180. RepoName: repo.Name,
  181. RefName: "main",
  182. IsPrivate: false,
  183. 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"}`,
  184. CreatedUnix: db.NowFunc().Unix(),
  185. },
  186. }
  187. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  188. assert.Equal(t, want, got)
  189. })
  190. t.Run("new ref", func(t *testing.T) {
  191. t.Cleanup(func() {
  192. err := db.Session(&gorm.Session{AllowGlobalUpdate: true}).WithContext(ctx).Delete(new(Action)).Error
  193. require.NoError(t, err)
  194. })
  195. err = db.CommitRepo(ctx,
  196. CommitRepoOptions{
  197. PusherName: alice.Name,
  198. Owner: alice,
  199. Repo: repo,
  200. RefFullName: "refs/heads/main",
  201. OldCommitID: git.EmptyID,
  202. NewCommitID: "085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7",
  203. Commits: CommitsToPushCommits(
  204. []*git.Commit{
  205. {
  206. ID: git.MustIDFromString("085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7"),
  207. Author: &git.Signature{
  208. Name: "alice",
  209. Email: "[email protected]",
  210. When: now,
  211. },
  212. Committer: &git.Signature{
  213. Name: "alice",
  214. Email: "[email protected]",
  215. When: now,
  216. },
  217. Message: "A random commit",
  218. },
  219. },
  220. ),
  221. },
  222. )
  223. require.NoError(t, err)
  224. got, err := db.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  225. require.NoError(t, err)
  226. require.Len(t, got, 2)
  227. got[0].ID = 0
  228. got[1].ID = 0
  229. want := []*Action{
  230. {
  231. UserID: alice.ID,
  232. OpType: ActionCommitRepo,
  233. ActUserID: alice.ID,
  234. ActUserName: alice.Name,
  235. RepoID: repo.ID,
  236. RepoUserName: alice.Name,
  237. RepoName: repo.Name,
  238. RefName: "main",
  239. IsPrivate: false,
  240. 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":""}`,
  241. CreatedUnix: db.NowFunc().Unix(),
  242. },
  243. {
  244. UserID: alice.ID,
  245. OpType: ActionCreateBranch,
  246. ActUserID: alice.ID,
  247. ActUserName: alice.Name,
  248. RepoID: repo.ID,
  249. RepoUserName: alice.Name,
  250. RepoName: repo.Name,
  251. RefName: "main",
  252. IsPrivate: false,
  253. 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":""}`,
  254. CreatedUnix: db.NowFunc().Unix(),
  255. },
  256. }
  257. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  258. want[1].Created = time.Unix(want[1].CreatedUnix, 0)
  259. assert.Equal(t, want, got)
  260. })
  261. t.Run("delete ref", func(t *testing.T) {
  262. t.Cleanup(func() {
  263. err := db.Session(&gorm.Session{AllowGlobalUpdate: true}).WithContext(ctx).Delete(new(Action)).Error
  264. require.NoError(t, err)
  265. })
  266. err = db.CommitRepo(ctx,
  267. CommitRepoOptions{
  268. PusherName: alice.Name,
  269. Owner: alice,
  270. Repo: repo,
  271. RefFullName: "refs/heads/main",
  272. OldCommitID: "ca82a6dff817ec66f44342007202690a93763949",
  273. NewCommitID: git.EmptyID,
  274. },
  275. )
  276. require.NoError(t, err)
  277. got, err := db.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  278. require.NoError(t, err)
  279. require.Len(t, got, 1)
  280. got[0].ID = 0
  281. want := []*Action{
  282. {
  283. UserID: alice.ID,
  284. OpType: ActionDeleteBranch,
  285. ActUserID: alice.ID,
  286. ActUserName: alice.Name,
  287. RepoID: repo.ID,
  288. RepoUserName: alice.Name,
  289. RepoName: repo.Name,
  290. RefName: "main",
  291. IsPrivate: false,
  292. CreatedUnix: db.NowFunc().Unix(),
  293. },
  294. }
  295. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  296. assert.Equal(t, want, got)
  297. })
  298. }
  299. func actionsListByOrganization(t *testing.T, db *actions) {
  300. if os.Getenv("GOGS_DATABASE_TYPE") != "postgres" {
  301. t.Skip("Skipping testing with not using PostgreSQL")
  302. return
  303. }
  304. ctx := context.Background()
  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, db *actions) {
  344. if os.Getenv("GOGS_DATABASE_TYPE") != "postgres" {
  345. t.Skip("Skipping testing with not using PostgreSQL")
  346. return
  347. }
  348. ctx := context.Background()
  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 := db.DB.ToSQL(func(tx *gorm.DB) *gorm.DB {
  400. return NewActionsStore(tx).(*actions).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, db *actions) {
  407. ctx := context.Background()
  408. alice, err := NewUsersStore(db.DB).Create(ctx, "alice", "[email protected]", CreateUserOptions{})
  409. require.NoError(t, err)
  410. repo, err := NewReposStore(db.DB).Create(ctx,
  411. alice.ID,
  412. CreateRepoOptions{
  413. Name: "example",
  414. },
  415. )
  416. require.NoError(t, err)
  417. err = db.MergePullRequest(ctx,
  418. alice,
  419. alice,
  420. repo,
  421. &Issue{
  422. Index: 1,
  423. Title: "Fix issue 1",
  424. },
  425. )
  426. require.NoError(t, err)
  427. got, err := db.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  428. require.NoError(t, err)
  429. require.Len(t, got, 1)
  430. got[0].ID = 0
  431. want := []*Action{
  432. {
  433. UserID: alice.ID,
  434. OpType: ActionMergePullRequest,
  435. ActUserID: alice.ID,
  436. ActUserName: alice.Name,
  437. RepoID: repo.ID,
  438. RepoUserName: alice.Name,
  439. RepoName: repo.Name,
  440. IsPrivate: false,
  441. Content: `1|Fix issue 1`,
  442. CreatedUnix: db.NowFunc().Unix(),
  443. },
  444. }
  445. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  446. assert.Equal(t, want, got)
  447. }
  448. func actionsMirrorSyncCreate(t *testing.T, db *actions) {
  449. ctx := context.Background()
  450. alice, err := NewUsersStore(db.DB).Create(ctx, "alice", "[email protected]", CreateUserOptions{})
  451. require.NoError(t, err)
  452. repo, err := NewReposStore(db.DB).Create(ctx,
  453. alice.ID,
  454. CreateRepoOptions{
  455. Name: "example",
  456. },
  457. )
  458. require.NoError(t, err)
  459. err = db.MirrorSyncCreate(ctx,
  460. alice,
  461. repo,
  462. "main",
  463. )
  464. require.NoError(t, err)
  465. got, err := db.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  466. require.NoError(t, err)
  467. require.Len(t, got, 1)
  468. got[0].ID = 0
  469. want := []*Action{
  470. {
  471. UserID: alice.ID,
  472. OpType: ActionMirrorSyncCreate,
  473. ActUserID: alice.ID,
  474. ActUserName: alice.Name,
  475. RepoID: repo.ID,
  476. RepoUserName: alice.Name,
  477. RepoName: repo.Name,
  478. RefName: "main",
  479. IsPrivate: false,
  480. CreatedUnix: db.NowFunc().Unix(),
  481. },
  482. }
  483. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  484. assert.Equal(t, want, got)
  485. }
  486. func actionsMirrorSyncDelete(t *testing.T, db *actions) {
  487. ctx := context.Background()
  488. alice, err := NewUsersStore(db.DB).Create(ctx, "alice", "[email protected]", CreateUserOptions{})
  489. require.NoError(t, err)
  490. repo, err := NewReposStore(db.DB).Create(ctx,
  491. alice.ID,
  492. CreateRepoOptions{
  493. Name: "example",
  494. },
  495. )
  496. require.NoError(t, err)
  497. err = db.MirrorSyncDelete(ctx,
  498. alice,
  499. repo,
  500. "main",
  501. )
  502. require.NoError(t, err)
  503. got, err := db.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  504. require.NoError(t, err)
  505. require.Len(t, got, 1)
  506. got[0].ID = 0
  507. want := []*Action{
  508. {
  509. UserID: alice.ID,
  510. OpType: ActionMirrorSyncDelete,
  511. ActUserID: alice.ID,
  512. ActUserName: alice.Name,
  513. RepoID: repo.ID,
  514. RepoUserName: alice.Name,
  515. RepoName: repo.Name,
  516. RefName: "main",
  517. IsPrivate: false,
  518. CreatedUnix: db.NowFunc().Unix(),
  519. },
  520. }
  521. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  522. assert.Equal(t, want, got)
  523. }
  524. func actionsMirrorSyncPush(t *testing.T, db *actions) {
  525. ctx := context.Background()
  526. alice, err := NewUsersStore(db.DB).Create(ctx, "alice", "[email protected]", CreateUserOptions{})
  527. require.NoError(t, err)
  528. repo, err := NewReposStore(db.DB).Create(ctx,
  529. alice.ID,
  530. CreateRepoOptions{
  531. Name: "example",
  532. },
  533. )
  534. require.NoError(t, err)
  535. now := time.Unix(1588568886, 0).UTC()
  536. err = db.MirrorSyncPush(ctx,
  537. MirrorSyncPushOptions{
  538. Owner: alice,
  539. Repo: repo,
  540. RefName: "main",
  541. OldCommitID: "ca82a6dff817ec66f44342007202690a93763949",
  542. NewCommitID: "085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7",
  543. Commits: CommitsToPushCommits(
  544. []*git.Commit{
  545. {
  546. ID: git.MustIDFromString("085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7"),
  547. Author: &git.Signature{
  548. Name: "alice",
  549. Email: "[email protected]",
  550. When: now,
  551. },
  552. Committer: &git.Signature{
  553. Name: "alice",
  554. Email: "[email protected]",
  555. When: now,
  556. },
  557. Message: "A random commit",
  558. },
  559. },
  560. ),
  561. },
  562. )
  563. require.NoError(t, err)
  564. got, err := db.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  565. require.NoError(t, err)
  566. require.Len(t, got, 1)
  567. got[0].ID = 0
  568. want := []*Action{
  569. {
  570. UserID: alice.ID,
  571. OpType: ActionMirrorSyncPush,
  572. ActUserID: alice.ID,
  573. ActUserName: alice.Name,
  574. RepoID: repo.ID,
  575. RepoUserName: alice.Name,
  576. RepoName: repo.Name,
  577. RefName: "main",
  578. IsPrivate: false,
  579. 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"}`,
  580. CreatedUnix: db.NowFunc().Unix(),
  581. },
  582. }
  583. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  584. assert.Equal(t, want, got)
  585. }
  586. func actionsNewRepo(t *testing.T, db *actions) {
  587. ctx := context.Background()
  588. alice, err := NewUsersStore(db.DB).Create(ctx, "alice", "[email protected]", CreateUserOptions{})
  589. require.NoError(t, err)
  590. repo, err := NewReposStore(db.DB).Create(ctx,
  591. alice.ID,
  592. CreateRepoOptions{
  593. Name: "example",
  594. },
  595. )
  596. require.NoError(t, err)
  597. t.Run("new repo", func(t *testing.T) {
  598. t.Cleanup(func() {
  599. err := db.Session(&gorm.Session{AllowGlobalUpdate: true}).WithContext(ctx).Delete(new(Action)).Error
  600. require.NoError(t, err)
  601. })
  602. err = db.NewRepo(ctx, alice, alice, repo)
  603. require.NoError(t, err)
  604. got, err := db.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  605. require.NoError(t, err)
  606. require.Len(t, got, 1)
  607. got[0].ID = 0
  608. want := []*Action{
  609. {
  610. UserID: alice.ID,
  611. OpType: ActionCreateRepo,
  612. ActUserID: alice.ID,
  613. ActUserName: alice.Name,
  614. RepoID: repo.ID,
  615. RepoUserName: alice.Name,
  616. RepoName: repo.Name,
  617. IsPrivate: false,
  618. CreatedUnix: db.NowFunc().Unix(),
  619. },
  620. }
  621. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  622. assert.Equal(t, want, got)
  623. })
  624. t.Run("fork repo", func(t *testing.T) {
  625. t.Cleanup(func() {
  626. err := db.Session(&gorm.Session{AllowGlobalUpdate: true}).WithContext(ctx).Delete(new(Action)).Error
  627. require.NoError(t, err)
  628. })
  629. repo.IsFork = true
  630. err = db.NewRepo(ctx, alice, alice, repo)
  631. require.NoError(t, err)
  632. got, err := db.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  633. require.NoError(t, err)
  634. require.Len(t, got, 1)
  635. got[0].ID = 0
  636. want := []*Action{
  637. {
  638. UserID: alice.ID,
  639. OpType: ActionForkRepo,
  640. ActUserID: alice.ID,
  641. ActUserName: alice.Name,
  642. RepoID: repo.ID,
  643. RepoUserName: alice.Name,
  644. RepoName: repo.Name,
  645. IsPrivate: false,
  646. CreatedUnix: db.NowFunc().Unix(),
  647. },
  648. }
  649. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  650. assert.Equal(t, want, got)
  651. })
  652. }
  653. func actionsPushTag(t *testing.T, db *actions) {
  654. ctx := context.Background()
  655. // NOTE: We set a noop mock here to avoid data race with other tests that writes
  656. // to the mock server because this function holds a lock.
  657. conf.SetMockServer(t, conf.ServerOpts{})
  658. alice, err := NewUsersStore(db.DB).Create(ctx, "alice", "[email protected]", CreateUserOptions{})
  659. require.NoError(t, err)
  660. repo, err := NewReposStore(db.DB).Create(ctx,
  661. alice.ID,
  662. CreateRepoOptions{
  663. Name: "example",
  664. },
  665. )
  666. require.NoError(t, err)
  667. t.Run("new tag", func(t *testing.T) {
  668. t.Cleanup(func() {
  669. err := db.Session(&gorm.Session{AllowGlobalUpdate: true}).WithContext(ctx).Delete(new(Action)).Error
  670. require.NoError(t, err)
  671. })
  672. err = db.PushTag(ctx,
  673. PushTagOptions{
  674. Owner: alice,
  675. Repo: repo,
  676. PusherName: alice.Name,
  677. RefFullName: "refs/tags/v1.0.0",
  678. NewCommitID: "085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7",
  679. },
  680. )
  681. require.NoError(t, err)
  682. got, err := db.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  683. require.NoError(t, err)
  684. require.Len(t, got, 1)
  685. got[0].ID = 0
  686. want := []*Action{
  687. {
  688. UserID: alice.ID,
  689. OpType: ActionPushTag,
  690. ActUserID: alice.ID,
  691. ActUserName: alice.Name,
  692. RepoID: repo.ID,
  693. RepoUserName: alice.Name,
  694. RepoName: repo.Name,
  695. RefName: "v1.0.0",
  696. IsPrivate: false,
  697. CreatedUnix: db.NowFunc().Unix(),
  698. },
  699. }
  700. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  701. assert.Equal(t, want, got)
  702. })
  703. t.Run("delete tag", func(t *testing.T) {
  704. t.Cleanup(func() {
  705. err := db.Session(&gorm.Session{AllowGlobalUpdate: true}).WithContext(ctx).Delete(new(Action)).Error
  706. require.NoError(t, err)
  707. })
  708. err = db.PushTag(ctx,
  709. PushTagOptions{
  710. Owner: alice,
  711. Repo: repo,
  712. PusherName: alice.Name,
  713. RefFullName: "refs/tags/v1.0.0",
  714. NewCommitID: git.EmptyID,
  715. },
  716. )
  717. require.NoError(t, err)
  718. got, err := db.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  719. require.NoError(t, err)
  720. require.Len(t, got, 1)
  721. got[0].ID = 0
  722. want := []*Action{
  723. {
  724. UserID: alice.ID,
  725. OpType: ActionDeleteTag,
  726. ActUserID: alice.ID,
  727. ActUserName: alice.Name,
  728. RepoID: repo.ID,
  729. RepoUserName: alice.Name,
  730. RepoName: repo.Name,
  731. RefName: "v1.0.0",
  732. IsPrivate: false,
  733. CreatedUnix: db.NowFunc().Unix(),
  734. },
  735. }
  736. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  737. assert.Equal(t, want, got)
  738. })
  739. }
  740. func actionsRenameRepo(t *testing.T, db *actions) {
  741. ctx := context.Background()
  742. alice, err := NewUsersStore(db.DB).Create(ctx, "alice", "[email protected]", CreateUserOptions{})
  743. require.NoError(t, err)
  744. repo, err := NewReposStore(db.DB).Create(ctx,
  745. alice.ID,
  746. CreateRepoOptions{
  747. Name: "example",
  748. },
  749. )
  750. require.NoError(t, err)
  751. err = db.RenameRepo(ctx, alice, alice, "oldExample", repo)
  752. require.NoError(t, err)
  753. got, err := db.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  754. require.NoError(t, err)
  755. require.Len(t, got, 1)
  756. got[0].ID = 0
  757. want := []*Action{
  758. {
  759. UserID: alice.ID,
  760. OpType: ActionRenameRepo,
  761. ActUserID: alice.ID,
  762. ActUserName: alice.Name,
  763. RepoID: repo.ID,
  764. RepoUserName: alice.Name,
  765. RepoName: repo.Name,
  766. IsPrivate: false,
  767. Content: "oldExample",
  768. CreatedUnix: db.NowFunc().Unix(),
  769. },
  770. }
  771. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  772. assert.Equal(t, want, got)
  773. }
  774. func actionsTransferRepo(t *testing.T, db *actions) {
  775. ctx := context.Background()
  776. alice, err := NewUsersStore(db.DB).Create(ctx, "alice", "[email protected]", CreateUserOptions{})
  777. require.NoError(t, err)
  778. bob, err := NewUsersStore(db.DB).Create(ctx, "bob", "[email protected]", CreateUserOptions{})
  779. require.NoError(t, err)
  780. repo, err := NewReposStore(db.DB).Create(ctx,
  781. alice.ID,
  782. CreateRepoOptions{
  783. Name: "example",
  784. },
  785. )
  786. require.NoError(t, err)
  787. err = db.TransferRepo(ctx, alice, alice, bob, repo)
  788. require.NoError(t, err)
  789. got, err := db.ListByUser(ctx, alice.ID, alice.ID, 0, false)
  790. require.NoError(t, err)
  791. require.Len(t, got, 1)
  792. got[0].ID = 0
  793. want := []*Action{
  794. {
  795. UserID: alice.ID,
  796. OpType: ActionTransferRepo,
  797. ActUserID: alice.ID,
  798. ActUserName: alice.Name,
  799. RepoID: repo.ID,
  800. RepoUserName: bob.Name,
  801. RepoName: repo.Name,
  802. IsPrivate: false,
  803. Content: "alice/example",
  804. CreatedUnix: db.NowFunc().Unix(),
  805. },
  806. }
  807. want[0].Created = time.Unix(want[0].CreatedUnix, 0)
  808. assert.Equal(t, want, got)
  809. }