Skip to content

Commit

Permalink
Test views of LFS files
Browse files Browse the repository at this point in the history
Follow up to go-gitea#22195:
that happened because there was no testing of how the UI
reacts to LFS files.

Until now Gitea has tested LFS via:

- the internal go API
- the external HTTP API
- the external git+http:// protocol
- the external git+ssh:// protocol

The first is small unit tests, and can create LFS structs in memory
as necessary. The latter all run `git lfs track *` and upload two random
binaries. ("code.gitea.io/gitea/tests/integration".lfsCommitAndPushTest)
In both cases, the LFS data are created by procedural code.

This is different: it adds declaractive LFS fixtures. That means a new
repo in gitea-repositories-meta/, a new folder for LFS objects in
gitea-lfs-meta/, and associated database entries in models/fixtures/.

Using this, it can easily add testing LFS via:

- the internal HTTP UI

Sources
-------

- lfs.git was hand-crafted using git commands, then `git push`ed into an
  empty bare repo.

Its contents:

- CONTRIBUTING.md (LFS object 7b6b2c88dba9f760a1a58469b67fee2b698ef7e9399c4ca4f34a14ccbe39f623)
  was hand-written.
- subdir/README.md (LFS object 9d172e5c64b4f0024b9901ec6afe9ea052f3c9b6ff9f4b07956d8c48c86fca82)
  was also hand-written.
- jpeg.jpg (LFS object 0b8d8b5f15046343fd32f451df93acc2bdd9e6373be478b968e4cad6b6647351)
  was copied from tests/gitea-repositories-meta/user2/repo1.wiki.git/
- crypt.bin (LFS object 2eccdb43825d2a49d99d542daa20075cff1d97d9d2349a8977efe9c03661737c)
  was generated with `dd if=/dev/urandom bs=1k count=2`
  • Loading branch information
kousu committed Dec 22, 2022
1 parent ea5a752 commit b6b2b6b
Show file tree
Hide file tree
Showing 27 changed files with 181 additions and 2 deletions.
2 changes: 2 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,8 @@ To maintain understandable code and avoid circular dependencies it is important
- **templates:** Golang templates for generating the html output.
- **tests/e2e:** End to end tests
- **tests/integration:** Integration tests
- **tests/gitea-repositories:** Sample repos used in integration tests. Adding a new repo requires editing `models/fixtures/repositories.yml` and `models/fixtures/repo_unit.yml` to match.
- **tests/gitea-lfs-meta:** Sample LFS objects used in integration tests. Adding a new object requires editing `models/fixtures/lfs_meta_object.yml` to match.
- **vendor:** External code that Gitea depends on.

## Documentation
Expand Down
2 changes: 1 addition & 1 deletion models/db/iterate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func TestIterate(t *testing.T) {
return nil
})
assert.NoError(t, err)
assert.EqualValues(t, 80, repoCnt)
assert.EqualValues(t, 81, repoCnt)

err = db.Iterate(db.DefaultContext, nil, func(ctx context.Context, repoUnit *repo_model.RepoUnit) error {
reopUnit2 := repo_model.RepoUnit{ID: repoUnit.ID}
Expand Down
32 changes: 32 additions & 0 deletions models/fixtures/lfs_meta_object.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# These are the LFS objects in user2/lfs.git
-

id: 1
oid: 0b8d8b5f15046343fd32f451df93acc2bdd9e6373be478b968e4cad6b6647351
size: 107
repository_id: 54
created_unix: 1671607299

-

id: 2
oid: 2eccdb43825d2a49d99d542daa20075cff1d97d9d2349a8977efe9c03661737c
size: 107
repository_id: 54
created_unix: 1671607299

-

id: 3
oid: 7b6b2c88dba9f760a1a58469b67fee2b698ef7e9399c4ca4f34a14ccbe39f623
size: 27
repository_id: 54
created_unix: 1671607299

-

id: 4
oid: 9d172e5c64b4f0024b9901ec6afe9ea052f3c9b6ff9f4b07956d8c48c86fca82
size: 25
repository_id: 54
created_unix: 1671607299
6 changes: 6 additions & 0 deletions models/fixtures/repo_unit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -550,3 +550,9 @@
repo_id: 53
type: 1
created_unix: 946684810

-
id: 81
repo_id: 54
type: 1
created_unix: 946684810
11 changes: 11 additions & 0 deletions models/fixtures/repository.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1585,3 +1585,14 @@
size: 0
is_fsck_enabled: true
close_issues_via_commit_in_any_branch: false

-
id: 54
owner_id: 2
owner_name: user2
lower_name: lfs
name: lfs
is_empty: false
is_archived: false
is_private: true
status: 0
2 changes: 1 addition & 1 deletion models/fixtures/user.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
num_followers: 2
num_following: 1
num_stars: 2
num_repos: 9
num_repos: 10
num_teams: 0
num_members: 0
visibility: 0
Expand Down
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Testing documents in LFS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Testing READMEs in LFS
1 change: 1 addition & 0 deletions tests/gitea-repositories-meta/user2/lfs.git/HEAD
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ref: refs/heads/master
4 changes: 4 additions & 0 deletions tests/gitea-repositories-meta/user2/lfs.git/config
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[core]
repositoryformatversion = 0
filemode = true
bare = true
1 change: 1 addition & 0 deletions tests/gitea-repositories-meta/user2/lfs.git/description
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Test data to see how the web UI renders files stored in Git LFS.
6 changes: 6 additions & 0 deletions tests/gitea-repositories-meta/user2/lfs.git/info/exclude
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# git ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
x��Q
B!E�v��bƗ�AD����7���0���V���¹'�Rr���M��Y0Y";2��8:/A�Ĝ&�Z�_��6�����]��g���\dk9�%�i��h�XG��?O]�g���@}97�
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
73cf03db6ece34e12bf91e8853dc58f678f2f82d
83 changes: 83 additions & 0 deletions tests/integration/lfs_view_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package integration

import (
"net/http"
"testing"

"code.gitea.io/gitea/tests"

"github.com/stretchr/testify/assert"
)

// check that files stored in LFS render properly in the web UI
func TestLFSRender(t *testing.T) {
defer tests.PrepareTestEnv(t)()

session := loginUser(t, "user2")

// check that a markup file is flagged with "Stored in Git LFS" and shows its text
t.Run("Markup", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()

req := NewRequest(t, "GET", "/user2/lfs/src/branch/master/CONTRIBUTING.md")
resp := session.MakeRequest(t, req, http.StatusOK)

doc := NewHTMLParser(t, resp.Body).doc

fileInfo := doc.Find("div.file-info-entry").First().Text()
assert.Contains(t, fileInfo, "Stored with Git LFS")

content := doc.Find("div.file-view").Text()
assert.Contains(t, content, "Testing documents in LFS")
})

// check that an image is flagged with "Stored in Git LFS" and renders inline
t.Run("Image", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()

req := NewRequest(t, "GET", "/user2/lfs/src/branch/master/jpeg.jpg")
resp := session.MakeRequest(t, req, http.StatusOK)

doc := NewHTMLParser(t, resp.Body).doc

fileInfo := doc.Find("div.file-info-entry").First().Text()
assert.Contains(t, fileInfo, "Stored with Git LFS")

src, exists := doc.Find(".file-view img").Attr("src")
assert.True(t, exists, "The image should be in an <img> tag")
assert.Equal(t, "/user2/lfs/media/branch/master/jpeg.jpg", src, "The image should use the /media link because it's in LFS")
})

// check that a binary file is flagged with "Stored in Git LFS" and renders a /media/ link instead of a /raw/ link
t.Run("Binary", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()

req := NewRequest(t, "GET", "/user2/lfs/src/branch/master/crypt.bin")
resp := session.MakeRequest(t, req, http.StatusOK)

doc := NewHTMLParser(t, resp.Body).doc

fileInfo := doc.Find("div.file-info-entry").First().Text()
assert.Contains(t, fileInfo, "Stored with Git LFS")

rawLink, exists := doc.Find("div.file-view > div.view-raw > a").Attr("href")
assert.True(t, exists, "Download link should render instead of content because this is a binary file")
assert.Equal(t, "/user2/lfs/media/branch/master/crypt.bin", rawLink, "The download link should use the proper /media link because it's in LFS")
})

