You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

test_utils.go 9.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. // Copyright 2017 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. //nolint:forbidigo
  4. package tests
  5. import (
  6. "context"
  7. "database/sql"
  8. "fmt"
  9. "os"
  10. "path"
  11. "path/filepath"
  12. "testing"
  13. "code.gitea.io/gitea/models/db"
  14. packages_model "code.gitea.io/gitea/models/packages"
  15. "code.gitea.io/gitea/models/unittest"
  16. "code.gitea.io/gitea/modules/base"
  17. "code.gitea.io/gitea/modules/git"
  18. "code.gitea.io/gitea/modules/graceful"
  19. "code.gitea.io/gitea/modules/log"
  20. repo_module "code.gitea.io/gitea/modules/repository"
  21. "code.gitea.io/gitea/modules/setting"
  22. "code.gitea.io/gitea/modules/storage"
  23. "code.gitea.io/gitea/modules/testlogger"
  24. "code.gitea.io/gitea/modules/util"
  25. "code.gitea.io/gitea/routers"
  26. "github.com/stretchr/testify/assert"
  27. )
  28. func exitf(format string, args ...any) {
  29. fmt.Printf(format+"\n", args...)
  30. os.Exit(1)
  31. }
  32. func InitTest(requireGitea bool) {
  33. log.RegisterEventWriter("test", testlogger.NewTestLoggerWriter)
  34. giteaRoot := base.SetupGiteaRoot()
  35. if giteaRoot == "" {
  36. exitf("Environment variable $GITEA_ROOT not set")
  37. }
  38. // TODO: Speedup tests that rely on the event source ticker, confirm whether there is any bug or failure.
  39. // setting.UI.Notification.EventSourceUpdateTime = time.Second
  40. setting.IsInTesting = true
  41. setting.AppWorkPath = giteaRoot
  42. setting.CustomPath = filepath.Join(setting.AppWorkPath, "custom")
  43. if requireGitea {
  44. giteaBinary := "gitea"
  45. if setting.IsWindows {
  46. giteaBinary += ".exe"
  47. }
  48. setting.AppPath = path.Join(giteaRoot, giteaBinary)
  49. if _, err := os.Stat(setting.AppPath); err != nil {
  50. exitf("Could not find gitea binary at %s", setting.AppPath)
  51. }
  52. }
  53. giteaConf := os.Getenv("GITEA_CONF")
  54. if giteaConf == "" {
  55. // By default, use sqlite.ini for testing, then IDE like GoLand can start the test process with debugger.
  56. // It's easier for developers to debug bugs step by step with a debugger.
  57. // Notice: when doing "ssh push", Gitea executes sub processes, debugger won't work for the sub processes.
  58. giteaConf = "tests/sqlite.ini"
  59. _ = os.Setenv("GITEA_CONF", giteaConf)
  60. fmt.Printf("Environment variable $GITEA_CONF not set, use default: %s\n", giteaConf)
  61. if !setting.EnableSQLite3 {
  62. exitf(`sqlite3 requires: import _ "github.com/mattn/go-sqlite3" or -tags sqlite,sqlite_unlock_notify`)
  63. }
  64. }
  65. if !path.IsAbs(giteaConf) {
  66. setting.CustomConf = filepath.Join(giteaRoot, giteaConf)
  67. } else {
  68. setting.CustomConf = giteaConf
  69. }
  70. unittest.InitSettings()
  71. setting.Repository.DefaultBranch = "master" // many test code still assume that default branch is called "master"
  72. _ = util.RemoveAll(repo_module.LocalCopyPath())
  73. if err := git.InitFull(context.Background()); err != nil {
  74. log.Fatal("git.InitOnceWithSync: %v", err)
  75. }
  76. setting.LoadDBSetting()
  77. if err := storage.Init(); err != nil {
  78. exitf("Init storage failed: %v", err)
  79. }
  80. switch {
  81. case setting.Database.Type.IsMySQL():
  82. connType := "tcp"
  83. if len(setting.Database.Host) > 0 && setting.Database.Host[0] == '/' { // looks like a unix socket
  84. connType = "unix"
  85. }
  86. db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@%s(%s)/",
  87. setting.Database.User, setting.Database.Passwd, connType, setting.Database.Host))
  88. defer db.Close()
  89. if err != nil {
  90. log.Fatal("sql.Open: %v", err)
  91. }
  92. if _, err = db.Exec(fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s", setting.Database.Name)); err != nil {
  93. log.Fatal("db.Exec: %v", err)
  94. }
  95. case setting.Database.Type.IsPostgreSQL():
  96. var db *sql.DB
  97. var err error
  98. if setting.Database.Host[0] == '/' {
  99. db, err = sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@/%s?sslmode=%s&host=%s",
  100. setting.Database.User, setting.Database.Passwd, setting.Database.Name, setting.Database.SSLMode, setting.Database.Host))
  101. } else {
  102. db, err = sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=%s",
  103. setting.Database.User, setting.Database.Passwd, setting.Database.Host, setting.Database.Name, setting.Database.SSLMode))
  104. }
  105. defer db.Close()
  106. if err != nil {
  107. log.Fatal("sql.Open: %v", err)
  108. }
  109. dbrows, err := db.Query(fmt.Sprintf("SELECT 1 FROM pg_database WHERE datname = '%s'", setting.Database.Name))
  110. if err != nil {
  111. log.Fatal("db.Query: %v", err)
  112. }
  113. defer dbrows.Close()
  114. if !dbrows.Next() {
  115. if _, err = db.Exec(fmt.Sprintf("CREATE DATABASE %s", setting.Database.Name)); err != nil {
  116. log.Fatal("db.Exec: CREATE DATABASE: %v", err)
  117. }
  118. }
  119. // Check if we need to setup a specific schema
  120. if len(setting.Database.Schema) == 0 {
  121. break
  122. }
  123. db.Close()
  124. if setting.Database.Host[0] == '/' {
  125. db, err = sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@/%s?sslmode=%s&host=%s",
  126. setting.Database.User, setting.Database.Passwd, setting.Database.Name, setting.Database.SSLMode, setting.Database.Host))
  127. } else {
  128. db, err = sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=%s",
  129. setting.Database.User, setting.Database.Passwd, setting.Database.Host, setting.Database.Name, setting.Database.SSLMode))
  130. }
  131. // This is a different db object; requires a different Close()
  132. defer db.Close()
  133. if err != nil {
  134. log.Fatal("sql.Open: %v", err)
  135. }
  136. schrows, err := db.Query(fmt.Sprintf("SELECT 1 FROM information_schema.schemata WHERE schema_name = '%s'", setting.Database.Schema))
  137. if err != nil {
  138. log.Fatal("db.Query: %v", err)
  139. }
  140. defer schrows.Close()
  141. if !schrows.Next() {
  142. // Create and setup a DB schema
  143. if _, err = db.Exec(fmt.Sprintf("CREATE SCHEMA %s", setting.Database.Schema)); err != nil {
  144. log.Fatal("db.Exec: CREATE SCHEMA: %v", err)
  145. }
  146. }
  147. case setting.Database.Type.IsMSSQL():
  148. host, port := setting.ParseMSSQLHostPort(setting.Database.Host)
  149. db, err := sql.Open("mssql", fmt.Sprintf("server=%s; port=%s; database=%s; user id=%s; password=%s;",
  150. host, port, "master", setting.Database.User, setting.Database.Passwd))
  151. if err != nil {
  152. log.Fatal("sql.Open: %v", err)
  153. }
  154. if _, err := db.Exec(fmt.Sprintf("If(db_id(N'%s') IS NULL) BEGIN CREATE DATABASE %s; END;", setting.Database.Name, setting.Database.Name)); err != nil {
  155. log.Fatal("db.Exec: %v", err)
  156. }
  157. defer db.Close()
  158. }
  159. routers.InitWebInstalled(graceful.GetManager().HammerContext())
  160. }
  161. func PrepareAttachmentsStorage(t testing.TB) {
  162. // prepare attachments directory and files
  163. assert.NoError(t, storage.Clean(storage.Attachments))
  164. s, err := storage.NewStorage(setting.LocalStorageType, &setting.Storage{
  165. Path: filepath.Join(filepath.Dir(setting.AppPath), "tests", "testdata", "data", "attachments"),
  166. })
  167. assert.NoError(t, err)
  168. assert.NoError(t, s.IterateObjects("", func(p string, obj storage.Object) error {
  169. _, err = storage.Copy(storage.Attachments, p, s, p)
  170. return err
  171. }))
  172. }
  173. func PrepareTestEnv(t testing.TB, skip ...int) func() {
  174. t.Helper()
  175. ourSkip := 1
  176. if len(skip) > 0 {
  177. ourSkip += skip[0]
  178. }
  179. deferFn := PrintCurrentTest(t, ourSkip)
  180. // load database fixtures
  181. assert.NoError(t, unittest.LoadFixtures())
  182. // load git repo fixtures
  183. assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
  184. assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "tests/gitea-repositories-meta"), setting.RepoRootPath))
  185. ownerDirs, err := os.ReadDir(setting.RepoRootPath)
  186. if err != nil {
  187. assert.NoError(t, err, "unable to read the new repo root: %v\n", err)
  188. }
  189. for _, ownerDir := range ownerDirs {
  190. if !ownerDir.Type().IsDir() {
  191. continue
  192. }
  193. repoDirs, err := os.ReadDir(filepath.Join(setting.RepoRootPath, ownerDir.Name()))
  194. if err != nil {
  195. assert.NoError(t, err, "unable to read the new repo root: %v\n", err)
  196. }
  197. for _, repoDir := range repoDirs {
  198. _ = os.MkdirAll(filepath.Join(setting.RepoRootPath, ownerDir.Name(), repoDir.Name(), "objects", "pack"), 0o755)
  199. _ = os.MkdirAll(filepath.Join(setting.RepoRootPath, ownerDir.Name(), repoDir.Name(), "objects", "info"), 0o755)
  200. _ = os.MkdirAll(filepath.Join(setting.RepoRootPath, ownerDir.Name(), repoDir.Name(), "refs", "heads"), 0o755)
  201. _ = os.MkdirAll(filepath.Join(setting.RepoRootPath, ownerDir.Name(), repoDir.Name(), "refs", "tag"), 0o755)
  202. }
  203. }
  204. // load LFS object fixtures
  205. // (LFS storage can be on any of several backends, including remote servers, so we init it with the storage API)
  206. lfsFixtures, err := storage.NewStorage(setting.LocalStorageType, &setting.Storage{
  207. Path: filepath.Join(filepath.Dir(setting.AppPath), "tests/gitea-lfs-meta"),
  208. })
  209. assert.NoError(t, err)
  210. assert.NoError(t, storage.Clean(storage.LFS))
  211. assert.NoError(t, lfsFixtures.IterateObjects("", func(path string, _ storage.Object) error {
  212. _, err := storage.Copy(storage.LFS, path, lfsFixtures, path)
  213. return err
  214. }))
  215. // clear all package data
  216. assert.NoError(t, db.TruncateBeans(db.DefaultContext,
  217. &packages_model.Package{},
  218. &packages_model.PackageVersion{},
  219. &packages_model.PackageFile{},
  220. &packages_model.PackageBlob{},
  221. &packages_model.PackageProperty{},
  222. &packages_model.PackageBlobUpload{},
  223. &packages_model.PackageCleanupRule{},
  224. ))
  225. assert.NoError(t, storage.Clean(storage.Packages))
  226. return deferFn
  227. }
  228. func PrintCurrentTest(t testing.TB, skip ...int) func() {
  229. t.Helper()
  230. actualSkip := 1
  231. if len(skip) > 0 {
  232. actualSkip = skip[0] + 1
  233. }
  234. return testlogger.PrintCurrentTest(t, actualSkip)
  235. }
  236. // Printf takes a format and args and prints the string to os.Stdout
  237. func Printf(format string, args ...any) {
  238. testlogger.Printf(format, args...)
  239. }