diff --git a/models/defaults.go b/models/defaults.go
index ecb8428..16a798b 100644
--- a/models/defaults.go
+++ b/models/defaults.go
@@ -31,7 +31,6 @@ var defaultSettings = []Setting{
 	{Name: "download_timeout", Value: `60`, Type: "timeout"},
 	{Name: "preview_timeout", Value: `60`, Type: "timeout"},
 	{Name: "doc_preview_timeout", Value: `60`, Type: "timeout"},
-	{Name: "upload_credential_timeout", Value: `1800`, Type: "timeout"},
 	{Name: "upload_session_timeout", Value: `86400`, Type: "timeout"},
 	{Name: "slave_api_timeout", Value: `60`, Type: "timeout"},
 	{Name: "slave_node_retry", Value: `3`, Type: "slave"},
diff --git a/pkg/conf/conf.go b/pkg/conf/conf.go
index 4988ef3..35ed8b6 100644
--- a/pkg/conf/conf.go
+++ b/pkg/conf/conf.go
@@ -65,6 +65,7 @@ type cors struct {
 var cfg *ini.File
 
 const defaultConf = `[System]
+Debug = false
 Mode = master
 Listen = :5212
 SessionSecret = {SessionSecret}
diff --git a/pkg/filesystem/chunk/chunk_test.go b/pkg/filesystem/chunk/chunk_test.go
index c6af9d9..4bdcd06 100644
--- a/pkg/filesystem/chunk/chunk_test.go
+++ b/pkg/filesystem/chunk/chunk_test.go
@@ -245,6 +245,6 @@ func TestChunkGroup_Process(t *testing.T) {
 			return errors.New("error")
 		}))
 		a.False(c.Next())
-		a.Equal(1, count)
+		a.Equal(4, count)
 	}
 }
diff --git a/pkg/filesystem/driver/local/handler_test.go b/pkg/filesystem/driver/local/handler_test.go
index 9ce5fe7..9167e82 100644
--- a/pkg/filesystem/driver/local/handler_test.go
+++ b/pkg/filesystem/driver/local/handler_test.go
@@ -81,12 +81,12 @@ func TestHandler_Delete(t *testing.T) {
 	asserts := assert.New(t)
 	handler := Driver{}
 	ctx := context.Background()
-	filePath := util.RelativePath("test.file")
+	filePath := util.RelativePath("TestHandler_Delete.file")
 
 	file, err := os.Create(filePath)
 	asserts.NoError(err)
 	_ = file.Close()
-	list, err := handler.Delete(ctx, []string{"test.file"})
+	list, err := handler.Delete(ctx, []string{"TestHandler_Delete.file"})
 	asserts.Equal([]string{}, list)
 	asserts.NoError(err)
 
@@ -94,7 +94,7 @@ func TestHandler_Delete(t *testing.T) {
 	_ = file.Close()
 	file, _ = os.OpenFile(filePath, os.O_RDWR, os.FileMode(0))
 	asserts.NoError(err)
-	list, err = handler.Delete(ctx, []string{"test.file", "test.notexist"})
+	list, err = handler.Delete(ctx, []string{"TestHandler_Delete.file", "test.notexist"})
 	file.Close()
 	asserts.Equal([]string{}, list)
 	asserts.NoError(err)
@@ -105,7 +105,7 @@ func TestHandler_Delete(t *testing.T) {
 
 	file, err = os.Create(filePath)
 	asserts.NoError(err)
-	list, err = handler.Delete(ctx, []string{"test.file"})
+	list, err = handler.Delete(ctx, []string{"TestHandler_Delete.file"})
 	_ = file.Close()
 	asserts.Equal([]string{}, list)
 	asserts.NoError(err)
diff --git a/pkg/filesystem/driver/oss/handler.go b/pkg/filesystem/driver/oss/handler.go
index c7eadc2..b0b55d2 100644
--- a/pkg/filesystem/driver/oss/handler.go
+++ b/pkg/filesystem/driver/oss/handler.go
@@ -229,7 +229,7 @@ func (handler *Driver) Put(ctx context.Context, file fsctx.FileHeader) error {
 	fileInfo := file.Info()
 
 	// 凭证有效期
-	credentialTTL := model.GetIntSetting("upload_credential_timeout", 3600)
+	credentialTTL := model.GetIntSetting("upload_session_timeout", 3600)
 
 	// 是否允许覆盖
 	overwrite := fileInfo.Mode&fsctx.Overwrite == fsctx.Overwrite
diff --git a/pkg/filesystem/driver/qiniu/handler.go b/pkg/filesystem/driver/qiniu/handler.go
index a47b8da..22a97d0 100644
--- a/pkg/filesystem/driver/qiniu/handler.go
+++ b/pkg/filesystem/driver/qiniu/handler.go
@@ -156,7 +156,7 @@ func (handler *Driver) Put(ctx context.Context, file fsctx.FileHeader) error {
 	defer file.Close()
 
 	// 凭证有效期
-	credentialTTL := model.GetIntSetting("upload_credential_timeout", 3600)
+	credentialTTL := model.GetIntSetting("upload_session_timeout", 3600)
 
 	// 生成上传策略
 	fileInfo := file.Info()
diff --git a/pkg/filesystem/image_test.go b/pkg/filesystem/image_test.go
index 42c7f45..cc33b19 100644
--- a/pkg/filesystem/image_test.go
+++ b/pkg/filesystem/image_test.go
@@ -1,38 +1,45 @@
 package filesystem
 
 import (
+	"context"
+	"errors"
+	model "github.com/cloudreve/Cloudreve/v3/models"
+	"github.com/cloudreve/Cloudreve/v3/pkg/cache"
+	"github.com/cloudreve/Cloudreve/v3/pkg/filesystem/response"
+	"github.com/cloudreve/Cloudreve/v3/pkg/request"
+	testMock "github.com/stretchr/testify/mock"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
 )
 
-//func TestFileSystem_GetThumb(t *testing.T) {
-//	asserts := assert.New(t)
-//	fs := &FileSystem{User: &model.User{}}
-//
-//	// 非图像文件
-//	{
-//		fs.SetTargetFile(&[]model.File{{}})
-//		_, err := fs.GetThumb(context.Background(), 1)
-//		asserts.Equal(err, ErrObjectNotExist)
-//	}
-//
-//	// 成功
-//	{
-//		cache.Set("setting_thumb_width", "10", 0)
-//		cache.Set("setting_thumb_height", "10", 0)
-//		cache.Set("setting_preview_timeout", "50", 0)
-//		testHandller2 := new(FileHeaderMock)
-//		testHandller2.On("Thumb", testMock.Anything, "").Return(&response.ContentResponse{}, nil)
-//		fs.CleanTargets()
-//		fs.SetTargetFile(&[]model.File{{PicInfo: "1,1", Policy: model.Policy{Type: "mock"}}})
-//		fs.FileTarget[0].Policy.ID = 1
-//		fs.Handler = testHandller2
-//		res, err := fs.GetThumb(context.Background(), 1)
-//		asserts.NoError(err)
-//		asserts.EqualValues(50, res.MaxAge)
-//	}
-//}
+func TestFileSystem_GetThumb(t *testing.T) {
+	asserts := assert.New(t)
+	fs := &FileSystem{User: &model.User{}}
+
+	// 非图像文件
+	{
+		fs.SetTargetFile(&[]model.File{{}})
+		_, err := fs.GetThumb(context.Background(), 1)
+		asserts.Equal(err, ErrObjectNotExist)
+	}
+
+	// 成功
+	{
+		cache.Set("setting_thumb_width", "10", 0)
+		cache.Set("setting_thumb_height", "10", 0)
+		cache.Set("setting_preview_timeout", "50", 0)
+		testHandller2 := new(FileHeaderMock)
+		testHandller2.On("Thumb", testMock.Anything, "").Return(&response.ContentResponse{}, nil)
+		fs.CleanTargets()
+		fs.SetTargetFile(&[]model.File{{PicInfo: "1,1", Policy: model.Policy{Type: "mock"}}})
+		fs.FileTarget[0].Policy.ID = 1
+		fs.Handler = testHandller2
+		res, err := fs.GetThumb(context.Background(), 1)
+		asserts.NoError(err)
+		asserts.EqualValues(50, res.MaxAge)
+	}
+}
 
 func TestFileSystem_ThumbWorker(t *testing.T) {
 	asserts := assert.New(t)
@@ -42,3 +49,22 @@ func TestFileSystem_ThumbWorker(t *testing.T) {
 		getThumbWorker().releaseWorker()
 	})
 }
+
+func TestFileSystem_GenerateThumbnail(t *testing.T) {
+	fs := &FileSystem{User: &model.User{}}
+
+	// 无法生成缩略图
+	{
+		fs.SetTargetFile(&[]model.File{{}})
+		fs.GenerateThumbnail(context.Background(), &model.File{})
+	}
+
+	// 无法获取文件数据
+	{
+		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"})
+		testHandller.AssertExpectations(t)
+	}
+}
diff --git a/pkg/filesystem/manage_test.go b/pkg/filesystem/manage_test.go
index 7357371..da91691 100644
--- a/pkg/filesystem/manage_test.go
+++ b/pkg/filesystem/manage_test.go
@@ -3,6 +3,8 @@ package filesystem
 import (
 	"context"
 	"errors"
+	"github.com/cloudreve/Cloudreve/v3/pkg/filesystem/response"
+	testMock "github.com/stretchr/testify/mock"
 	"os"
 	"testing"
 
@@ -17,51 +19,51 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
-//func TestFileSystem_ListPhysical(t *testing.T) {
-//	asserts := assert.New(t)
-//	fs := &FileSystem{
-//		User: &model.User{
-//			Model: gorm.Model{
-//				ID: 1,
-//			},
-//		},
-//		Policy: &model.Policy{Type: "mock"},
-//	}
-//	ctx := context.Background()
-//
-//	// 未知存储策略
-//	{
-//		fs.Policy.Type = "unknown"
-//		res, err := fs.ListPhysical(ctx, "/")
-//		asserts.Equal(ErrUnknownPolicyType, err)
-//		asserts.Empty(res)
-//		fs.Policy.Type = "mock"
-//	}
-//
-//	// 无法列取目录
-//	{
-//		testHandler := new(FileHeaderMock)
-//		testHandler.On("List", testMock.Anything, "/", testMock.Anything).Return([]response.Object{}, errors.New("error"))
-//		fs.Handler = testHandler
-//		res, err := fs.ListPhysical(ctx, "/")
-//		asserts.EqualError(err, "error")
-//		asserts.Empty(res)
-//	}
-//
-//	// 成功
-//	{
-//		testHandler := new(FileHeaderMock)
-//		testHandler.On("List", testMock.Anything, "/", testMock.Anything).Return(
-//			[]response.Object{{IsDir: true, Name: "1"}, {IsDir: false, Name: "2"}},
-//			nil,
-//		)
-//		fs.Handler = testHandler
-//		res, err := fs.ListPhysical(ctx, "/")
-//		asserts.NoError(err)
-//		asserts.Len(res, 1)
-//		asserts.Equal("1", res[0].Name)
-//	}
-//}
+func TestFileSystem_ListPhysical(t *testing.T) {
+	asserts := assert.New(t)
+	fs := &FileSystem{
+		User: &model.User{
+			Model: gorm.Model{
+				ID: 1,
+			},
+		},
+		Policy: &model.Policy{Type: "mock"},
+	}
+	ctx := context.Background()
+
+	// 未知存储策略
+	{
+		fs.Policy.Type = "unknown"
+		res, err := fs.ListPhysical(ctx, "/")
+		asserts.Equal(ErrUnknownPolicyType, err)
+		asserts.Empty(res)
+		fs.Policy.Type = "mock"
+	}
+
+	// 无法列取目录
+	{
+		testHandler := new(FileHeaderMock)
+		testHandler.On("List", testMock.Anything, "/", testMock.Anything).Return([]response.Object{}, errors.New("error"))
+		fs.Handler = testHandler
+		res, err := fs.ListPhysical(ctx, "/")
+		asserts.EqualError(err, "error")
+		asserts.Empty(res)
+	}
+
+	// 成功
+	{
+		testHandler := new(FileHeaderMock)
+		testHandler.On("List", testMock.Anything, "/", testMock.Anything).Return(
+			[]response.Object{{IsDir: true, Name: "1"}, {IsDir: false, Name: "2"}},
+			nil,
+		)
+		fs.Handler = testHandler
+		res, err := fs.ListPhysical(ctx, "/")
+		asserts.NoError(err)
+		asserts.Len(res, 1)
+		asserts.Equal("1", res[0].Name)
+	}
+}
 
 func TestFileSystem_List(t *testing.T) {
 	asserts := assert.New(t)
@@ -294,12 +296,12 @@ func TestFileSystem_ListDeleteDirs(t *testing.T) {
 	{
 		mock.ExpectQuery("SELECT(.+)").
 			WillReturnRows(
-				sqlmock.NewRows([]string{"id"}).
-					AddRow(1).
-					AddRow(2).
-					AddRow(3),
+				sqlmock.NewRows([]string{"id", "parent_id"}).
+					AddRow(1, 0).
+					AddRow(2, 0).
+					AddRow(3, 0),
 			)
-		mock.ExpectQuery("SELECT(.+)").
+		mock.ExpectQuery("SELECT(.+)files(.+)").
 			WithArgs(1, 2, 3).
 			WillReturnRows(
 				sqlmock.NewRows([]string{"id", "name"}).
@@ -314,21 +316,47 @@ func TestFileSystem_ListDeleteDirs(t *testing.T) {
 		asserts.NoError(mock.ExpectationsWereMet())
 	}
 
+	// 成功,忽略根目录
+	{
+		mock.ExpectQuery("SELECT(.+)").
+			WillReturnRows(
+				sqlmock.NewRows([]string{"id", "parent_id"}).
+					AddRow(1, 0).
+					AddRow(2, nil).
+					AddRow(3, 0),
+			)
+		mock.ExpectQuery("SELECT(.+)files(.+)").
+			WithArgs(1, 3).
+			WillReturnRows(
+				sqlmock.NewRows([]string{"id", "name"}).
+					AddRow(4, "1.txt").
+					AddRow(5, "2.txt").
+					AddRow(6, "3.txt"),
+			)
+		fs.CleanTargets()
+		err := fs.ListDeleteDirs(context.Background(), []uint{1})
+		asserts.NoError(err)
+		asserts.Len(fs.FileTarget, 3)
+		asserts.Len(fs.DirTarget, 2)
+		asserts.NoError(mock.ExpectationsWereMet())
+	}
+
 	// 检索文件发生错误
 	{
 		mock.ExpectQuery("SELECT(.+)").
 			WillReturnRows(
-				sqlmock.NewRows([]string{"id"}).
-					AddRow(1).
-					AddRow(2).
-					AddRow(3),
+				sqlmock.NewRows([]string{"id", "parent_id"}).
+					AddRow(1, 0).
+					AddRow(2, 0).
+					AddRow(3, 0),
 			)
 		mock.ExpectQuery("SELECT(.+)").
 			WithArgs(1, 2, 3).
 			WillReturnError(errors.New("error"))
+		fs.CleanTargets()
 		err := fs.ListDeleteDirs(context.Background(), []uint{1})
 		asserts.Error(err)
-		asserts.Len(fs.DirTarget, 6)
+		asserts.Len(fs.DirTarget, 3)
 		asserts.NoError(mock.ExpectationsWereMet())
 	}
 	// 检索目录发生错误
@@ -347,7 +375,7 @@ func TestFileSystem_Delete(t *testing.T) {
 	cache.Set("pack_size_1", uint64(0), 0)
 	fs := &FileSystem{User: &model.User{
 		Model: gorm.Model{
-			ID: 1,
+			ID: 0,
 		},
 		Storage: 3,
 		Group:   model.Group{MaxStorage: 3},
@@ -359,10 +387,10 @@ func TestFileSystem_Delete(t *testing.T) {
 		fs.CleanTargets()
 		mock.ExpectQuery("SELECT(.+)").
 			WillReturnRows(
-				sqlmock.NewRows([]string{"id"}).
-					AddRow(1).
-					AddRow(2).
-					AddRow(3),
+				sqlmock.NewRows([]string{"id", "parent_id"}).
+					AddRow(1, 0).
+					AddRow(2, 0).
+					AddRow(3, 0),
 			)
 		mock.ExpectQuery("SELECT(.+)").
 			WithArgs(1, 2, 3).
@@ -378,18 +406,16 @@ func TestFileSystem_Delete(t *testing.T) {
 		// 删除文件记录
 		mock.ExpectBegin()
 		mock.ExpectExec("DELETE(.+)").
-			WillReturnResult(sqlmock.NewResult(0, 3))
+			WillReturnResult(sqlmock.NewResult(0, 1))
+		mock.ExpectExec("DELETE(.+)").
+			WillReturnResult(sqlmock.NewResult(0, 1))
+		mock.ExpectExec("UPDATE(.+)users(.+)storage(.+)").WillReturnResult(sqlmock.NewResult(1, 1))
 		mock.ExpectCommit()
 		// 删除对应分享
 		mock.ExpectBegin()
 		mock.ExpectExec("UPDATE(.+)shares").
 			WillReturnResult(sqlmock.NewResult(0, 3))
 		mock.ExpectCommit()
-		// 归还容量
-		mock.ExpectBegin()
-		mock.ExpectExec("UPDATE(.+)").
-			WillReturnResult(sqlmock.NewResult(0, 3))
-		mock.ExpectCommit()
 		// 删除目录
 		mock.ExpectBegin()
 		mock.ExpectExec("DELETE(.+)").
@@ -405,7 +431,6 @@ func TestFileSystem_Delete(t *testing.T) {
 		fs.DirTarget = []model.Folder{}
 		err := fs.Delete(ctx, []uint{1}, []uint{1}, true)
 		asserts.NoError(err)
-		asserts.Equal(uint64(0), fs.User.Storage)
 	}
 	//全部成功
 	{
@@ -417,10 +442,10 @@ func TestFileSystem_Delete(t *testing.T) {
 		asserts.NoError(err)
 		mock.ExpectQuery("SELECT(.+)").
 			WillReturnRows(
-				sqlmock.NewRows([]string{"id"}).
-					AddRow(1).
-					AddRow(2).
-					AddRow(3),
+				sqlmock.NewRows([]string{"id", "parent_id"}).
+					AddRow(1, 0).
+					AddRow(2, 0).
+					AddRow(3, 0),
 			)
 		mock.ExpectQuery("SELECT(.+)").
 			WithArgs(1, 2, 3).
@@ -436,18 +461,16 @@ func TestFileSystem_Delete(t *testing.T) {
 		// 删除文件记录
 		mock.ExpectBegin()
 		mock.ExpectExec("DELETE(.+)").
-			WillReturnResult(sqlmock.NewResult(0, 3))
+			WillReturnResult(sqlmock.NewResult(0, 1))
+		mock.ExpectExec("DELETE(.+)").
+			WillReturnResult(sqlmock.NewResult(0, 1))
+		mock.ExpectExec("UPDATE(.+)users(.+)storage(.+)").WillReturnResult(sqlmock.NewResult(1, 1))
 		mock.ExpectCommit()
 		// 删除对应分享
 		mock.ExpectBegin()
 		mock.ExpectExec("UPDATE(.+)shares").
 			WillReturnResult(sqlmock.NewResult(0, 3))
 		mock.ExpectCommit()
-		// 归还容量
-		mock.ExpectBegin()
-		mock.ExpectExec("UPDATE(.+)").
-			WillReturnResult(sqlmock.NewResult(0, 3))
-		mock.ExpectCommit()
 		// 删除目录
 		mock.ExpectBegin()
 		mock.ExpectExec("DELETE(.+)").
@@ -463,7 +486,6 @@ func TestFileSystem_Delete(t *testing.T) {
 		fs.DirTarget = []model.Folder{}
 		err = fs.Delete(ctx, []uint{1}, []uint{1}, false)
 		asserts.NoError(err)
-		asserts.Equal(uint64(0), fs.User.Storage)
 	}
 
 }
@@ -571,7 +593,9 @@ func TestFileSystem_Rename(t *testing.T) {
 		Model: gorm.Model{
 			ID: 1,
 		},
-	}}
+	},
+		Policy: &model.Policy{},
+	}
 	ctx := context.Background()
 
 	// 重命名文件 成功
@@ -681,7 +705,7 @@ func TestFileSystem_Rename(t *testing.T) {
 
 	// 新名字是文件,扩展名不合法
 	{
-		fs.User.Policy.OptionsSerialized.FileType = []string{"txt"}
+		fs.Policy.OptionsSerialized.FileType = []string{"txt"}
 		err := fs.Rename(ctx, []uint{}, []uint{10}, "1.jpg")
 		asserts.Error(err)
 		asserts.Equal(ErrIllegalObjectName, err)
@@ -689,7 +713,7 @@ func TestFileSystem_Rename(t *testing.T) {
 
 	// 新名字是目录,不应该检测扩展名
 	{
-		fs.User.Policy.OptionsSerialized.FileType = []string{"txt"}
+		fs.Policy.OptionsSerialized.FileType = []string{"txt"}
 		mock.ExpectQuery("SELECT(.+)folders(.+)").
 			WithArgs(10, 1).
 			WillReturnRows(sqlmock.NewRows([]string{"id", "name"}))
diff --git a/pkg/filesystem/upload_test.go b/pkg/filesystem/upload_test.go
index 1f1b963..30f24cc 100644
--- a/pkg/filesystem/upload_test.go
+++ b/pkg/filesystem/upload_test.go
@@ -2,11 +2,23 @@ package filesystem
 
 import (
 	"context"
+	"errors"
+	"github.com/DATA-DOG/go-sqlmock"
+	model "github.com/cloudreve/Cloudreve/v3/models"
+	"github.com/cloudreve/Cloudreve/v3/pkg/cache"
 	"github.com/cloudreve/Cloudreve/v3/pkg/filesystem/fsctx"
 	"github.com/cloudreve/Cloudreve/v3/pkg/filesystem/response"
 	"github.com/cloudreve/Cloudreve/v3/pkg/serializer"
+	"github.com/gin-gonic/gin"
+	"github.com/jinzhu/gorm"
+	"github.com/stretchr/testify/assert"
 	testMock "github.com/stretchr/testify/mock"
+	"io/ioutil"
+	"net/http"
+	"net/http/httptest"
 	"net/url"
+	"strings"
+	"testing"
 )
 
 type FileHeaderMock struct {
@@ -53,177 +65,200 @@ func (m FileHeaderMock) Source(ctx context.Context, path string, url url.URL, ex
 	return args.Get(0).(string), args.Error(1)
 }
 
-//func TestFileSystem_Upload(t *testing.T) {
-//	asserts := assert.New(t)
-//
-//	// 正常
-//	testHandler := new(FileHeaderMock)
-//	testHandler.On("Put", testMock.Anything, testMock.Anything, testMock.Anything).Return(nil)
-//	fs := &FileSystem{
-//		Handler: testHandler,
-//		User: &model.User{
-//			Model: gorm.Model{
-//				ID: 1,
-//			},
-//			Policy: model.Policy{
-//				AutoRename:  false,
-//				DirNameRule: "{path}",
-//			},
-//		},
-//	}
-//	ctx, cancel := context.WithCancel(context.Background())
-//	c, _ := gin.CreateTestContext(httptest.NewRecorder())
-//	c.Request, _ = http.NewRequest("POST", "/", nil)
-//	ctx = context.WithValue(ctx, fsctx.GinCtx, c)
-//	cancel()
-//	file := fsctx.FileStream{
-//		Size:        5,
-//		VirtualPath: "/",
-//		Name:        "1.txt",
-//	}
-//	err := fs.Upload(ctx, file)
-//	asserts.NoError(err)
-//
-//	// 正常,上下文已指定源文件
-//	testHandler = new(FileHeaderMock)
-//	testHandler.On("Put", testMock.Anything, testMock.Anything, "123/123.txt").Return(nil)
-//	fs = &FileSystem{
-//		Handler: testHandler,
-//		User: &model.User{
-//			Model: gorm.Model{
-//				ID: 1,
-//			},
-//			Policy: model.Policy{
-//				AutoRename:  false,
-//				DirNameRule: "{path}",
-//			},
-//		},
-//	}
-//	ctx, cancel = context.WithCancel(context.Background())
-//	c, _ = gin.CreateTestContext(httptest.NewRecorder())
-//	c.Request, _ = http.NewRequest("POST", "/", nil)
-//	ctx = context.WithValue(ctx, fsctx.GinCtx, c)
-//	ctx = context.WithValue(ctx, fsctx.FileModelCtx, model.File{SourceName: "123/123.txt"})
-//	cancel()
-//	file = fsctx.FileStream{
-//		Size:        5,
-//		VirtualPath: "/",
-//		Name:        "1.txt",
-//		File:        ioutil.NopCloser(strings.NewReader("")),
-//	}
-//	err = fs.Upload(ctx, file)
-//	asserts.NoError(err)
-//
-//	// BeforeUpload 返回错误
-//	fs.Use("BeforeUpload", func(ctx context.Context, fs *FileSystem) error {
-//		return errors.New("error")
-//	})
-//	err = fs.Upload(ctx, file)
-//	asserts.Error(err)
-//	fs.Hooks["BeforeUpload"] = nil
-//	testHandler.AssertExpectations(t)
-//
-//	// 上传文件失败
-//	testHandler2 := new(FileHeaderMock)
-//	testHandler2.On("Put", testMock.Anything, testMock.Anything, testMock.Anything).Return(errors.New("error"))
-//	fs.Handler = testHandler2
-//	err = fs.Upload(ctx, file)
-//	asserts.Error(err)
-//	testHandler2.AssertExpectations(t)
-//
-//	// AfterUpload失败
-//	testHandler3 := new(FileHeaderMock)
-//	testHandler3.On("Put", testMock.Anything, testMock.Anything, testMock.Anything).Return(nil)
-//	fs.Handler = testHandler3
-//	fs.Use("AfterUpload", func(ctx context.Context, fs *FileSystem) error {
-//		return errors.New("error")
-//	})
-//	fs.Use("AfterValidateFailed", func(ctx context.Context, fs *FileSystem) error {
-//		return errors.New("error")
-//	})
-//	err = fs.Upload(ctx, file)
-//	asserts.Error(err)
-//	testHandler2.AssertExpectations(t)
-//
-//}
-//
-//func TestFileSystem_GenerateSavePath_Anonymous(t *testing.T) {
-//	asserts := assert.New(t)
-//	fs := FileSystem{User: &model.User{}}
-//	ctx := context.WithValue(
-//		context.Background(),
-//		fsctx.UploadPolicyCtx,
-//		serializer.UploadPolicy{
-//			SavePath:   "{randomkey16}",
-//			AutoRename: false,
-//		},
-//	)
-//
-//	savePath := fs.GenerateSavePath(ctx, fsctx.FileStream{
-//		Name: "test.test",
-//	})
-//	asserts.Len(savePath, 26)
-//	asserts.Contains(savePath, "test.test")
-//}
-//
-//func TestFileSystem_GetUploadToken(t *testing.T) {
-//	asserts := assert.New(t)
-//	fs := FileSystem{User: &model.User{Model: gorm.Model{ID: 1}}}
-//	ctx := context.Background()
-//
-//	// 成功
-//	{
-//		cache.SetSettings(map[string]string{
-//			"upload_credential_timeout": "10",
-//			"upload_session_timeout":    "10",
-//		}, "setting_")
-//		testHandler := new(FileHeaderMock)
-//		testHandler.On("Token", testMock.Anything, int64(10), testMock.Anything).Return(serializer.UploadCredential{Token: "test"}, nil)
-//		fs.Handler = testHandler
-//		res, err := fs.CreateUploadSession(ctx, "/", 10, "123")
-//		testHandler.AssertExpectations(t)
-//		asserts.NoError(err)
-//		asserts.Equal("test", res.Token)
-//	}
-//
-//	// 无法获取上传凭证
-//	{
-//		cache.SetSettings(map[string]string{
-//			"upload_credential_timeout": "10",
-//			"upload_session_timeout":    "10",
-//		}, "setting_")
-//		testHandler := new(FileHeaderMock)
-//		testHandler.On("Token", testMock.Anything, int64(10), testMock.Anything).Return(serializer.UploadCredential{}, errors.New("error"))
-//		fs.Handler = testHandler
-//		_, err := fs.CreateUploadSession(ctx, "/", 10, "123")
-//		testHandler.AssertExpectations(t)
-//		asserts.Error(err)
-//	}
-//}
-//
-//func TestFileSystem_UploadFromStream(t *testing.T) {
-//	asserts := assert.New(t)
-//	fs := FileSystem{User: &model.User{Model: gorm.Model{ID: 1}}}
-//	ctx := context.Background()
-//
-//	err := fs.UploadFromStream(ctx, ioutil.NopCloser(strings.NewReader("123")), "/1.txt", 1)
-//	asserts.Error(err)
-//}
-//
-//func TestFileSystem_UploadFromPath(t *testing.T) {
-//	asserts := assert.New(t)
-//	fs := FileSystem{User: &model.User{Policy: model.Policy{Type: "mock"}, Model: gorm.Model{ID: 1}}}
-//	ctx := context.Background()
-//
-//	// 文件不存在
-//	{
-//		err := fs.UploadFromPath(ctx, "test/not_exist", "/", true)
-//		asserts.Error(err)
-//	}
-//
-//	// 文存在,上传失败
-//	{
-//		err := fs.UploadFromPath(ctx, "tests/test.zip", "/", true)
-//		asserts.Error(err)
-//	}
-//}
+func TestFileSystem_Upload(t *testing.T) {
+	asserts := assert.New(t)
+
+	// 正常
+	testHandler := new(FileHeaderMock)
+	testHandler.On("Put", testMock.Anything, testMock.Anything, testMock.Anything).Return(nil)
+	fs := &FileSystem{
+		Handler: testHandler,
+		User: &model.User{
+			Model: gorm.Model{
+				ID: 1,
+			},
+		},
+		Policy: &model.Policy{
+			AutoRename:  false,
+			DirNameRule: "{path}",
+		},
+	}
+	ctx, cancel := context.WithCancel(context.Background())
+	c, _ := gin.CreateTestContext(httptest.NewRecorder())
+	c.Request, _ = http.NewRequest("POST", "/", nil)
+	ctx = context.WithValue(ctx, fsctx.GinCtx, c)
+	cancel()
+	file := &fsctx.FileStream{
+		Size:        5,
+		VirtualPath: "/",
+		Name:        "1.txt",
+	}
+	err := fs.Upload(ctx, file)
+	asserts.NoError(err)
+
+	// 正常,上下文已指定源文件
+	testHandler = new(FileHeaderMock)
+	testHandler.On("Put", testMock.Anything, testMock.Anything).Return(nil)
+	fs = &FileSystem{
+		Handler: testHandler,
+		User: &model.User{
+			Model: gorm.Model{
+				ID: 1,
+			},
+		},
+		Policy: &model.Policy{
+			AutoRename:  false,
+			DirNameRule: "{path}",
+		},
+	}
+	ctx, cancel = context.WithCancel(context.Background())
+	c, _ = gin.CreateTestContext(httptest.NewRecorder())
+	c.Request, _ = http.NewRequest("POST", "/", nil)
+	ctx = context.WithValue(ctx, fsctx.GinCtx, c)
+	ctx = context.WithValue(ctx, fsctx.FileModelCtx, model.File{SourceName: "123/123.txt"})
+	cancel()
+	file = &fsctx.FileStream{
+		Size:        5,
+		VirtualPath: "/",
+		Name:        "1.txt",
+		File:        ioutil.NopCloser(strings.NewReader("")),
+	}
+	err = fs.Upload(ctx, file)
+	asserts.NoError(err)
+
+	// BeforeUpload 返回错误
+	fs.Use("BeforeUpload", func(ctx context.Context, fs *FileSystem, file fsctx.FileHeader) error {
+		return errors.New("error")
+	})
+	err = fs.Upload(ctx, file)
+	asserts.Error(err)
+	fs.Hooks["BeforeUpload"] = nil
+	testHandler.AssertExpectations(t)
+
+	// 上传文件失败
+	testHandler2 := new(FileHeaderMock)
+	testHandler2.On("Put", testMock.Anything, testMock.Anything).Return(errors.New("error"))
+	fs.Handler = testHandler2
+	err = fs.Upload(ctx, file)
+	asserts.Error(err)
+	testHandler2.AssertExpectations(t)
+
+	// AfterUpload失败
+	testHandler3 := new(FileHeaderMock)
+	testHandler3.On("Put", testMock.Anything, testMock.Anything).Return(nil)
+	fs.Handler = testHandler3
+	fs.Use("AfterUpload", func(ctx context.Context, fs *FileSystem, file fsctx.FileHeader) error {
+		return errors.New("error")
+	})
+	fs.Use("AfterValidateFailed", func(ctx context.Context, fs *FileSystem, file fsctx.FileHeader) error {
+		return errors.New("error")
+	})
+	err = fs.Upload(ctx, file)
+	asserts.Error(err)
+	testHandler2.AssertExpectations(t)
+
+}
+
+func TestFileSystem_GetUploadToken(t *testing.T) {
+	asserts := assert.New(t)
+	fs := FileSystem{
+		User:   &model.User{Model: gorm.Model{ID: 1}},
+		Policy: &model.Policy{},
+	}
+	ctx := context.Background()
+
+	// 成功
+	{
+		cache.SetSettings(map[string]string{
+			"upload_session_timeout": "10",
+		}, "setting_")
+		testHandler := new(FileHeaderMock)
+		testHandler.On("Token", testMock.Anything, int64(10), testMock.Anything, testMock.Anything).Return(&serializer.UploadCredential{Credential: "test"}, nil)
+		fs.Handler = testHandler
+		mock.ExpectQuery("SELECT(.+)").
+			WithArgs(1).
+			WillReturnRows(sqlmock.NewRows([]string{"id", "owner_id"}).AddRow(1, 1))
+		mock.ExpectQuery("SELECT(.+)files(.+)").WillReturnError(errors.New("not found"))
+		mock.ExpectBegin()
+		mock.ExpectExec("INSERT(.+)files(.+)").WillReturnResult(sqlmock.NewResult(1, 1))
+		mock.ExpectExec("UPDATE(.+)storage(.+)").WillReturnResult(sqlmock.NewResult(1, 1))
+		mock.ExpectCommit()
+		res, err := fs.CreateUploadSession(ctx, &fsctx.FileStream{
+			Size:        0,
+			Name:        "file",
+			VirtualPath: "/",
+		})
+		asserts.NoError(mock.ExpectationsWereMet())
+		testHandler.AssertExpectations(t)
+		asserts.NoError(err)
+		asserts.Equal("test", res.Credential)
+	}
+
+	// 无法获取上传凭证
+	{
+		cache.SetSettings(map[string]string{
+			"upload_credential_timeout": "10",
+			"upload_session_timeout":    "10",
+		}, "setting_")
+		testHandler := new(FileHeaderMock)
+		testHandler.On("Token", testMock.Anything, int64(10), testMock.Anything, testMock.Anything).Return(&serializer.UploadCredential{}, errors.New("error"))
+		fs.Handler = testHandler
+		mock.ExpectQuery("SELECT(.+)").
+			WithArgs(1).
+			WillReturnRows(sqlmock.NewRows([]string{"id", "owner_id"}).AddRow(1, 1))
+		mock.ExpectQuery("SELECT(.+)files(.+)").WillReturnError(errors.New("not found"))
+		mock.ExpectBegin()
+		mock.ExpectExec("INSERT(.+)files(.+)").WillReturnResult(sqlmock.NewResult(1, 1))
+		mock.ExpectExec("UPDATE(.+)storage(.+)").WillReturnResult(sqlmock.NewResult(1, 1))
+		mock.ExpectCommit()
+		_, err := fs.CreateUploadSession(ctx, &fsctx.FileStream{
+			Size:        0,
+			Name:        "file",
+			VirtualPath: "/",
+		})
+		asserts.NoError(mock.ExpectationsWereMet())
+		testHandler.AssertExpectations(t)
+		asserts.Error(err)
+	}
+}
+
+func TestFileSystem_UploadFromStream(t *testing.T) {
+	asserts := assert.New(t)
+	fs := FileSystem{
+		User: &model.User{
+			Model:  gorm.Model{ID: 1},
+			Policy: model.Policy{Type: "mock"},
+		},
+		Policy: &model.Policy{Type: "mock"},
+	}
+	ctx := context.Background()
+
+	err := fs.UploadFromStream(ctx, &fsctx.FileStream{
+		File: ioutil.NopCloser(strings.NewReader("123")),
+	}, true)
+	asserts.Error(err)
+}
+
+func TestFileSystem_UploadFromPath(t *testing.T) {
+	asserts := assert.New(t)
+	fs := FileSystem{
+		User: &model.User{
+			Model:  gorm.Model{ID: 1},
+			Policy: model.Policy{Type: "mock"},
+		},
+		Policy: &model.Policy{Type: "mock"},
+	}
+	ctx := context.Background()
+
+	// 文件不存在
+	{
+		err := fs.UploadFromPath(ctx, "test/not_exist", "/", fsctx.Overwrite)
+		asserts.Error(err)
+	}
+
+	// 文存在,上传失败
+	{
+		err := fs.UploadFromPath(ctx, "tests/test.zip", "/", fsctx.Overwrite)
+		asserts.Error(err)
+	}
+}
diff --git a/pkg/filesystem/validator_test.go b/pkg/filesystem/validator_test.go
index 8a39ae2..8f685f2 100644
--- a/pkg/filesystem/validator_test.go
+++ b/pkg/filesystem/validator_test.go
@@ -68,10 +68,9 @@ func TestFileSystem_ValidateFileSize(t *testing.T) {
 	asserts := assert.New(t)
 	ctx := context.Background()
 	fs := FileSystem{
-		User: &model.User{
-			Policy: model.Policy{
-				MaxSize: 10,
-			},
+		User: &model.User{},
+		Policy: &model.Policy{
+			MaxSize: 10,
 		},
 	}
 
@@ -80,7 +79,7 @@ func TestFileSystem_ValidateFileSize(t *testing.T) {
 	asserts.False(fs.ValidateFileSize(ctx, 11))
 
 	// 无限制
-	fs.User.Policy.MaxSize = 0
+	fs.Policy.MaxSize = 0
 	asserts.True(fs.ValidateFileSize(ctx, 11))
 }
 
@@ -88,11 +87,10 @@ func TestFileSystem_ValidateExtension(t *testing.T) {
 	asserts := assert.New(t)
 	ctx := context.Background()
 	fs := FileSystem{
-		User: &model.User{
-			Policy: model.Policy{
-				OptionsSerialized: model.PolicyOption{
-					FileType: nil,
-				},
+		User: &model.User{},
+		Policy: &model.Policy{
+			OptionsSerialized: model.PolicyOption{
+				FileType: nil,
 			},
 		},
 	}
@@ -100,11 +98,11 @@ func TestFileSystem_ValidateExtension(t *testing.T) {
 	asserts.True(fs.ValidateExtension(ctx, "1"))
 	asserts.True(fs.ValidateExtension(ctx, "1.txt"))
 
-	fs.User.Policy.OptionsSerialized.FileType = []string{}
+	fs.Policy.OptionsSerialized.FileType = []string{}
 	asserts.True(fs.ValidateExtension(ctx, "1"))
 	asserts.True(fs.ValidateExtension(ctx, "1.txt"))
 
-	fs.User.Policy.OptionsSerialized.FileType = []string{"txt", "jpg"}
+	fs.Policy.OptionsSerialized.FileType = []string{"txt", "jpg"}
 	asserts.False(fs.ValidateExtension(ctx, "1"))
 	asserts.False(fs.ValidateExtension(ctx, "1.jpg.png"))
 	asserts.True(fs.ValidateExtension(ctx, "1.txt"))