// check that a directory with a README file shows its text
t.Run("Readme", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()

req := NewRequest(t, "GET", "/user2/lfs/src/branch/master/subdir")
resp := session.MakeRequest(t, req, http.StatusOK)

doc := NewHTMLParser(t, resp.Body).doc

content := doc.Find("div.file-view").Text()
assert.Contains(t, content, "Testing READMEs in LFS")
})
}
28 changes: 28 additions & 0 deletions tests/test_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,11 @@ func PrepareTestEnv(t testing.TB, skip ...int) func() {
ourSkip += skip[0]
}
deferFn := PrintCurrentTest(t, ourSkip)

// load database fixtures
assert.NoError(t, unittest.LoadFixtures())

// load git repo fixtures
assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "tests/gitea-repositories-meta"), setting.RepoRootPath))
ownerDirs, err := os.ReadDir(setting.RepoRootPath)
Expand All @@ -190,6 +194,16 @@ func PrepareTestEnv(t testing.TB, skip ...int) func() {
}
}

// load LFS object fixtures
// (LFS storage can be on any of several backends, including remote servers, so we init it with the storage API)
lfsFixtures, err := storage.NewStorage("", storage.LocalStorageConfig{Path: path.Join(filepath.Dir(setting.AppPath), "tests/gitea-lfs-meta")})
assert.NoError(t, err)
assert.NoError(t, storage.Clean(storage.LFS))
assert.NoError(t, lfsFixtures.IterateObjects(func(path string, _ storage.Object) error {
_, err := storage.Copy(storage.LFS, path, lfsFixtures, path)
return err
}))

return deferFn
}

Expand All @@ -198,7 +212,11 @@ func PrepareTestEnv(t testing.TB, skip ...int) func() {
// within a single test this is required
func ResetFixtures(t *testing.T) {
assert.NoError(t, queue.GetManager().FlushAll(context.Background(), -1))

// load database fixtures
assert.NoError(t, unittest.LoadFixtures())

// load git repo fixtures
assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "tests/gitea-repositories-meta"), setting.RepoRootPath))
ownerDirs, err := os.ReadDir(setting.RepoRootPath)
Expand All @@ -220,4 +238,14 @@ func ResetFixtures(t *testing.T) {
_ = os.MkdirAll(filepath.Join(setting.RepoRootPath, ownerDir.Name(), repoDir.Name(), "refs", "tag"), 0o755)
}
}

// load LFS object fixtures
// (LFS storage can be on any of several backends, including remote servers, so we init it with the storage API)
lfsFixtures, err := storage.NewStorage("", storage.LocalStorageConfig{Path: path.Join(filepath.Dir(setting.AppPath), "tests/gitea-lfs-meta")})
assert.NoError(t, err)
assert.NoError(t, storage.Clean(storage.LFS))
assert.NoError(t, lfsFixtures.IterateObjects(func(path string, _ storage.Object) error {
_, err := storage.Copy(storage.LFS, path, lfsFixtures, path)
return err
}))
}

0 comments on commit b6b2b6b

Please sign in to comment.