github.com/cloudreve/Cloudreve/v3@v3.0.0-20240224133659-3edb00a6484c/pkg/filesystem/hooks_test.go (about)

     1  package filesystem
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"github.com/DATA-DOG/go-sqlmock"
     7  	"github.com/cloudreve/Cloudreve/v3/pkg/cache"
     8  	"github.com/cloudreve/Cloudreve/v3/pkg/conf"
     9  	"github.com/cloudreve/Cloudreve/v3/pkg/filesystem/driver/local"
    10  	"github.com/cloudreve/Cloudreve/v3/pkg/filesystem/fsctx"
    11  	"github.com/cloudreve/Cloudreve/v3/pkg/mocks/requestmock"
    12  	"github.com/cloudreve/Cloudreve/v3/pkg/request"
    13  	"github.com/cloudreve/Cloudreve/v3/pkg/serializer"
    14  	"io/ioutil"
    15  	"net/http"
    16  	"strings"
    17  	"testing"
    18  
    19  	model "github.com/cloudreve/Cloudreve/v3/models"
    20  	"github.com/jinzhu/gorm"
    21  	"github.com/stretchr/testify/assert"
    22  	testMock "github.com/stretchr/testify/mock"
    23  )
    24  
    25  func TestGenericBeforeUpload(t *testing.T) {
    26  	asserts := assert.New(t)
    27  	file := &fsctx.FileStream{
    28  		Size: 5,
    29  		Name: "1.txt",
    30  	}
    31  	ctx := context.Background()
    32  	cache.Set("pack_size_0", uint64(0), 0)
    33  	fs := FileSystem{
    34  		User: &model.User{
    35  			Storage: 0,
    36  			Group: model.Group{
    37  				MaxStorage: 11,
    38  			},
    39  		},
    40  		Policy: &model.Policy{
    41  			MaxSize: 4,
    42  			OptionsSerialized: model.PolicyOption{
    43  				FileType: []string{"txt"},
    44  			},
    45  		},
    46  	}
    47  
    48  	asserts.Error(HookValidateFile(ctx, &fs, file))
    49  
    50  	file.Size = 1
    51  	file.Name = "1"
    52  	asserts.Error(HookValidateFile(ctx, &fs, file))
    53  
    54  	file.Name = "1.txt"
    55  	asserts.NoError(HookValidateFile(ctx, &fs, file))
    56  
    57  	file.Name = "1.t/xt"
    58  	asserts.Error(HookValidateFile(ctx, &fs, file))
    59  }
    60  
    61  func TestGenericAfterUploadCanceled(t *testing.T) {
    62  	asserts := assert.New(t)
    63  	file := &fsctx.FileStream{
    64  		Size:     5,
    65  		Name:     "TestGenericAfterUploadCanceled",
    66  		SavePath: "TestGenericAfterUploadCanceled",
    67  	}
    68  	ctx := context.Background()
    69  	fs := FileSystem{
    70  		User: &model.User{},
    71  	}
    72  
    73  	// 成功
    74  	{
    75  		mockHandler := &FileHeaderMock{}
    76  		fs.Handler = mockHandler
    77  		mockHandler.On("Delete", testMock.Anything, testMock.Anything).Return([]string{}, nil)
    78  		err := HookDeleteTempFile(ctx, &fs, file)
    79  		asserts.NoError(err)
    80  		mockHandler.AssertExpectations(t)
    81  	}
    82  
    83  	// 失败
    84  	{
    85  		mockHandler := &FileHeaderMock{}
    86  		fs.Handler = mockHandler
    87  		mockHandler.On("Delete", testMock.Anything, testMock.Anything).Return([]string{}, errors.New(""))
    88  		err := HookDeleteTempFile(ctx, &fs, file)
    89  		asserts.NoError(err)
    90  		mockHandler.AssertExpectations(t)
    91  	}
    92  
    93  }
    94  
    95  func TestGenericAfterUpload(t *testing.T) {
    96  	asserts := assert.New(t)
    97  	fs := FileSystem{
    98  		User: &model.User{
    99  			Model: gorm.Model{
   100  				ID: 1,
   101  			},
   102  		},
   103  		Policy: &model.Policy{},
   104  	}
   105  
   106  	ctx := context.Background()
   107  	file := &fsctx.FileStream{
   108  		VirtualPath: "/我的文件",
   109  		Name:        "test.txt",
   110  	}
   111  
   112  	// 正常
   113  	mock.ExpectQuery("SELECT(.+)").
   114  		WithArgs(1).
   115  		WillReturnRows(sqlmock.NewRows([]string{"id", "owner_id"}).AddRow(1, 1))
   116  	mock.ExpectQuery("SELECT(.+)files").
   117  		WithArgs(1, "我的文件").
   118  		WillReturnRows(sqlmock.NewRows([]string{"id", "owner_id"}))
   119  	// 1
   120  	mock.ExpectQuery("SELECT(.+)").
   121  		WithArgs("我的文件", 1, 1).
   122  		WillReturnRows(sqlmock.NewRows([]string{"id", "owner_id"}).AddRow(2, 1))
   123  	mock.ExpectQuery("SELECT(.+)files(.+)").WillReturnError(errors.New("not found"))
   124  	mock.ExpectBegin()
   125  	mock.ExpectExec("INSERT(.+)files(.+)").WillReturnResult(sqlmock.NewResult(1, 1))
   126  	mock.ExpectExec("UPDATE(.+)storage(.+)").WillReturnResult(sqlmock.NewResult(1, 1))
   127  	mock.ExpectCommit()
   128  
   129  	err := GenericAfterUpload(ctx, &fs, file)
   130  	asserts.NoError(err)
   131  	asserts.NoError(mock.ExpectationsWereMet())
   132  
   133  	// 文件已存在
   134  	mock.ExpectQuery("SELECT(.+)").
   135  		WithArgs(1).
   136  		WillReturnRows(sqlmock.NewRows([]string{"id", "owner_id"}).AddRow(1, 1))
   137  	mock.ExpectQuery("SELECT(.+)files").
   138  		WithArgs(1, "我的文件").
   139  		WillReturnRows(sqlmock.NewRows([]string{"id", "owner_id"}))
   140  	// 1
   141  	mock.ExpectQuery("SELECT(.+)").
   142  		WithArgs("我的文件", 1, 1).
   143  		WillReturnRows(sqlmock.NewRows([]string{"id", "owner_id"}).AddRow(2, 1))
   144  	mock.ExpectQuery("SELECT(.+)files(.+)").WillReturnRows(
   145  		mock.NewRows([]string{"name"}).AddRow("test.txt"),
   146  	)
   147  	err = GenericAfterUpload(ctx, &fs, file)
   148  	asserts.Equal(ErrFileExisted, err)
   149  	asserts.NoError(mock.ExpectationsWereMet())
   150  
   151  	// 文件已存在, 且为上传占位符
   152  	mock.ExpectQuery("SELECT(.+)").
   153  		WithArgs(1).
   154  		WillReturnRows(sqlmock.NewRows([]string{"id", "owner_id"}).AddRow(1, 1))
   155  	mock.ExpectQuery("SELECT(.+)files").
   156  		WithArgs(1, "我的文件").
   157  		WillReturnRows(sqlmock.NewRows([]string{"id", "owner_id"}))
   158  	// 1
   159  	mock.ExpectQuery("SELECT(.+)").
   160  		WithArgs("我的文件", 1, 1).
   161  		WillReturnRows(sqlmock.NewRows([]string{"id", "owner_id"}).AddRow(2, 1))
   162  	mock.ExpectQuery("SELECT(.+)files(.+)").WillReturnRows(
   163  		mock.NewRows([]string{"name", "upload_session_id"}).AddRow("test.txt", "1"),
   164  	)
   165  	err = GenericAfterUpload(ctx, &fs, file)
   166  	asserts.Equal(ErrFileUploadSessionExisted, err)
   167  	asserts.NoError(mock.ExpectationsWereMet())
   168  
   169  	// 插入失败
   170  	mock.ExpectQuery("SELECT(.+)").
   171  		WithArgs(1).
   172  		WillReturnRows(sqlmock.NewRows([]string{"id", "owner_id"}).AddRow(1, 1))
   173  	mock.ExpectQuery("SELECT(.+)files").
   174  		WithArgs(1, "我的文件").
   175  		WillReturnRows(sqlmock.NewRows([]string{"id", "owner_id"}))
   176  	// 1
   177  	mock.ExpectQuery("SELECT(.+)").
   178  		WithArgs("我的文件", 1, 1).
   179  		WillReturnRows(sqlmock.NewRows([]string{"id", "owner_id"}).AddRow(2, 1))
   180  
   181  	mock.ExpectQuery("SELECT(.+)files(.+)").WillReturnError(errors.New("not found"))
   182  	mock.ExpectBegin()
   183  	mock.ExpectExec("INSERT(.+)files(.+)").WillReturnError(errors.New("error"))
   184  	mock.ExpectRollback()
   185  
   186  	err = GenericAfterUpload(ctx, &fs, file)
   187  	asserts.Equal(ErrInsertFileRecord, err)
   188  	asserts.NoError(mock.ExpectationsWereMet())
   189  
   190  }
   191  
   192  func TestFileSystem_Use(t *testing.T) {
   193  	asserts := assert.New(t)
   194  	fs := FileSystem{}
   195  
   196  	hook := func(ctx context.Context, fs *FileSystem, fileHeader fsctx.FileHeader) error {
   197  		return nil
   198  	}
   199  
   200  	// 添加一个
   201  	fs.Use("BeforeUpload", hook)
   202  	asserts.Len(fs.Hooks["BeforeUpload"], 1)
   203  
   204  	// 添加一个
   205  	fs.Use("BeforeUpload", hook)
   206  	asserts.Len(fs.Hooks["BeforeUpload"], 2)
   207  
   208  	// 不存在
   209  	fs.Use("BeforeUpload2333", hook)
   210  
   211  	asserts.NotPanics(func() {
   212  		for _, hookName := range []string{
   213  			"AfterUpload",
   214  			"AfterValidateFailed",
   215  			"AfterUploadCanceled",
   216  			"BeforeFileDownload",
   217  		} {
   218  			fs.Use(hookName, hook)
   219  		}
   220  	})
   221  
   222  }
   223  
   224  func TestFileSystem_Trigger(t *testing.T) {
   225  	asserts := assert.New(t)
   226  	fs := FileSystem{
   227  		User: &model.User{},
   228  	}
   229  	ctx := context.Background()
   230  
   231  	hook := func(ctx context.Context, fs *FileSystem, fileHeader fsctx.FileHeader) error {
   232  		fs.User.Storage++
   233  		return nil
   234  	}
   235  
   236  	// 一个
   237  	fs.Use("BeforeUpload", hook)
   238  	err := fs.Trigger(ctx, "BeforeUpload", nil)
   239  	asserts.NoError(err)
   240  	asserts.Equal(uint64(1), fs.User.Storage)
   241  
   242  	// 多个
   243  	fs.Use("BeforeUpload", hook)
   244  	fs.Use("BeforeUpload", hook)
   245  	err = fs.Trigger(ctx, "BeforeUpload", nil)
   246  	asserts.NoError(err)
   247  	asserts.Equal(uint64(4), fs.User.Storage)
   248  
   249  	// 多个,有失败
   250  	fs.Use("BeforeUpload", func(ctx context.Context, fs *FileSystem, file fsctx.FileHeader) error {
   251  		return errors.New("error")
   252  	})
   253  	fs.Use("BeforeUpload", func(ctx context.Context, fs *FileSystem, file fsctx.FileHeader) error {
   254  		asserts.Fail("following hooks executed")
   255  		return nil
   256  	})
   257  	err = fs.Trigger(ctx, "BeforeUpload", nil)
   258  	asserts.Error(err)
   259  }
   260  
   261  func TestHookValidateCapacity(t *testing.T) {
   262  	asserts := assert.New(t)
   263  	cache.Set("pack_size_1", uint64(0), 0)
   264  	fs := &FileSystem{User: &model.User{
   265  		Model:   gorm.Model{ID: 1},
   266  		Storage: 0,
   267  		Group: model.Group{
   268  			MaxStorage: 11,
   269  		},
   270  	}}
   271  	ctx := context.Background()
   272  	file := &fsctx.FileStream{Size: 11}
   273  	{
   274  		err := HookValidateCapacity(ctx, fs, file)
   275  		asserts.NoError(err)
   276  	}
   277  	{
   278  		file.Size = 12
   279  		err := HookValidateCapacity(ctx, fs, file)
   280  		asserts.Error(err)
   281  	}
   282  }
   283  
   284  func TestHookValidateCapacityDiff(t *testing.T) {
   285  	a := assert.New(t)
   286  	fs := &FileSystem{User: &model.User{
   287  		Group: model.Group{
   288  			MaxStorage: 11,
   289  		},
   290  	}}
   291  	file := model.File{Size: 10}
   292  	ctx := context.WithValue(context.Background(), fsctx.FileModelCtx, file)
   293  
   294  	// 无需操作
   295  	{
   296  		a.NoError(HookValidateCapacityDiff(ctx, fs, &fsctx.FileStream{Size: 10}))
   297  	}
   298  
   299  	// 需要验证
   300  	{
   301  		a.Error(HookValidateCapacityDiff(ctx, fs, &fsctx.FileStream{Size: 12}))
   302  	}
   303  
   304  }
   305  
   306  func TestHookResetPolicy(t *testing.T) {
   307  	asserts := assert.New(t)
   308  	fs := &FileSystem{User: &model.User{
   309  		Model: gorm.Model{ID: 1},
   310  	}}
   311  
   312  	// 成功
   313  	{
   314  		file := model.File{PolicyID: 2}
   315  		cache.Deletes([]string{"2"}, "policy_")
   316  		mock.ExpectQuery("SELECT(.+)policies(.+)").
   317  			WillReturnRows(sqlmock.NewRows([]string{"id", "type"}).AddRow(2, "local"))
   318  		ctx := context.WithValue(context.Background(), fsctx.FileModelCtx, file)
   319  		err := HookResetPolicy(ctx, fs, nil)
   320  		asserts.NoError(mock.ExpectationsWereMet())
   321  		asserts.NoError(err)
   322  	}
   323  
   324  	// 上下文文件不存在
   325  	{
   326  		cache.Deletes([]string{"2"}, "policy_")
   327  		ctx := context.Background()
   328  		err := HookResetPolicy(ctx, fs, nil)
   329  		asserts.Error(err)
   330  	}
   331  }
   332  
   333  func TestHookCleanFileContent(t *testing.T) {
   334  	asserts := assert.New(t)
   335  	fs := &FileSystem{User: &model.User{
   336  		Model: gorm.Model{ID: 1},
   337  	}}
   338  
   339  	file := &fsctx.FileStream{SavePath: "123/123"}
   340  	handlerMock := FileHeaderMock{}
   341  	handlerMock.On("Put", testMock.Anything, testMock.Anything).Return(errors.New("error"))
   342  	fs.Handler = handlerMock
   343  	err := HookCleanFileContent(context.Background(), fs, file)
   344  	asserts.Error(err)
   345  	handlerMock.AssertExpectations(t)
   346  }
   347  
   348  func TestHookClearFileSize(t *testing.T) {
   349  	asserts := assert.New(t)
   350  	fs := &FileSystem{User: &model.User{
   351  		Model: gorm.Model{ID: 1},
   352  	}}
   353  
   354  	// 成功
   355  	{
   356  		ctx := context.WithValue(
   357  			context.Background(),
   358  			fsctx.FileModelCtx,
   359  			model.File{Model: gorm.Model{ID: 1}, Size: 10},
   360  		)
   361  		mock.ExpectBegin()
   362  		mock.ExpectExec("UPDATE(.+)files(.+)").
   363  			WithArgs("", 0, sqlmock.AnyArg(), 1, 10).
   364  			WillReturnResult(sqlmock.NewResult(1, 1))
   365  		mock.ExpectExec("UPDATE(.+)users(.+)").
   366  			WithArgs(10, sqlmock.AnyArg()).
   367  			WillReturnResult(sqlmock.NewResult(1, 1))
   368  		mock.ExpectCommit()
   369  		err := HookClearFileSize(ctx, fs, nil)
   370  		asserts.NoError(mock.ExpectationsWereMet())
   371  		asserts.NoError(err)
   372  	}
   373  
   374  	// 上下文对象不存在
   375  	{
   376  		ctx := context.Background()
   377  		err := HookClearFileSize(ctx, fs, nil)
   378  		asserts.Error(err)
   379  	}
   380  
   381  }
   382  
   383  func TestHookUpdateSourceName(t *testing.T) {
   384  	asserts := assert.New(t)
   385  	fs := &FileSystem{User: &model.User{
   386  		Model: gorm.Model{ID: 1},
   387  	}}
   388  
   389  	// 成功
   390  	{
   391  		originFile := model.File{
   392  			Model:      gorm.Model{ID: 1},
   393  			SourceName: "new.txt",
   394  		}
   395  		ctx := context.WithValue(context.Background(), fsctx.FileModelCtx, originFile)
   396  		mock.ExpectBegin()
   397  		mock.ExpectExec("UPDATE(.+)").WithArgs("", "new.txt", sqlmock.AnyArg(), 1).WillReturnResult(sqlmock.NewResult(1, 1))
   398  		mock.ExpectCommit()
   399  		err := HookUpdateSourceName(ctx, fs, nil)
   400  		asserts.NoError(mock.ExpectationsWereMet())
   401  		asserts.NoError(err)
   402  	}
   403  
   404  	// 上下文错误
   405  	{
   406  		ctx := context.Background()
   407  		err := HookUpdateSourceName(ctx, fs, nil)
   408  		asserts.Error(err)
   409  	}
   410  }
   411  
   412  func TestGenericAfterUpdate(t *testing.T) {
   413  	asserts := assert.New(t)
   414  	fs := &FileSystem{User: &model.User{
   415  		Model: gorm.Model{ID: 1},
   416  	}}
   417  
   418  	// 成功 是图像文件
   419  	{
   420  		originFile := model.File{
   421  			Model:   gorm.Model{ID: 1},
   422  			PicInfo: "1,1",
   423  		}
   424  		newFile := &fsctx.FileStream{Size: 10}
   425  		ctx := context.WithValue(context.Background(), fsctx.FileModelCtx, originFile)
   426  
   427  		handlerMock := FileHeaderMock{}
   428  		handlerMock.On("Delete", testMock.Anything, []string{"._thumb"}).Return([]string{}, nil)
   429  		fs.Handler = handlerMock
   430  		mock.ExpectBegin()
   431  		mock.ExpectExec("UPDATE(.+)files(.+)").
   432  			WithArgs("", 10, sqlmock.AnyArg(), 1, 0).
   433  			WillReturnResult(sqlmock.NewResult(1, 1))
   434  		mock.ExpectExec("UPDATE(.+)users(.+)").
   435  			WithArgs(10, sqlmock.AnyArg()).
   436  			WillReturnResult(sqlmock.NewResult(1, 1))
   437  		mock.ExpectCommit()
   438  
   439  		err := GenericAfterUpdate(ctx, fs, newFile)
   440  
   441  		asserts.NoError(mock.ExpectationsWereMet())
   442  		asserts.NoError(err)
   443  	}
   444  
   445  	// 原始文件上下文不存在
   446  	{
   447  		newFile := &fsctx.FileStream{Size: 10}
   448  		ctx := context.Background()
   449  		err := GenericAfterUpdate(ctx, fs, newFile)
   450  		asserts.Error(err)
   451  	}
   452  
   453  	// 无法更新数据库容量
   454  	// 成功 是图像文件
   455  	{
   456  		originFile := model.File{
   457  			Model:   gorm.Model{ID: 1},
   458  			PicInfo: "1,1",
   459  		}
   460  		newFile := &fsctx.FileStream{Size: 10}
   461  		ctx := context.WithValue(context.Background(), fsctx.FileModelCtx, originFile)
   462  
   463  		mock.ExpectBegin()
   464  		mock.ExpectExec("UPDATE(.+)").
   465  			WithArgs("", 10, sqlmock.AnyArg(), 1, 0).
   466  			WillReturnError(errors.New("error"))
   467  		mock.ExpectRollback()
   468  
   469  		err := GenericAfterUpdate(ctx, fs, newFile)
   470  
   471  		asserts.NoError(mock.ExpectationsWereMet())
   472  		asserts.Error(err)
   473  	}
   474  }
   475  
   476  func TestSlaveAfterUpload(t *testing.T) {
   477  	asserts := assert.New(t)
   478  	conf.SystemConfig.Mode = "slave"
   479  	fs, err := NewAnonymousFileSystem()
   480  	conf.SystemConfig.Mode = "master"
   481  	asserts.NoError(err)
   482  
   483  	// 成功
   484  	{
   485  		clientMock := requestmock.RequestMock{}
   486  		clientMock.On(
   487  			"Request",
   488  			"POST",
   489  			"http://test/callbakc",
   490  			testMock.Anything,
   491  			testMock.Anything,
   492  		).Return(&request.Response{
   493  			Err: nil,
   494  			Response: &http.Response{
   495  				StatusCode: 200,
   496  				Body:       ioutil.NopCloser(strings.NewReader(`{"code":0}`)),
   497  			},
   498  		})
   499  		request.GeneralClient = clientMock
   500  		file := &fsctx.FileStream{
   501  			Size:        10,
   502  			VirtualPath: "/my",
   503  			Name:        "test.txt",
   504  			SavePath:    "/not_exist",
   505  		}
   506  		err := SlaveAfterUpload(&serializer.UploadSession{Callback: "http://test/callbakc"})(context.Background(), fs, file)
   507  		clientMock.AssertExpectations(t)
   508  		asserts.NoError(err)
   509  	}
   510  
   511  	// 跳过回调
   512  	{
   513  		file := &fsctx.FileStream{
   514  			Size:        10,
   515  			VirtualPath: "/my",
   516  			Name:        "test.txt",
   517  			SavePath:    "/not_exist",
   518  		}
   519  		err := SlaveAfterUpload(&serializer.UploadSession{})(context.Background(), fs, file)
   520  		asserts.NoError(err)
   521  	}
   522  }
   523  
   524  func TestFileSystem_CleanHooks(t *testing.T) {
   525  	asserts := assert.New(t)
   526  	fs := &FileSystem{
   527  		User: &model.User{
   528  			Model: gorm.Model{ID: 1},
   529  		},
   530  		Hooks: map[string][]Hook{
   531  			"hook1": []Hook{},
   532  			"hook2": []Hook{},
   533  			"hook3": []Hook{},
   534  		},
   535  	}
   536  
   537  	// 清理一个
   538  	{
   539  		fs.CleanHooks("hook2")
   540  		asserts.Len(fs.Hooks, 2)
   541  		asserts.Contains(fs.Hooks, "hook1")
   542  		asserts.Contains(fs.Hooks, "hook3")
   543  	}
   544  
   545  	// 清理全部
   546  	{
   547  		fs.CleanHooks("")
   548  		asserts.Len(fs.Hooks, 0)
   549  	}
   550  }
   551  
   552  func TestHookCancelContext(t *testing.T) {
   553  	asserts := assert.New(t)
   554  	fs := &FileSystem{}
   555  	ctx, cancel := context.WithCancel(context.Background())
   556  
   557  	// empty ctx
   558  	{
   559  		asserts.NoError(HookCancelContext(ctx, fs, nil))
   560  		select {
   561  		case <-ctx.Done():
   562  			t.Errorf("Channel should not be closed")
   563  		default:
   564  
   565  		}
   566  	}
   567  
   568  	// with cancel ctx
   569  	{
   570  		ctx = context.WithValue(ctx, fsctx.CancelFuncCtx, cancel)
   571  		asserts.NoError(HookCancelContext(ctx, fs, nil))
   572  		_, ok := <-ctx.Done()
   573  		asserts.False(ok)
   574  	}
   575  }
   576  
   577  func TestHookClearFileHeaderSize(t *testing.T) {
   578  	a := assert.New(t)
   579  	fs := &FileSystem{}
   580  	file := &fsctx.FileStream{Size: 10}
   581  	a.NoError(HookClearFileHeaderSize(context.Background(), fs, file))
   582  	a.EqualValues(0, file.Size)
   583  }
   584  
   585  func TestHookTruncateFileTo(t *testing.T) {
   586  	a := assert.New(t)
   587  	fs := &FileSystem{}
   588  	file := &fsctx.FileStream{}
   589  	a.NoError(HookTruncateFileTo(0)(context.Background(), fs, file))
   590  
   591  	fs.Handler = local.Driver{}
   592  	a.Error(HookTruncateFileTo(0)(context.Background(), fs, file))
   593  }
   594  
   595  func TestHookChunkUploaded(t *testing.T) {
   596  	a := assert.New(t)
   597  	fs := &FileSystem{}
   598  	file := &fsctx.FileStream{
   599  		AppendStart: 10,
   600  		Size:        10,
   601  		Model: &model.File{
   602  			Model: gorm.Model{ID: 1},
   603  		},
   604  	}
   605  
   606  	mock.ExpectBegin()
   607  	mock.ExpectExec("UPDATE(.+)files(.+)").WithArgs("", 20, sqlmock.AnyArg(), 1, 0).WillReturnResult(sqlmock.NewResult(1, 1))
   608  	mock.ExpectExec("UPDATE(.+)users(.+)").
   609  		WithArgs(20, sqlmock.AnyArg()).
   610  		WillReturnResult(sqlmock.NewResult(1, 1))
   611  	mock.ExpectCommit()
   612  	a.NoError(HookChunkUploaded(context.Background(), fs, file))
   613  	a.NoError(mock.ExpectationsWereMet())
   614  }
   615  
   616  func TestHookChunkUploadFailed(t *testing.T) {
   617  	a := assert.New(t)
   618  	fs := &FileSystem{}
   619  	file := &fsctx.FileStream{
   620  		AppendStart: 10,
   621  		Size:        10,
   622  		Model: &model.File{
   623  			Model: gorm.Model{ID: 1},
   624  		},
   625  	}
   626  
   627  	mock.ExpectBegin()
   628  	mock.ExpectExec("UPDATE(.+)files(.+)").WithArgs("", 10, sqlmock.AnyArg(), 1, 0).WillReturnResult(sqlmock.NewResult(1, 1))
   629  	mock.ExpectExec("UPDATE(.+)users(.+)").
   630  		WithArgs(10, sqlmock.AnyArg()).
   631  		WillReturnResult(sqlmock.NewResult(1, 1))
   632  	mock.ExpectCommit()
   633  	a.NoError(HookChunkUploadFailed(context.Background(), fs, file))
   634  	a.NoError(mock.ExpectationsWereMet())
   635  }
   636  
   637  func TestHookPopPlaceholderToFile(t *testing.T) {
   638  	a := assert.New(t)
   639  	fs := &FileSystem{}
   640  	file := &fsctx.FileStream{
   641  		Model: &model.File{
   642  			Model: gorm.Model{ID: 1},
   643  		},
   644  	}
   645  
   646  	mock.ExpectBegin()
   647  	mock.ExpectExec("UPDATE(.+)files(.+)").WillReturnResult(sqlmock.NewResult(1, 1))
   648  	mock.ExpectCommit()
   649  	a.NoError(HookPopPlaceholderToFile("1,1")(context.Background(), fs, file))
   650  	a.NoError(mock.ExpectationsWereMet())
   651  }
   652  
   653  func TestHookPopPlaceholderToFileBySuffix(t *testing.T) {
   654  	a := assert.New(t)
   655  	fs := &FileSystem{
   656  		Policy: &model.Policy{Type: "cos"},
   657  	}
   658  	file := &fsctx.FileStream{
   659  		Name: "1.png",
   660  		Model: &model.File{
   661  			Model: gorm.Model{ID: 1},
   662  		},
   663  	}
   664  
   665  	mock.ExpectBegin()
   666  	mock.ExpectExec("UPDATE(.+)files(.+)").WillReturnResult(sqlmock.NewResult(1, 1))
   667  	mock.ExpectCommit()
   668  	a.NoError(HookPopPlaceholderToFile("")(context.Background(), fs, file))
   669  	a.NoError(mock.ExpectationsWereMet())
   670  }
   671  
   672  func TestHookDeleteUploadSession(t *testing.T) {
   673  	a := assert.New(t)
   674  	fs := &FileSystem{}
   675  	file := &fsctx.FileStream{
   676  		Model: &model.File{
   677  			Model: gorm.Model{ID: 1},
   678  		},
   679  	}
   680  
   681  	cache.Set(UploadSessionCachePrefix+"TestHookDeleteUploadSession", "", 0)
   682  	a.NoError(HookDeleteUploadSession("TestHookDeleteUploadSession")(context.Background(), fs, file))
   683  	_, ok := cache.Get(UploadSessionCachePrefix + "TestHookDeleteUploadSession")
   684  	a.False(ok)
   685  }
   686  func TestNewWebdavAfterUploadHook(t *testing.T) {
   687  	a := assert.New(t)
   688  	fs := &FileSystem{}
   689  	file := &fsctx.FileStream{
   690  		Model: &model.File{
   691  			Model: gorm.Model{ID: 1},
   692  		},
   693  	}
   694  
   695  	req, _ := http.NewRequest("get", "http://localhost", nil)
   696  	req.Header.Add("X-Oc-Mtime", "1681521402")
   697  	req.Header.Add("OC-Checksum", "checksum")
   698  	mock.ExpectBegin()
   699  	mock.ExpectExec("UPDATE(.+)files(.+)").WillReturnResult(sqlmock.NewResult(1, 1))
   700  	mock.ExpectCommit()
   701  	mock.ExpectBegin()
   702  	mock.ExpectExec("UPDATE(.+)files(.+)").WillReturnResult(sqlmock.NewResult(1, 1))
   703  	mock.ExpectCommit()
   704  	err := NewWebdavAfterUploadHook(req)(context.Background(), fs, file)
   705  	a.NoError(err)
   706  	a.NoError(mock.ExpectationsWereMet())
   707  
   708  }