gitea源码

testdb.go 6.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. // Copyright 2021 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package unittest
  4. import (
  5. "context"
  6. "fmt"
  7. "os"
  8. "path/filepath"
  9. "strings"
  10. "testing"
  11. "code.gitea.io/gitea/models/db"
  12. "code.gitea.io/gitea/models/system"
  13. "code.gitea.io/gitea/modules/auth/password/hash"
  14. "code.gitea.io/gitea/modules/cache"
  15. "code.gitea.io/gitea/modules/git"
  16. "code.gitea.io/gitea/modules/log"
  17. "code.gitea.io/gitea/modules/setting"
  18. "code.gitea.io/gitea/modules/setting/config"
  19. "code.gitea.io/gitea/modules/storage"
  20. "code.gitea.io/gitea/modules/tempdir"
  21. "code.gitea.io/gitea/modules/test"
  22. "code.gitea.io/gitea/modules/util"
  23. "github.com/stretchr/testify/assert"
  24. "xorm.io/xorm"
  25. "xorm.io/xorm/names"
  26. )
  27. var giteaRoot string
  28. func fatalTestError(fmtStr string, args ...any) {
  29. _, _ = fmt.Fprintf(os.Stderr, fmtStr, args...)
  30. os.Exit(1)
  31. }
  32. // InitSettingsForTesting initializes config provider and load common settings for tests
  33. func InitSettingsForTesting() {
  34. setting.IsInTesting = true
  35. log.OsExiter = func(code int) {
  36. if code != 0 {
  37. // non-zero exit code (log.Fatal) shouldn't occur during testing, if it happens, show a full stacktrace for more details
  38. panic(fmt.Errorf("non-zero exit code during testing: %d", code))
  39. }
  40. os.Exit(0)
  41. }
  42. if setting.CustomConf == "" {
  43. setting.CustomConf = filepath.Join(setting.CustomPath, "conf/app-unittest-tmp.ini")
  44. _ = os.Remove(setting.CustomConf)
  45. }
  46. setting.InitCfgProvider(setting.CustomConf)
  47. setting.LoadCommonSettings()
  48. if err := setting.PrepareAppDataPath(); err != nil {
  49. log.Fatal("Can not prepare APP_DATA_PATH: %v", err)
  50. }
  51. // register the dummy hash algorithm function used in the test fixtures
  52. _ = hash.Register("dummy", hash.NewDummyHasher)
  53. setting.PasswordHashAlgo, _ = hash.SetDefaultPasswordHashAlgorithm("dummy")
  54. setting.InitGiteaEnvVarsForTesting()
  55. }
  56. // TestOptions represents test options
  57. type TestOptions struct {
  58. FixtureFiles []string
  59. SetUp func() error // SetUp will be executed before all tests in this package
  60. TearDown func() error // TearDown will be executed after all tests in this package
  61. }
  62. // MainTest a reusable TestMain(..) function for unit tests that need to use a
  63. // test database. Creates the test database, and sets necessary settings.
  64. func MainTest(m *testing.M, testOptsArg ...*TestOptions) {
  65. testOpts := util.OptionalArg(testOptsArg, &TestOptions{})
  66. giteaRoot = test.SetupGiteaRoot()
  67. setting.CustomPath = filepath.Join(giteaRoot, "custom")
  68. InitSettingsForTesting()
  69. fixturesOpts := FixturesOptions{Dir: filepath.Join(giteaRoot, "models", "fixtures"), Files: testOpts.FixtureFiles}
  70. if err := CreateTestEngine(fixturesOpts); err != nil {
  71. fatalTestError("Error creating test engine: %v\n", err)
  72. }
  73. setting.IsInTesting = true
  74. setting.AppURL = "https://try.gitea.io/"
  75. setting.Domain = "try.gitea.io"
  76. setting.RunUser = "runuser"
  77. setting.SSH.User = "sshuser"
  78. setting.SSH.BuiltinServerUser = "builtinuser"
  79. setting.SSH.Port = 3000
  80. setting.SSH.Domain = "try.gitea.io"
  81. setting.Database.Type = "sqlite3"
  82. setting.Repository.DefaultBranch = "master" // many test code still assume that default branch is called "master"
  83. repoRootPath, cleanup1, err := tempdir.OsTempDir("gitea-test").MkdirTempRandom("repos")
  84. if err != nil {
  85. fatalTestError("TempDir: %v\n", err)
  86. }
  87. defer cleanup1()
  88. setting.RepoRootPath = repoRootPath
  89. appDataPath, cleanup2, err := tempdir.OsTempDir("gitea-test").MkdirTempRandom("appdata")
  90. if err != nil {
  91. fatalTestError("TempDir: %v\n", err)
  92. }
  93. defer cleanup2()
  94. setting.AppDataPath = appDataPath
  95. setting.AppWorkPath = giteaRoot
  96. setting.StaticRootPath = giteaRoot
  97. setting.GravatarSource = "https://secure.gravatar.com/avatar/"
  98. setting.Attachment.Storage.Path = filepath.Join(setting.AppDataPath, "attachments")
  99. setting.LFS.Storage.Path = filepath.Join(setting.AppDataPath, "lfs")
  100. setting.Avatar.Storage.Path = filepath.Join(setting.AppDataPath, "avatars")
  101. setting.RepoAvatar.Storage.Path = filepath.Join(setting.AppDataPath, "repo-avatars")
  102. setting.RepoArchive.Storage.Path = filepath.Join(setting.AppDataPath, "repo-archive")
  103. setting.Packages.Storage.Path = filepath.Join(setting.AppDataPath, "packages")
  104. setting.Actions.LogStorage.Path = filepath.Join(setting.AppDataPath, "actions_log")
  105. setting.Git.HomePath = filepath.Join(setting.AppDataPath, "home")
  106. setting.IncomingEmail.ReplyToAddress = "incoming+%{token}@localhost"
  107. config.SetDynGetter(system.NewDatabaseDynKeyGetter())
  108. if err = cache.Init(); err != nil {
  109. fatalTestError("cache.Init: %v\n", err)
  110. }
  111. if err = storage.Init(); err != nil {
  112. fatalTestError("storage.Init: %v\n", err)
  113. }
  114. if err = SyncDirs(filepath.Join(giteaRoot, "tests", "gitea-repositories-meta"), setting.RepoRootPath); err != nil {
  115. fatalTestError("util.SyncDirs: %v\n", err)
  116. }
  117. if err = git.InitFull(); err != nil {
  118. fatalTestError("git.Init: %v\n", err)
  119. }
  120. if testOpts.SetUp != nil {
  121. if err := testOpts.SetUp(); err != nil {
  122. fatalTestError("set up failed: %v\n", err)
  123. }
  124. }
  125. exitStatus := m.Run()
  126. if testOpts.TearDown != nil {
  127. if err := testOpts.TearDown(); err != nil {
  128. fatalTestError("tear down failed: %v\n", err)
  129. }
  130. }
  131. os.Exit(exitStatus)
  132. }
  133. // FixturesOptions fixtures needs to be loaded options
  134. type FixturesOptions struct {
  135. Dir string
  136. Files []string
  137. }
  138. // CreateTestEngine creates a memory database and loads the fixture data from fixturesDir
  139. func CreateTestEngine(opts FixturesOptions) error {
  140. x, err := xorm.NewEngine("sqlite3", "file::memory:?cache=shared&_txlock=immediate")
  141. if err != nil {
  142. if strings.Contains(err.Error(), "unknown driver") {
  143. return fmt.Errorf(`sqlite3 requires: -tags sqlite,sqlite_unlock_notify%s%w`, "\n", err)
  144. }
  145. return err
  146. }
  147. x.SetMapper(names.GonicMapper{})
  148. db.SetDefaultEngine(context.Background(), x)
  149. if err = db.SyncAllTables(); err != nil {
  150. return err
  151. }
  152. switch os.Getenv("GITEA_UNIT_TESTS_LOG_SQL") {
  153. case "true", "1":
  154. x.ShowSQL(true)
  155. }
  156. return InitFixtures(opts)
  157. }
  158. // PrepareTestDatabase load test fixtures into test database
  159. func PrepareTestDatabase() error {
  160. return LoadFixtures()
  161. }
  162. // PrepareTestEnv prepares the environment for unit tests. Can only be called
  163. // by tests that use the above MainTest(..) function.
  164. func PrepareTestEnv(t testing.TB) {
  165. assert.NoError(t, PrepareTestDatabase())
  166. metaPath := filepath.Join(giteaRoot, "tests", "gitea-repositories-meta")
  167. assert.NoError(t, SyncDirs(metaPath, setting.RepoRootPath))
  168. test.SetupGiteaRoot() // Makes sure GITEA_ROOT is set
  169. }