gitea源码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  1. // Copyright 2017 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package integration
  4. import (
  5. "fmt"
  6. "net/http"
  7. "os"
  8. "path"
  9. "strconv"
  10. "strings"
  11. "testing"
  12. "time"
  13. repo_model "code.gitea.io/gitea/models/repo"
  14. "code.gitea.io/gitea/models/unit"
  15. "code.gitea.io/gitea/models/unittest"
  16. user_model "code.gitea.io/gitea/models/user"
  17. "code.gitea.io/gitea/modules/setting"
  18. "code.gitea.io/gitea/modules/test"
  19. "code.gitea.io/gitea/modules/util"
  20. repo_service "code.gitea.io/gitea/services/repository"
  21. "code.gitea.io/gitea/tests"
  22. "github.com/PuerkitoBio/goquery"
  23. "github.com/stretchr/testify/assert"
  24. "github.com/stretchr/testify/require"
  25. )
  26. func TestRepoView(t *testing.T) {
  27. defer tests.PrepareTestEnv(t)()
  28. t.Run("ViewRepoPublic", testViewRepoPublic)
  29. t.Run("ViewRepoWithCache", testViewRepoWithCache)
  30. t.Run("ViewRepoPrivate", testViewRepoPrivate)
  31. t.Run("ViewRepo1CloneLinkAnonymous", testViewRepo1CloneLinkAnonymous)
  32. t.Run("ViewRepo1CloneLinkAuthorized", testViewRepo1CloneLinkAuthorized)
  33. t.Run("ViewRepoWithSymlinks", testViewRepoWithSymlinks)
  34. t.Run("ViewFileInRepo", testViewFileInRepo)
  35. t.Run("BlameFileInRepo", testBlameFileInRepo)
  36. t.Run("ViewRepoDirectory", testViewRepoDirectory)
  37. t.Run("ViewRepoDirectoryReadme", testViewRepoDirectoryReadme)
  38. t.Run("ViewRepoSymlink", testViewRepoSymlink)
  39. t.Run("MarkDownReadmeImage", testMarkDownReadmeImage)
  40. t.Run("MarkDownReadmeImageSubfolder", testMarkDownReadmeImageSubfolder)
  41. t.Run("GeneratedSourceLink", testGeneratedSourceLink)
  42. t.Run("ViewCommit", testViewCommit)
  43. }
  44. func testViewRepoPublic(t *testing.T) {
  45. defer tests.PrintCurrentTest(t)()
  46. session := loginUser(t, "user2")
  47. req := NewRequest(t, "GET", "/user2/repo1")
  48. resp := session.MakeRequest(t, req, http.StatusOK)
  49. htmlDoc := NewHTMLParser(t, resp.Body)
  50. repoTopics := htmlDoc.doc.Find("#repo-topics").Children()
  51. repoSummary := htmlDoc.doc.Find(".repository-summary").Children()
  52. assert.True(t, repoTopics.HasClass("repo-topic"))
  53. assert.True(t, repoSummary.HasClass("repository-menu"))
  54. req = NewRequest(t, "GET", "/org3/repo3")
  55. MakeRequest(t, req, http.StatusNotFound)
  56. session = loginUser(t, "user1")
  57. session.MakeRequest(t, req, http.StatusNotFound)
  58. }
  59. func testViewRepoWithCache(t *testing.T) {
  60. defer tests.PrintCurrentTest(t)()
  61. testView := func(t *testing.T) {
  62. req := NewRequest(t, "GET", "/org3/repo3")
  63. session := loginUser(t, "user2")
  64. resp := session.MakeRequest(t, req, http.StatusOK)
  65. htmlDoc := NewHTMLParser(t, resp.Body)
  66. files := htmlDoc.doc.Find("#repo-files-table .repo-file-item")
  67. type file struct {
  68. fileName string
  69. commitID string
  70. commitMsg string
  71. commitTime string
  72. }
  73. var items []file
  74. files.Each(func(i int, s *goquery.Selection) {
  75. tds := s.Find(".repo-file-cell")
  76. var f file
  77. tds.Each(func(i int, s *goquery.Selection) {
  78. if i == 0 {
  79. f.fileName = strings.TrimSpace(s.Text())
  80. } else if i == 1 {
  81. a := s.Find("a")
  82. f.commitMsg = strings.TrimSpace(a.Text())
  83. l, _ := a.Attr("href")
  84. f.commitID = path.Base(l)
  85. }
  86. })
  87. // convert "2017-06-14 21:54:21 +0800" to "Wed, 14 Jun 2017 13:54:21 UTC"
  88. htmlTimeString, _ := s.Find("relative-time").Attr("datetime")
  89. htmlTime, _ := time.Parse(time.RFC3339, htmlTimeString)
  90. f.commitTime = htmlTime.In(time.Local).Format(time.RFC1123)
  91. items = append(items, f)
  92. })
  93. commitT := time.Date(2017, time.June, 14, 13, 54, 21, 0, time.UTC).In(time.Local).Format(time.RFC1123)
  94. assert.Equal(t, []file{
  95. {
  96. fileName: "doc",
  97. commitID: "2a47ca4b614a9f5a43abbd5ad851a54a616ffee6",
  98. commitMsg: "init project",
  99. commitTime: commitT,
  100. },
  101. {
  102. fileName: "README.md",
  103. commitID: "2a47ca4b614a9f5a43abbd5ad851a54a616ffee6",
  104. commitMsg: "init project",
  105. commitTime: commitT,
  106. },
  107. }, items)
  108. }
  109. // FIXME: these test don't seem quite right, no enough assert
  110. // no last commit cache
  111. testView(t)
  112. // enable last commit cache for all repositories
  113. oldCommitsCount := setting.CacheService.LastCommit.CommitsCount
  114. setting.CacheService.LastCommit.CommitsCount = 0
  115. // first view will not hit the cache
  116. testView(t)
  117. // second view will hit the cache
  118. testView(t)
  119. setting.CacheService.LastCommit.CommitsCount = oldCommitsCount
  120. }
  121. func testViewRepoPrivate(t *testing.T) {
  122. defer tests.PrintCurrentTest(t)()
  123. req := NewRequest(t, "GET", "/org3/repo3")
  124. MakeRequest(t, req, http.StatusNotFound)
  125. t.Run("OrgMemberAccess", func(t *testing.T) {
  126. req = NewRequest(t, "GET", "/org3/repo3")
  127. session := loginUser(t, "user4")
  128. resp := session.MakeRequest(t, req, http.StatusOK)
  129. assert.Contains(t, resp.Body.String(), `<div id="repo-files-table"`)
  130. })
  131. t.Run("PublicAccess-AnonymousAccess", func(t *testing.T) {
  132. session := loginUser(t, "user1")
  133. // set unit code to "anonymous read"
  134. req = NewRequestWithValues(t, "POST", "/org3/repo3/settings/public_access", map[string]string{
  135. "_csrf": GetUserCSRFToken(t, session),
  136. "repo-unit-access-" + strconv.Itoa(int(unit.TypeCode)): "anonymous-read",
  137. })
  138. session.MakeRequest(t, req, http.StatusSeeOther)
  139. // try to "anonymous read" (ok)
  140. req = NewRequest(t, "GET", "/org3/repo3")
  141. resp := MakeRequest(t, req, http.StatusOK)
  142. assert.Contains(t, resp.Body.String(), `<span class="ui basic orange label">Public Access</span>`)
  143. // remove "anonymous read"
  144. req = NewRequestWithValues(t, "POST", "/org3/repo3/settings/public_access", map[string]string{
  145. "_csrf": GetUserCSRFToken(t, session),
  146. })
  147. session.MakeRequest(t, req, http.StatusSeeOther)
  148. // try to "anonymous read" (not found)
  149. req = NewRequest(t, "GET", "/org3/repo3")
  150. MakeRequest(t, req, http.StatusNotFound)
  151. })
  152. }
  153. func testViewRepo1CloneLinkAnonymous(t *testing.T) {
  154. defer tests.PrintCurrentTest(t)()
  155. req := NewRequest(t, "GET", "/user2/repo1")
  156. resp := MakeRequest(t, req, http.StatusOK)
  157. htmlDoc := NewHTMLParser(t, resp.Body)
  158. link, exists := htmlDoc.doc.Find(".repo-clone-https").Attr("data-link")
  159. assert.True(t, exists, "The template has changed")
  160. assert.Equal(t, setting.AppURL+"user2/repo1.git", link)
  161. _, exists = htmlDoc.doc.Find(".repo-clone-ssh").Attr("data-link")
  162. assert.False(t, exists)
  163. link, exists = htmlDoc.doc.Find(".repo-clone-tea").Attr("data-link")
  164. assert.True(t, exists, "The template has changed")
  165. assert.Equal(t, "tea clone user2/repo1", link)
  166. }
  167. func testViewRepo1CloneLinkAuthorized(t *testing.T) {
  168. defer tests.PrintCurrentTest(t)()
  169. session := loginUser(t, "user2")
  170. req := NewRequest(t, "GET", "/user2/repo1")
  171. resp := session.MakeRequest(t, req, http.StatusOK)
  172. htmlDoc := NewHTMLParser(t, resp.Body)
  173. link, exists := htmlDoc.doc.Find(".repo-clone-https").Attr("data-link")
  174. assert.True(t, exists, "The template has changed")
  175. assert.Equal(t, setting.AppURL+"user2/repo1.git", link)
  176. link, exists = htmlDoc.doc.Find(".repo-clone-ssh").Attr("data-link")
  177. assert.True(t, exists, "The template has changed")
  178. sshURL := fmt.Sprintf("ssh://%s@%s:%d/user2/repo1.git", setting.SSH.User, setting.SSH.Domain, setting.SSH.Port)
  179. assert.Equal(t, sshURL, link)
  180. link, exists = htmlDoc.doc.Find(".repo-clone-tea").Attr("data-link")
  181. assert.True(t, exists, "The template has changed")
  182. assert.Equal(t, "tea clone user2/repo1", link)
  183. }
  184. func testViewRepoWithSymlinks(t *testing.T) {
  185. defer tests.PrintCurrentTest(t)()
  186. defer test.MockVariableValue(&setting.UI.FileIconTheme, "basic")()
  187. session := loginUser(t, "user2")
  188. req := NewRequest(t, "GET", "/user2/repo20.git")
  189. resp := session.MakeRequest(t, req, http.StatusOK)
  190. htmlDoc := NewHTMLParser(t, resp.Body)
  191. files := htmlDoc.doc.Find("#repo-files-table .repo-file-cell.name")
  192. items := files.Map(func(i int, s *goquery.Selection) string {
  193. cls, _ := s.Find("SVG").Attr("class")
  194. file := strings.Trim(s.Find("A").Text(), " \t\n")
  195. return fmt.Sprintf("%s: %s", file, cls)
  196. })
  197. assert.Len(t, items, 5)
  198. assert.Equal(t, "a: svg octicon-file-directory-fill", items[0])
  199. assert.Equal(t, "link_b: svg octicon-file-directory-symlink", items[1])
  200. assert.Equal(t, "link_d: svg octicon-file-symlink-file", items[2])
  201. assert.Equal(t, "link_hi: svg octicon-file-symlink-file", items[3])
  202. assert.Equal(t, "link_link: svg octicon-file-symlink-file", items[4])
  203. }
  204. // TestViewFileInRepo repo description, topics and summary should not be displayed when viewing a file
  205. func testViewFileInRepo(t *testing.T) {
  206. defer tests.PrintCurrentTest(t)()
  207. session := loginUser(t, "user2")
  208. req := NewRequest(t, "GET", "/user2/repo1/src/branch/master/README.md")
  209. resp := session.MakeRequest(t, req, http.StatusOK)
  210. htmlDoc := NewHTMLParser(t, resp.Body)
  211. description := htmlDoc.doc.Find(".repo-description")
  212. repoTopics := htmlDoc.doc.Find("#repo-topics")
  213. repoSummary := htmlDoc.doc.Find(".repository-summary")
  214. assert.Equal(t, 0, description.Length())
  215. assert.Equal(t, 0, repoTopics.Length())
  216. assert.Equal(t, 0, repoSummary.Length())
  217. }
  218. // TestBlameFileInRepo repo description, topics and summary should not be displayed when running blame on a file
  219. func testBlameFileInRepo(t *testing.T) {
  220. defer tests.PrintCurrentTest(t)()
  221. session := loginUser(t, "user2")
  222. req := NewRequest(t, "GET", "/user2/repo1/blame/branch/master/README.md")
  223. resp := session.MakeRequest(t, req, http.StatusOK)
  224. htmlDoc := NewHTMLParser(t, resp.Body)
  225. description := htmlDoc.doc.Find(".repo-description")
  226. repoTopics := htmlDoc.doc.Find("#repo-topics")
  227. repoSummary := htmlDoc.doc.Find(".repository-summary")
  228. assert.Equal(t, 0, description.Length())
  229. assert.Equal(t, 0, repoTopics.Length())
  230. assert.Equal(t, 0, repoSummary.Length())
  231. }
  232. // TestViewRepoDirectory repo description, topics and summary should not be displayed when within a directory
  233. func testViewRepoDirectory(t *testing.T) {
  234. defer tests.PrintCurrentTest(t)()
  235. session := loginUser(t, "user2")
  236. req := NewRequest(t, "GET", "/user2/repo20/src/branch/master/a")
  237. resp := session.MakeRequest(t, req, http.StatusOK)
  238. htmlDoc := NewHTMLParser(t, resp.Body)
  239. description := htmlDoc.doc.Find(".repo-description")
  240. repoTopics := htmlDoc.doc.Find("#repo-topics")
  241. repoSummary := htmlDoc.doc.Find(".repository-summary")
  242. repoFilesTable := htmlDoc.doc.Find("#repo-files-table")
  243. assert.NotEmpty(t, repoFilesTable.Nodes)
  244. assert.Zero(t, description.Length())
  245. assert.Zero(t, repoTopics.Length())
  246. assert.Zero(t, repoSummary.Length())
  247. }
  248. // ensure that the all the different ways to find and render a README work
  249. func testViewRepoDirectoryReadme(t *testing.T) {
  250. defer tests.PrintCurrentTest(t)()
  251. // there are many combinations:
  252. // - READMEs can be .md, .txt, or have no extension
  253. // - READMEs can be tagged with a language and even a country code
  254. // - READMEs can be stored in docs/, .gitea/, or .github/
  255. // - READMEs can be symlinks to other files
  256. // - READMEs can be broken symlinks which should not render
  257. //
  258. // this doesn't cover all possible cases, just the major branches of the code
  259. session := loginUser(t, "user2")
  260. check := func(name, url, expectedFilename, expectedReadmeType, expectedContent string) {
  261. t.Run(name, func(t *testing.T) {
  262. defer tests.PrintCurrentTest(t)()
  263. req := NewRequest(t, "GET", url)
  264. resp := session.MakeRequest(t, req, http.StatusOK)
  265. htmlDoc := NewHTMLParser(t, resp.Body)
  266. readmeName := htmlDoc.doc.Find("h4.file-header")
  267. readmeContent := htmlDoc.doc.Find(".file-view") // TODO: add a id="readme" to the output to make this test more precise
  268. readmeType, _ := readmeContent.Attr("class")
  269. assert.Equal(t, expectedFilename, strings.TrimSpace(readmeName.Text()))
  270. assert.Contains(t, readmeType, expectedReadmeType)
  271. assert.Contains(t, readmeContent.Text(), expectedContent)
  272. })
  273. }
  274. // viewing the top level
  275. check("Home", "/user2/readme-test/", "README.md", "markdown", "The cake is a lie.")
  276. // viewing different file extensions
  277. check("md", "/user2/readme-test/src/branch/master/", "README.md", "markdown", "The cake is a lie.")
  278. check("txt", "/user2/readme-test/src/branch/txt/", "README.txt", "plain-text", "My spoon is too big.")
  279. check("plain", "/user2/readme-test/src/branch/plain/", "README", "plain-text", "Birken my stocks gee howdy")
  280. check("i18n", "/user2/readme-test/src/branch/i18n/", "README.zh.md", "markdown", "蛋糕是一个谎言")
  281. // using HEAD ref
  282. check("branch-HEAD", "/user2/readme-test/src/branch/HEAD/", "README.md", "markdown", "The cake is a lie.")
  283. check("commit-HEAD", "/user2/readme-test/src/commit/HEAD/", "README.md", "markdown", "The cake is a lie.")
  284. // viewing different subdirectories
  285. check("subdir", "/user2/readme-test/src/branch/subdir/libcake", "README.md", "markdown", "Four pints of sugar.")
  286. check("docs-direct", "/user2/readme-test/src/branch/special-subdir-docs/docs/", "README.md", "markdown", "This is in docs/")
  287. check("docs", "/user2/readme-test/src/branch/special-subdir-docs/", "docs/README.md", "markdown", "This is in docs/")
  288. check(".gitea", "/user2/readme-test/src/branch/special-subdir-.gitea/", ".gitea/README.md", "markdown", "This is in .gitea/")
  289. check(".github", "/user2/readme-test/src/branch/special-subdir-.github/", ".github/README.md", "markdown", "This is in .github/")
  290. // symlinks
  291. // symlinks are subtle:
  292. // - they should be able to handle going a reasonable number of times up and down in the tree
  293. // - they shouldn't get stuck on link cycles
  294. // - they should determine the filetype based on the name of the link, not the target
  295. check("symlink", "/user2/readme-test/src/branch/symlink/", "README.md", "markdown", "This is in some/other/path")
  296. check("symlink-multiple", "/user2/readme-test/src/branch/symlink/some/", "README.txt", "plain-text", "This is in some/other/path")
  297. check("symlink-up-and-down", "/user2/readme-test/src/branch/symlink/up/back/down/down", "README.md", "markdown", "It's a me, mario")
  298. // testing fallback rules
  299. // READMEs are searched in this order:
  300. // - [README.zh-cn.md, README.zh_cn.md, README.zh.md, README_zh.md, README.md, README.txt, README,
  301. // docs/README.zh-cn.md, docs/README.zh_cn.md, docs/README.zh.md, docs/README_zh.md, docs/README.md, docs/README.txt, docs/README,
  302. // .gitea/README.zh-cn.md, .gitea/README.zh_cn.md, .gitea/README.zh.md, .gitea/README_zh.md, .gitea/README.md, .gitea/README.txt, .gitea/README,
  303. // .github/README.zh-cn.md, .github/README.zh_cn.md, .github/README.zh.md, .github/README_zh.md, .github/README.md, .github/README.txt, .github/README]
  304. // and a broken/looped symlink counts as not existing at all and should be skipped.
  305. // again, this doesn't cover all cases, but it covers a few
  306. check("fallback/top", "/user2/readme-test/src/branch/fallbacks/", "README.en.md", "markdown", "This is README.en.md")
  307. check("fallback/2", "/user2/readme-test/src/branch/fallbacks2/", "README.md", "markdown", "This is README.md")
  308. check("fallback/3", "/user2/readme-test/src/branch/fallbacks3/", "README", "plain-text", "This is README")
  309. check("fallback/4", "/user2/readme-test/src/branch/fallbacks4/", "docs/README.en.md", "markdown", "This is docs/README.en.md")
  310. check("fallback/5", "/user2/readme-test/src/branch/fallbacks5/", "docs/README.md", "markdown", "This is docs/README.md")
  311. check("fallback/6", "/user2/readme-test/src/branch/fallbacks6/", "docs/README", "plain-text", "This is docs/README")
  312. check("fallback/7", "/user2/readme-test/src/branch/fallbacks7/", ".gitea/README.en.md", "markdown", "This is .gitea/README.en.md")
  313. check("fallback/8", "/user2/readme-test/src/branch/fallbacks8/", ".gitea/README.md", "markdown", "This is .gitea/README.md")
  314. check("fallback/9", "/user2/readme-test/src/branch/fallbacks9/", ".gitea/README", "plain-text", "This is .gitea/README")
  315. // this case tests that broken symlinks count as missing files, instead of rendering their contents
  316. check("fallbacks-broken-symlinks", "/user2/readme-test/src/branch/fallbacks-broken-symlinks/", "docs/README", "plain-text", "This is docs/README")
  317. // some cases that should NOT render a README
  318. // - /readme
  319. // - /.github/docs/README.md
  320. // - a symlink loop
  321. missing := func(name, url string) {
  322. t.Run("missing/"+name, func(t *testing.T) {
  323. defer tests.PrintCurrentTest(t)()
  324. req := NewRequest(t, "GET", url)
  325. resp := session.MakeRequest(t, req, http.StatusOK)
  326. htmlDoc := NewHTMLParser(t, resp.Body)
  327. _, exists := htmlDoc.doc.Find(".file-view").Attr("class")
  328. assert.False(t, exists, "README should not have rendered")
  329. })
  330. }
  331. missing("sp-ace", "/user2/readme-test/src/branch/sp-ace/")
  332. missing("nested-special", "/user2/readme-test/src/branch/special-subdir-nested/subproject") // the special subdirs should only trigger on the repo root
  333. missing("special-subdir-nested", "/user2/readme-test/src/branch/special-subdir-nested/")
  334. missing("symlink-loop", "/user2/readme-test/src/branch/symlink-loop/")
  335. }
  336. func testViewRepoSymlink(t *testing.T) {
  337. session := loginUser(t, "user2")
  338. req := NewRequest(t, "GET", "/user2/readme-test/src/branch/symlink")
  339. resp := session.MakeRequest(t, req, http.StatusOK)
  340. htmlDoc := NewHTMLParser(t, resp.Body)
  341. AssertHTMLElement(t, htmlDoc, ".entry-symbol-link", true)
  342. followSymbolLinkHref := htmlDoc.Find(".entry-symbol-link").AttrOr("href", "")
  343. require.Equal(t, "/user2/readme-test/src/branch/symlink/README.md?follow_symlink=1", followSymbolLinkHref)
  344. req = NewRequest(t, "GET", followSymbolLinkHref)
  345. resp = session.MakeRequest(t, req, http.StatusSeeOther)
  346. assert.Equal(t, "/user2/readme-test/src/branch/symlink/some/other/path/awefulcake.txt?follow_symlink=1", resp.Header().Get("Location"))
  347. }
  348. func testMarkDownReadmeImage(t *testing.T) {
  349. defer tests.PrintCurrentTest(t)()
  350. session := loginUser(t, "user2")
  351. req := NewRequest(t, "GET", "/user2/repo1/src/branch/home-md-img-check")
  352. resp := session.MakeRequest(t, req, http.StatusOK)
  353. htmlDoc := NewHTMLParser(t, resp.Body)
  354. src, exists := htmlDoc.doc.Find(`.markdown img`).Attr("src")
  355. assert.True(t, exists, "Image not found in README")
  356. assert.Equal(t, "/user2/repo1/media/branch/home-md-img-check/test-fake-img.jpg", src)
  357. req = NewRequest(t, "GET", "/user2/repo1/src/branch/home-md-img-check/README.md")
  358. resp = session.MakeRequest(t, req, http.StatusOK)
  359. htmlDoc = NewHTMLParser(t, resp.Body)
  360. src, exists = htmlDoc.doc.Find(`.markdown img`).Attr("src")
  361. assert.True(t, exists, "Image not found in markdown file")
  362. assert.Equal(t, "/user2/repo1/media/branch/home-md-img-check/test-fake-img.jpg", src)
  363. }
  364. func testMarkDownReadmeImageSubfolder(t *testing.T) {
  365. defer tests.PrintCurrentTest(t)()
  366. session := loginUser(t, "user2")
  367. // this branch has the README in the special docs/README.md location
  368. req := NewRequest(t, "GET", "/user2/repo1/src/branch/sub-home-md-img-check")
  369. resp := session.MakeRequest(t, req, http.StatusOK)
  370. htmlDoc := NewHTMLParser(t, resp.Body)
  371. src, exists := htmlDoc.doc.Find(`.markdown img`).Attr("src")
  372. assert.True(t, exists, "Image not found in README")
  373. assert.Equal(t, "/user2/repo1/media/branch/sub-home-md-img-check/docs/test-fake-img.jpg", src)
  374. req = NewRequest(t, "GET", "/user2/repo1/src/branch/sub-home-md-img-check/docs/README.md")
  375. resp = session.MakeRequest(t, req, http.StatusOK)
  376. htmlDoc = NewHTMLParser(t, resp.Body)
  377. src, exists = htmlDoc.doc.Find(`.markdown img`).Attr("src")
  378. assert.True(t, exists, "Image not found in markdown file")
  379. assert.Equal(t, "/user2/repo1/media/branch/sub-home-md-img-check/docs/test-fake-img.jpg", src)
  380. }
  381. func testGeneratedSourceLink(t *testing.T) {
  382. defer tests.PrintCurrentTest(t)()
  383. t.Run("Rendered file", func(t *testing.T) {
  384. defer tests.PrintCurrentTest(t)()
  385. req := NewRequest(t, "GET", "/user2/repo1/src/branch/master/README.md?display=source")
  386. resp := MakeRequest(t, req, http.StatusOK)
  387. doc := NewHTMLParser(t, resp.Body)
  388. dataURL, exists := doc.doc.Find(".copy-line-permalink").Attr("data-url")
  389. assert.True(t, exists)
  390. assert.Equal(t, "/user2/repo1/src/commit/65f1bf27bc3bf70f64657658635e66094edbcb4d/README.md?display=source", dataURL)
  391. dataURL, exists = doc.doc.Find(".ref-in-new-issue").Attr("data-url-param-body-link")
  392. assert.True(t, exists)
  393. assert.Equal(t, "/user2/repo1/src/commit/65f1bf27bc3bf70f64657658635e66094edbcb4d/README.md?display=source", dataURL)
  394. })
  395. t.Run("Non-Rendered file", func(t *testing.T) {
  396. defer tests.PrintCurrentTest(t)()
  397. session := loginUser(t, "user27")
  398. req := NewRequest(t, "GET", "/user27/repo49/src/branch/master/test/test.txt")
  399. resp := session.MakeRequest(t, req, http.StatusOK)
  400. doc := NewHTMLParser(t, resp.Body)
  401. dataURL, exists := doc.doc.Find(".copy-line-permalink").Attr("data-url")
  402. assert.True(t, exists)
  403. assert.Equal(t, "/user27/repo49/src/commit/aacbdfe9e1c4b47f60abe81849045fa4e96f1d75/test/test.txt", dataURL)
  404. dataURL, exists = doc.doc.Find(".ref-in-new-issue").Attr("data-url-param-body-link")
  405. assert.True(t, exists)
  406. assert.Equal(t, "/user27/repo49/src/commit/aacbdfe9e1c4b47f60abe81849045fa4e96f1d75/test/test.txt", dataURL)
  407. })
  408. }
  409. func testViewCommit(t *testing.T) {
  410. defer tests.PrintCurrentTest(t)()
  411. req := NewRequest(t, "GET", "/user2/repo1/commit/0123456789012345678901234567890123456789")
  412. req.Header.Add("Accept", "text/html")
  413. resp := MakeRequest(t, req, http.StatusNotFound)
  414. assert.True(t, test.IsNormalPageCompleted(resp.Body.String()), "non-existing commit should render 404 page")
  415. }
  416. // TestGenerateRepository the test cannot succeed when moved as a unit test
  417. func TestGenerateRepository(t *testing.T) {
  418. defer tests.PrepareTestEnv(t)()
  419. // a successful generate from template
  420. user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
  421. repo44 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 44})
  422. generatedRepo, err := repo_service.GenerateRepository(t.Context(), user2, user2, repo44, repo_service.GenerateRepoOptions{
  423. Name: "generated-from-template-44",
  424. GitContent: true,
  425. })
  426. assert.NoError(t, err)
  427. assert.NotNil(t, generatedRepo)
  428. exist, err := util.IsExist(repo_model.RepoPath(user2.Name, generatedRepo.Name))
  429. assert.NoError(t, err)
  430. assert.True(t, exist)
  431. unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: user2.Name, Name: generatedRepo.Name})
  432. err = repo_service.DeleteRepositoryDirectly(t.Context(), generatedRepo.ID)
  433. assert.NoError(t, err)
  434. // a failed creating because some mock data
  435. // create the repository directory so that the creation will fail after database record created.
  436. assert.NoError(t, os.MkdirAll(repo_model.RepoPath(user2.Name, "generated-from-template-44"), os.ModePerm))
  437. generatedRepo2, err := repo_service.GenerateRepository(t.Context(), user2, user2, repo44, repo_service.GenerateRepoOptions{
  438. Name: "generated-from-template-44",
  439. GitContent: true,
  440. })
  441. assert.Nil(t, generatedRepo2)
  442. assert.Error(t, err)
  443. // assert the cleanup is successful
  444. unittest.AssertNotExistsBean(t, &repo_model.Repository{OwnerName: user2.Name, Name: generatedRepo.Name})
  445. exist, err = util.IsExist(repo_model.RepoPath(user2.Name, generatedRepo.Name))
  446. assert.NoError(t, err)
  447. assert.False(t, exist)
  448. }