test(thumb): new changes in filesystem pkg

pull/1710/head
Aaron Liu 1 year ago
parent 408733a974
commit 8e2fc1a8f6

@ -4,6 +4,7 @@ import (
"context"
model "github.com/cloudreve/Cloudreve/v3/models"
"github.com/cloudreve/Cloudreve/v3/pkg/auth"
"github.com/cloudreve/Cloudreve/v3/pkg/filesystem/driver"
"github.com/cloudreve/Cloudreve/v3/pkg/filesystem/fsctx"
"github.com/cloudreve/Cloudreve/v3/pkg/serializer"
"github.com/cloudreve/Cloudreve/v3/pkg/util"
@ -141,17 +142,34 @@ func TestHandler_Thumb(t *testing.T) {
asserts.NoError(err)
file.Close()
f := &model.File{
SourceName: "TestHandler_Thumb",
MetadataSerialized: map[string]string{
model.ThumbStatusMetadataKey: model.ThumbStatusExist,
},
}
// 正常
{
thumb, err := handler.Thumb(ctx, "TestHandler_Thumb")
thumb, err := handler.Thumb(ctx, f)
asserts.NoError(err)
asserts.NotNil(thumb.Content)
}
// 不存在
// file 不存在
{
f.SourceName = "not_exist"
_, err := handler.Thumb(ctx, f)
asserts.Error(err)
asserts.ErrorIs(err, driver.ErrorThumbNotExist)
}
// thumb not exist
{
_, err := handler.Thumb(ctx, "not_exist")
f.MetadataSerialized[model.ThumbStatusMetadataKey] = model.ThumbStatusNotExist
_, err := handler.Thumb(ctx, f)
asserts.Error(err)
asserts.ErrorIs(err, driver.ErrorThumbNotExist)
}
}

@ -246,19 +246,19 @@ func TestDriver_Thumb(t *testing.T) {
}
handler.Client, _ = NewClient(&model.Policy{})
handler.Client.Credential.ExpiresIn = time.Now().Add(time.Duration(100) * time.Hour).Unix()
file := &model.File{PicInfo: "1,1", Model: gorm.Model{ID: 1}}
// 失败
{
ctx := context.WithValue(context.Background(), fsctx.ThumbSizeCtx, [2]uint{10, 20})
ctx = context.WithValue(ctx, fsctx.FileModelCtx, model.File{PicInfo: "1,1", Model: gorm.Model{ID: 1}})
res, err := handler.Thumb(ctx, "123.jpg")
res, err := handler.Thumb(ctx, file)
asserts.Error(err)
asserts.Empty(res.URL)
}
// 上下文错误
{
_, err := handler.Thumb(context.Background(), "123.jpg")
_, err := handler.Thumb(context.Background(), file)
asserts.Error(err)
}
}

