gitea源码

context_test.go 4.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. // Copyright 2022 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package db_test
  4. import (
  5. "context"
  6. "testing"
  7. "code.gitea.io/gitea/models/db"
  8. "code.gitea.io/gitea/models/unittest"
  9. "github.com/stretchr/testify/assert"
  10. )
  11. func TestInTransaction(t *testing.T) {
  12. assert.NoError(t, unittest.PrepareTestDatabase())
  13. assert.False(t, db.InTransaction(t.Context()))
  14. assert.NoError(t, db.WithTx(t.Context(), func(ctx context.Context) error {
  15. assert.True(t, db.InTransaction(ctx))
  16. return nil
  17. }))
  18. ctx, committer, err := db.TxContext(t.Context())
  19. assert.NoError(t, err)
  20. defer committer.Close()
  21. assert.True(t, db.InTransaction(ctx))
  22. assert.NoError(t, db.WithTx(ctx, func(ctx context.Context) error {
  23. assert.True(t, db.InTransaction(ctx))
  24. return nil
  25. }))
  26. }
  27. func TestTxContext(t *testing.T) {
  28. assert.NoError(t, unittest.PrepareTestDatabase())
  29. { // create new transaction
  30. ctx, committer, err := db.TxContext(t.Context())
  31. assert.NoError(t, err)
  32. assert.True(t, db.InTransaction(ctx))
  33. assert.NoError(t, committer.Commit())
  34. }
  35. { // reuse the transaction created by TxContext and commit it
  36. ctx, committer, err := db.TxContext(t.Context())
  37. engine := db.GetEngine(ctx)
  38. assert.NoError(t, err)
  39. assert.True(t, db.InTransaction(ctx))
  40. {
  41. ctx, committer, err := db.TxContext(ctx)
  42. assert.NoError(t, err)
  43. assert.True(t, db.InTransaction(ctx))
  44. assert.Equal(t, engine, db.GetEngine(ctx))
  45. assert.NoError(t, committer.Commit())
  46. }
  47. assert.NoError(t, committer.Commit())
  48. }
  49. { // reuse the transaction created by TxContext and close it
  50. ctx, committer, err := db.TxContext(t.Context())
  51. engine := db.GetEngine(ctx)
  52. assert.NoError(t, err)
  53. assert.True(t, db.InTransaction(ctx))
  54. {
  55. ctx, committer, err := db.TxContext(ctx)
  56. assert.NoError(t, err)
  57. assert.True(t, db.InTransaction(ctx))
  58. assert.Equal(t, engine, db.GetEngine(ctx))
  59. assert.NoError(t, committer.Close())
  60. }
  61. assert.NoError(t, committer.Close())
  62. }
  63. { // reuse the transaction created by WithTx
  64. assert.NoError(t, db.WithTx(t.Context(), func(ctx context.Context) error {
  65. assert.True(t, db.InTransaction(ctx))
  66. {
  67. ctx, committer, err := db.TxContext(ctx)
  68. assert.NoError(t, err)
  69. assert.True(t, db.InTransaction(ctx))
  70. assert.NoError(t, committer.Commit())
  71. }
  72. return nil
  73. }))
  74. }
  75. }
  76. func TestContextSafety(t *testing.T) {
  77. type TestModel1 struct {
  78. ID int64
  79. }
  80. type TestModel2 struct {
  81. ID int64
  82. }
  83. assert.NoError(t, unittest.GetXORMEngine().Sync(&TestModel1{}, &TestModel2{}))
  84. assert.NoError(t, db.TruncateBeans(t.Context(), &TestModel1{}, &TestModel2{}))
  85. testCount := 10
  86. for i := 1; i <= testCount; i++ {
  87. assert.NoError(t, db.Insert(t.Context(), &TestModel1{ID: int64(i)}))
  88. assert.NoError(t, db.Insert(t.Context(), &TestModel2{ID: int64(-i)}))
  89. }
  90. t.Run("Show-XORM-Bug", func(t *testing.T) {
  91. actualCount := 0
  92. // here: db.GetEngine(t.Context()) is a new *Session created from *Engine
  93. _ = db.WithTx(t.Context(), func(ctx context.Context) error {
  94. _ = db.GetEngine(ctx).Iterate(&TestModel1{}, func(i int, bean any) error {
  95. // here: db.GetEngine(ctx) is always the unclosed "Iterate" *Session with autoResetStatement=false,
  96. // and the internal states (including "cond" and others) are always there and not be reset in this callback.
  97. m1 := bean.(*TestModel1)
  98. assert.EqualValues(t, i+1, m1.ID)
  99. // here: XORM bug, it fails because the SQL becomes "WHERE id=-1", "WHERE id=-1 AND id=-2", "WHERE id=-1 AND id=-2 AND id=-3" ...
  100. // and it conflicts with the "Iterate"'s internal states.
  101. // has, err := db.GetEngine(ctx).Get(&TestModel2{ID: -m1.ID})
  102. actualCount++
  103. return nil
  104. })
  105. return nil
  106. })
  107. assert.Equal(t, testCount, actualCount)
  108. })
  109. t.Run("DenyBadUsage", func(t *testing.T) {
  110. assert.PanicsWithError(t, "using session context in an iterator would cause corrupted results", func() {
  111. _ = db.WithTx(t.Context(), func(ctx context.Context) error {
  112. return db.GetEngine(ctx).Iterate(&TestModel1{}, func(i int, bean any) error {
  113. _ = db.GetEngine(ctx)
  114. return nil
  115. })
  116. })
  117. })
  118. })
  119. }