@ -3,6 +3,7 @@ package remote
import (
"context"
"errors"
"github.com/cloudreve/Cloudreve/v3/pkg/filesystem/driver"
"github.com/cloudreve/Cloudreve/v3/pkg/mocks/remoteclientmock"
"github.com/cloudreve/Cloudreve/v3/pkg/serializer"
"io"
@ -373,14 +374,33 @@ func TestHandler_Thumb(t *testing.T) {
Type: "remote",
SecretKey: "test",
Server: "http://test.com",
OptionsSerialized: model.PolicyOption{
ThumbExts: []string{"txt"},
},
},
AuthInstance: auth.HMACAuth{},
}
file := &model.File{
Name: "1.txt",
SourceName: "1.txt",
}
ctx := context.Background()
asserts.NoError(cache.Set("setting_preview_timeout", "60", 0))
resp, err := handler.Thumb(ctx, "/1.txt")
asserts.NoError(err)
asserts.True(resp.Redirect)
// no error
{
resp, err := handler.Thumb(ctx, file)
asserts.NoError(err)
asserts.True(resp.Redirect)
}
// ext not support
{
file.Name = "1.jpg"
resp, err := handler.Thumb(ctx, file)
asserts.ErrorIs(err, driver.ErrorThumbNotSupported)
asserts.Nil(resp)
}
}
func TestHandler_Token(t *testing.T) {

@ -58,7 +58,6 @@ func TestFileSystem_AddFile(t *testing.T) {
asserts.NoError(err)
asserts.NoError(mock.ExpectationsWereMet())
asserts.Equal("/Uploads/1_sad.png", f.SourceName)
asserts.NotEmpty(f.PicInfo)
// 前置钩子执行失败
{
@ -312,6 +311,19 @@ func TestFileSystem_deleteGroupedFile(t *testing.T) {
_, ok := cache.Get(UploadSessionCachePrefix + sessionID)
asserts.False(ok)
}
// 包含缩略图
{
files[0].MetadataSerialized = map[string]string{
model.ThumbSidecarMetadataKey: "1",
}
failed := fs.deleteGroupedFile(ctx, fs.GroupFileByPolicy(ctx, files))
asserts.Equal(map[uint][]string{
1: {},
2: {},
3: {},
}, failed)
}
}
func TestFileSystem_GetSource(t *testing.T) {

@ -360,7 +360,7 @@ func TestHookClearFileSize(t *testing.T) {
)
mock.ExpectBegin()
mock.ExpectExec("UPDATE(.+)files(.+)").
WithArgs(0, sqlmock.AnyArg(), 1, 10).
WithArgs("", 0, sqlmock.AnyArg(), 1, 10).
WillReturnResult(sqlmock.NewResult(1, 1))
mock.ExpectExec("UPDATE(.+)users(.+)").
WithArgs(10, sqlmock.AnyArg()).
@ -394,7 +394,7 @@ func TestHookUpdateSourceName(t *testing.T) {
}
ctx := context.WithValue(context.Background(), fsctx.FileModelCtx, originFile)
mock.ExpectBegin()
mock.ExpectExec("UPDATE(.+)").WithArgs("new.txt", sqlmock.AnyArg(), 1).WillReturnResult(sqlmock.NewResult(1, 1))
mock.ExpectExec("UPDATE(.+)").WithArgs("", "new.txt", sqlmock.AnyArg(), 1).WillReturnResult(sqlmock.NewResult(1, 1))
mock.ExpectCommit()
err := HookUpdateSourceName(ctx, fs, nil)
asserts.NoError(mock.ExpectationsWereMet())
@ -429,7 +429,7 @@ func TestGenericAfterUpdate(t *testing.T) {
fs.Handler = handlerMock
mock.ExpectBegin()
mock.ExpectExec("UPDATE(.+)files(.+)").
WithArgs(10, sqlmock.AnyArg(), 1, 0).
WithArgs("", 10, sqlmock.AnyArg(), 1, 0).
WillReturnResult(sqlmock.NewResult(1, 1))
mock.ExpectExec("UPDATE(.+)users(.+)").
WithArgs(10, sqlmock.AnyArg()).
@ -462,7 +462,7 @@ func TestGenericAfterUpdate(t *testing.T) {
mock.ExpectBegin()
mock.ExpectExec("UPDATE(.+)").
WithArgs(10, sqlmock.AnyArg(), 1, 0).
WithArgs("", 10, sqlmock.AnyArg(), 1, 0).
WillReturnError(errors.New("error"))
mock.ExpectRollback()
@ -473,27 +473,6 @@ func TestGenericAfterUpdate(t *testing.T) {
}
}
func TestHookGenerateThumb(t *testing.T) {
a := assert.New(t)
mockHandler := &FileHeaderMock{}
fs := &FileSystem{
User: &model.User{
Model: gorm.Model{ID: 1},
},
Handler: mockHandler,
Policy: &model.Policy{Type: "local"},
}
mockHandler.On("Delete", testMock.Anything, []string{"1.txt._thumb"}).Return([]string{}, nil)
a.NoError(HookGenerateThumb(context.Background(), fs, &fsctx.FileStream{
Model: &model.File{
SourceName: "1.txt",
},
}))
fs.Recycle()
mockHandler.AssertExpectations(t)
}
func TestSlaveAfterUpload(t *testing.T) {
asserts := assert.New(t)
conf.SystemConfig.Mode = "slave"
@ -625,7 +604,7 @@ func TestHookChunkUploaded(t *testing.T) {
}
mock.ExpectBegin()
mock.ExpectExec("UPDATE(.+)files(.+)").WithArgs(20, sqlmock.AnyArg(), 1, 0).WillReturnResult(sqlmock.NewResult(1, 1))
mock.ExpectExec("UPDATE(.+)files(.+)").WithArgs("", 20, sqlmock.AnyArg(), 1, 0).WillReturnResult(sqlmock.NewResult(1, 1))
mock.ExpectExec("UPDATE(.+)users(.+)").
WithArgs(20, sqlmock.AnyArg()).
WillReturnResult(sqlmock.NewResult(1, 1))
@ -646,7 +625,7 @@ func TestHookChunkUploadFailed(t *testing.T) {
}
mock.ExpectBegin()
mock.ExpectExec("UPDATE(.+)files(.+)").WithArgs(10, sqlmock.AnyArg(), 1, 0).WillReturnResult(sqlmock.NewResult(1, 1))
mock.ExpectExec("UPDATE(.+)files(.+)").WithArgs("", 10, sqlmock.AnyArg(), 1, 0).WillReturnResult(sqlmock.NewResult(1, 1))
mock.ExpectExec("UPDATE(.+)users(.+)").
WithArgs(10, sqlmock.AnyArg()).
WillReturnResult(sqlmock.NewResult(1, 1))

@ -28,9 +28,7 @@ func (fs *FileSystem) GetThumb(ctx context.Context, id uint) (*response.ContentR
// 根据 ID 查找文件
err := fs.resetFileIDIfNotExist(ctx, id)
if err != nil {
return &response.ContentResponse{
Redirect: false,
}, ErrObjectNotExist
return nil, ErrObjectNotExist
}
file := fs.FileTarget[0]
@ -44,7 +42,7 @@ func (fs *FileSystem) GetThumb(ctx context.Context, id uint) (*response.ContentR
res, err := fs.Handler.Thumb(ctx, &file)
if errors.Is(err, driver.ErrorThumbNotExist) {
// Regenerate thumb if the thumb is not initialized yet
if generateErr := fs.GenerateThumbnail(ctx, &file); generateErr == nil {
if generateErr := fs.generateThumbnail(ctx, &file); generateErr == nil {
res, err = fs.Handler.Thumb(ctx, &file)
} else {
err = generateErr
@ -69,7 +67,7 @@ func (fs *FileSystem) GetThumb(ctx context.Context, id uint) (*response.ContentR
)
} else {
// if not exist, generate and upload the sidecar thumb.
if err = fs.GenerateThumbnail(ctx, &file); err == nil {
if err = fs.generateThumbnail(ctx, &file); err == nil {
return fs.GetThumb(ctx, id)
}
}
@ -119,8 +117,8 @@ func (pool *Pool) releaseWorker() {
<-pool.worker
}
// GenerateThumbnail generates thumb for given file, upload the thumb file back with given suffix
func (fs *FileSystem) GenerateThumbnail(ctx context.Context, file *model.File) error {
// generateThumbnail generates thumb for given file, upload the thumb file back with given suffix
func (fs *FileSystem) generateThumbnail(ctx context.Context, file *model.File) error {
// 新建上下文
newCtx, cancel := context.WithCancel(context.Background())
defer cancel()
@ -164,13 +162,13 @@ func (fs *FileSystem) GenerateThumbnail(ctx context.Context, file *model.File) e
thumbFile, err := os.Open(thumbRes.Path)
if err != nil {
return fmt.Errorf("failed to open temp thumb %q: %w", thumbFile, err)
return fmt.Errorf("failed to open temp thumb %q: %w", thumbRes.Path, err)
}
defer thumbFile.Close()
fileInfo, err := thumbFile.Stat()
if err != nil {
return fmt.Errorf("failed to stat temp thumb %q: %w", thumbFile, err)
return fmt.Errorf("failed to stat temp thumb %q: %w", thumbRes.Path, err)
}
if err = fs.Handler.Put(newCtx, &fsctx.FileStream{
@ -184,7 +182,7 @@ func (fs *FileSystem) GenerateThumbnail(ctx context.Context, file *model.File) e
}
if model.IsTrueVal(model.GetSettingByName("thumb_gc_after_gen")) {
util.Log().Debug("GenerateThumbnail runtime.GC")
util.Log().Debug("generateThumbnail runtime.GC")
runtime.GC()
}

@ -5,8 +5,11 @@ import (
"errors"
model "github.com/cloudreve/Cloudreve/v3/models"
"github.com/cloudreve/Cloudreve/v3/pkg/cache"
"github.com/cloudreve/Cloudreve/v3/pkg/filesystem/driver"
"github.com/cloudreve/Cloudreve/v3/pkg/filesystem/response"
"github.com/cloudreve/Cloudreve/v3/pkg/mocks/thumbmock"
"github.com/cloudreve/Cloudreve/v3/pkg/request"
"github.com/cloudreve/Cloudreve/v3/pkg/thumb"
testMock "github.com/stretchr/testify/mock"
"testing"
@ -14,30 +17,104 @@ import (
)
func TestFileSystem_GetThumb(t *testing.T) {
asserts := assert.New(t)
a := assert.New(t)
fs := &FileSystem{User: &model.User{}}
// 非图像文件
// file not found
{
fs.SetTargetFile(&[]model.File{{}})
_, err := fs.GetThumb(context.Background(), 1)
asserts.Equal(err, ErrObjectNotExist)
mock.ExpectQuery("SELECT(.+)").WillReturnError(errors.New("error"))
res, err := fs.GetThumb(context.Background(), 1)
a.ErrorIs(err, ErrObjectNotExist)
a.Nil(res)
a.NoError(mock.ExpectationsWereMet())
}
// thumb not exist
{
fs.SetTargetFile(&[]model.File{{
MetadataSerialized: map[string]string{
model.ThumbStatusMetadataKey: model.ThumbStatusNotAvailable,
},
Policy: model.Policy{Type: "mock"},
}})
fs.FileTarget[0].Policy.ID = 1
res, err := fs.GetThumb(context.Background(), 1)
a.ErrorIs(err, ErrObjectNotExist)
a.Nil(res)
}
// thumb not initialized, also failed to generate
{
fs.CleanTargets()
fs.SetTargetFile(&[]model.File{{
Policy: model.Policy{Type: "mock"},
Size: 31457281,
}})
testHandller2 := new(FileHeaderMock)
testHandller2.On("Thumb", testMock.Anything, &fs.FileTarget[0]).Return(&response.ContentResponse{}, driver.ErrorThumbNotExist)
fs.Handler = testHandller2
fs.FileTarget[0].Policy.ID = 1
res, err := fs.GetThumb(context.Background(), 1)
a.Contains(err.Error(), "file too large")
a.Nil(res.Content)
}
// 成功
// thumb not initialized, failed to get source
{
cache.Set("setting_thumb_width", "10", 0)
cache.Set("setting_thumb_height", "10", 0)
cache.Set("setting_preview_timeout", "50", 0)
fs.CleanTargets()
fs.SetTargetFile(&[]model.File{{
Policy: model.Policy{Type: "mock"},
}})
testHandller2 := new(FileHeaderMock)
testHandller2.On("Thumb", testMock.Anything, "").Return(&response.ContentResponse{}, nil)
testHandller2.On("Thumb", testMock.Anything, &fs.FileTarget[0]).Return(&response.ContentResponse{}, driver.ErrorThumbNotExist)
testHandller2.On("Get", testMock.Anything, "").Return(MockRSC{}, errors.New("error"))
fs.Handler = testHandller2
fs.FileTarget[0].Policy.ID = 1
res, err := fs.GetThumb(context.Background(), 1)
a.Contains(err.Error(), "error")
a.Nil(res.Content)
}
// thumb not initialized, no available generators
{
thumb.Generators = []thumb.Generator{}
fs.CleanTargets()
fs.SetTargetFile(&[]model.File{{PicInfo: "1,1", Policy: model.Policy{Type: "mock"}}})
fs.SetTargetFile(&[]model.File{{
Policy: model.Policy{Type: "local"},
}})
testHandller2 := new(FileHeaderMock)
testHandller2.On("Thumb", testMock.Anything, &fs.FileTarget[0]).Return(&response.ContentResponse{}, driver.ErrorThumbNotExist)
testHandller2.On("Get", testMock.Anything, "").Return(MockRSC{}, nil)
fs.Handler = testHandller2
fs.FileTarget[0].Policy.ID = 1
res, err := fs.GetThumb(context.Background(), 1)
a.ErrorIs(err, thumb.ErrNotAvailable)
a.Nil(res)
}
// thumb not initialized, thumb generated but cannot be open
{
mockGenerator := &thumbmock.GeneratorMock{}
thumb.Generators = []thumb.Generator{mockGenerator}
fs.CleanTargets()
fs.SetTargetFile(&[]model.File{{
Policy: model.Policy{Type: "mock"},
}})
cache.Set("setting_thumb_vips_enabled", "1", 0)
testHandller2 := new(FileHeaderMock)
testHandller2.On("Thumb", testMock.Anything, &fs.FileTarget[0]).Return(&response.ContentResponse{}, driver.ErrorThumbNotExist)
testHandller2.On("Get", testMock.Anything, "").Return(MockRSC{}, nil)
mockGenerator.On("Generate", testMock.Anything, testMock.Anything, testMock.Anything, testMock.Anything, testMock.Anything).
Return(&thumb.Result{Path: "not_exit_thumb"}, nil)
fs.Handler = testHandller2
fs.FileTarget[0].Policy.ID = 1
res, err := fs.GetThumb(context.Background(), 1)
asserts.NoError(err)
asserts.EqualValues(50, res.MaxAge)
a.Contains(err.Error(), "failed to open temp thumb")
a.Nil(res.Content)
testHandller2.AssertExpectations(t)
mockGenerator.AssertExpectations(t)
}
}
@ -56,7 +133,7 @@ func TestFileSystem_GenerateThumbnail(t *testing.T) {
// 无法生成缩略图
{
fs.SetTargetFile(&[]model.File{{}})
fs.GenerateThumbnail(context.Background(), &model.File{})
fs.generateThumbnail(context.Background(), &model.File{})
}
// 无法获取文件数据
@ -64,7 +141,7 @@ func TestFileSystem_GenerateThumbnail(t *testing.T) {
testHandller := new(FileHeaderMock)
testHandller.On("Get", testMock.Anything, "").Return(request.NopRSCloser{}, errors.New("error"))
fs.Handler = testHandller
fs.GenerateThumbnail(context.Background(), &model.File{Name: "test.png"})
fs.generateThumbnail(context.Background(), &model.File{Name: "test.png"})
testHandller.AssertExpectations(t)
}
}

@ -55,7 +55,7 @@ func (m FileHeaderMock) Delete(ctx context.Context, files []string) ([]string, e
return args.Get(0).([]string), args.Error(1)
}
func (m FileHeaderMock) Thumb(ctx context.Context, files string) (*response.ContentResponse, error) {
func (m FileHeaderMock) Thumb(ctx context.Context, files *model.File) (*response.ContentResponse, error) {
args := m.Called(ctx, files)
return args.Get(0).(*response.ContentResponse), args.Error(1)
}

@ -0,0 +1,25 @@
package thumbmock
import (
"context"
"github.com/cloudreve/Cloudreve/v3/pkg/thumb"
"github.com/stretchr/testify/mock"
"io"
)
type GeneratorMock struct {
mock.Mock
}
func (g GeneratorMock) Generate(ctx context.Context, file io.Reader, src string, name string, options map[string]string) (*thumb.Result, error) {
res := g.Called(ctx, file, src, name, options)
return res.Get(0).(*thumb.Result), res.Error(1)
}
func (g GeneratorMock) Priority() int {
return 0
}
func (g GeneratorMock) EnableFlag() string {
return "thumb_vips_enabled"
}

@ -1,146 +0,0 @@
package thumb
import (
"fmt"
"image"
"image/jpeg"
"os"
"testing"
"github.com/cloudreve/Cloudreve/v3/pkg/cache"
"github.com/cloudreve/Cloudreve/v3/pkg/util"
"github.com/stretchr/testify/assert"
)
func CreateTestImage() *os.File {
file, err := os.Create("TestNewThumbFromFile.jpeg")
alpha := image.NewAlpha(image.Rect(0, 0, 500, 200))
jpeg.Encode(file, alpha, nil)
if err != nil {
fmt.Println(err)
}
_, _ = file.Seek(0, 0)
return file
}
func TestNewThumbFromFile(t *testing.T) {
asserts := assert.New(t)
file := CreateTestImage()
defer file.Close()
// 无扩展名时
{
thumb, err := NewThumbFromFile(file, "123")
asserts.Error(err)
asserts.Nil(thumb)
}
{
thumb, err := NewThumbFromFile(file, "123.jpg")
asserts.NoError(err)
asserts.NotNil(thumb)
}
{
thumb, err := NewThumbFromFile(file, "123.jpeg")
asserts.Error(err)
asserts.Nil(thumb)
}
{
thumb, err := NewThumbFromFile(file, "123.png")
asserts.Error(err)
asserts.Nil(thumb)
}
{
thumb, err := NewThumbFromFile(file, "123.gif")
asserts.Error(err)
asserts.Nil(thumb)
}
{
thumb, err := NewThumbFromFile(file, "123.3211")
asserts.Error(err)
asserts.Nil(thumb)
}
}
func TestThumb_GetSize(t *testing.T) {
asserts := assert.New(t)
file := CreateTestImage()
defer file.Close()
thumb, err := NewThumbFromFile(file, "123.jpg")
asserts.NoError(err)
w, h := thumb.GetSize()
asserts.Equal(500, w)
asserts.Equal(200, h)
}
func TestThumb_GetThumb(t *testing.T) {
asserts := assert.New(t)
file := CreateTestImage()
defer file.Close()
thumb, err := NewThumbFromFile(file, "123.jpg")
asserts.NoError(err)
asserts.NotPanics(func() {
thumb.GetThumb(10, 10)
})
}
func TestThumb_Thumbnail(t *testing.T) {
asserts := assert.New(t)
{
img := image.NewRGBA(image.Rect(0, 0, 500, 200))
thumb := Thumbnail(100, 100, img)
asserts.Equal(thumb.Bounds(), image.Rect(0, 0, 100, 40))
}
{
img := image.NewRGBA(image.Rect(0, 0, 200, 200))
thumb := Thumbnail(100, 100, img)
asserts.Equal(thumb.Bounds(), image.Rect(0, 0, 100, 100))
}
{
img := image.NewRGBA(image.Rect(0, 0, 500, 500))
thumb := Thumbnail(100, 100, img)
asserts.Equal(thumb.Bounds(), image.Rect(0, 0, 100, 100))
}
{
img := image.NewRGBA(image.Rect(0, 0, 200, 500))
thumb := Thumbnail(100, 100, img)
asserts.Equal(thumb.Bounds(), image.Rect(0, 0, 40, 100))
}
}
func TestThumb_Save(t *testing.T) {
asserts := assert.New(t)
file := CreateTestImage()
defer file.Close()
thumb, err := NewThumbFromFile(file, "123.jpg")
asserts.NoError(err)
err = thumb.Save("/:noteexist/")
asserts.Error(err)
err = thumb.Save("TestThumb_Save.png")
asserts.NoError(err)
asserts.True(util.Exists("TestThumb_Save.png"))
}
func TestThumb_CreateAvatar(t *testing.T) {
asserts := assert.New(t)
file := CreateTestImage()
defer file.Close()
thumb, err := NewThumbFromFile(file, "123.jpg")
asserts.NoError(err)
cache.Set("setting_avatar_path", "tests", 0)
cache.Set("setting_avatar_size_s", "50", 0)
cache.Set("setting_avatar_size_m", "130", 0)
cache.Set("setting_avatar_size_l", "200", 0)
asserts.NoError(thumb.CreateAvatar(1))
asserts.True(util.Exists(util.RelativePath("tests/avatar_1_1.png")))
asserts.True(util.Exists(util.RelativePath("tests/avatar_1_2.png")))
asserts.True(util.Exists(util.RelativePath("tests/avatar_1_0.png")))
}
Loading…
Cancel
Save