github.com/cloudreve/Cloudreve/v3@v3.0.0-20240224133659-3edb00a6484c/models/file_test.go (about)

     1  package model
     2  
     3  import (
     4  	"errors"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/DATA-DOG/go-sqlmock"
     9  	"github.com/jinzhu/gorm"
    10  	"github.com/stretchr/testify/assert"
    11  )
    12  
    13  func TestFile_Create(t *testing.T) {
    14  	asserts := assert.New(t)
    15  	file := File{
    16  		Name: "123",
    17  	}
    18  
    19  	// 无法插入文件记录
    20  	{
    21  		mock.ExpectBegin()
    22  		mock.ExpectExec("INSERT(.+)").WillReturnError(errors.New("error"))
    23  		mock.ExpectRollback()
    24  		err := file.Create()
    25  		asserts.Error(err)
    26  		asserts.NoError(mock.ExpectationsWereMet())
    27  	}
    28  
    29  	// 无法更新用户容量
    30  	{
    31  		mock.ExpectBegin()
    32  		mock.ExpectExec("INSERT(.+)").WillReturnResult(sqlmock.NewResult(5, 1))
    33  		mock.ExpectExec("UPDATE(.+)").WillReturnError(errors.New("error"))
    34  		mock.ExpectRollback()
    35  		err := file.Create()
    36  		asserts.Error(err)
    37  		asserts.NoError(mock.ExpectationsWereMet())
    38  	}
    39  
    40  	// 成功
    41  	{
    42  		mock.ExpectBegin()
    43  		mock.ExpectExec("INSERT(.+)").WillReturnResult(sqlmock.NewResult(5, 1))
    44  		mock.ExpectExec("UPDATE(.+)storage(.+)").WillReturnResult(sqlmock.NewResult(0, 1))
    45  		mock.ExpectCommit()
    46  		err := file.Create()
    47  		asserts.NoError(err)
    48  		asserts.Equal(uint(5), file.ID)
    49  		asserts.NoError(mock.ExpectationsWereMet())
    50  	}
    51  }
    52  
    53  func TestFile_AfterFind(t *testing.T) {
    54  	a := assert.New(t)
    55  
    56  	// metadata not empty
    57  	{
    58  		file := File{
    59  			Name:     "123",
    60  			Metadata: "{\"name\":\"123\"}",
    61  		}
    62  
    63  		a.NoError(file.AfterFind())
    64  		a.Equal("123", file.MetadataSerialized["name"])
    65  	}
    66  
    67  	// metadata empty
    68  	{
    69  		file := File{
    70  			Name:     "123",
    71  			Metadata: "",
    72  		}
    73  		a.Nil(file.MetadataSerialized)
    74  		a.NoError(file.AfterFind())
    75  		a.NotNil(file.MetadataSerialized)
    76  	}
    77  }
    78  
    79  func TestFile_BeforeSave(t *testing.T) {
    80  	a := assert.New(t)
    81  
    82  	// metadata not empty
    83  	{
    84  		file := File{
    85  			Name: "123",
    86  			MetadataSerialized: map[string]string{
    87  				"name": "123",
    88  			},
    89  		}
    90  
    91  		a.NoError(file.BeforeSave())
    92  		a.Equal("{\"name\":\"123\"}", file.Metadata)
    93  	}
    94  
    95  	// metadata empty
    96  	{
    97  		file := File{
    98  			Name: "123",
    99  		}
   100  		a.NoError(file.BeforeSave())
   101  		a.Equal("", file.Metadata)
   102  	}
   103  }
   104  
   105  func TestFolder_GetChildFile(t *testing.T) {
   106  	asserts := assert.New(t)
   107  	folder := Folder{Model: gorm.Model{ID: 1}, Name: "/"}
   108  	// 存在
   109  	{
   110  		mock.ExpectQuery("SELECT(.+)").
   111  			WithArgs(1, "1.txt").
   112  			WillReturnRows(sqlmock.NewRows([]string{"id", "name"}).AddRow(1, "1.txt"))
   113  		file, err := folder.GetChildFile("1.txt")
   114  		asserts.NoError(mock.ExpectationsWereMet())
   115  		asserts.NoError(err)
   116  		asserts.Equal("1.txt", file.Name)
   117  		asserts.Equal("/", file.Position)
   118  	}
   119  
   120  	// 不存在
   121  	{
   122  		mock.ExpectQuery("SELECT(.+)").
   123  			WithArgs(1, "1.txt").
   124  			WillReturnRows(sqlmock.NewRows([]string{"id", "name"}))
   125  		_, err := folder.GetChildFile("1.txt")
   126  		asserts.NoError(mock.ExpectationsWereMet())
   127  		asserts.Error(err)
   128  	}
   129  }
   130  
   131  func TestFolder_GetChildFiles(t *testing.T) {
   132  	asserts := assert.New(t)
   133  	folder := &Folder{
   134  		Model: gorm.Model{
   135  			ID: 1,
   136  		},
   137  		Position: "/123",
   138  		Name:     "456",
   139  	}
   140  
   141  	// 找不到
   142  	mock.ExpectQuery("SELECT(.+)folder_id(.+)").WithArgs(1).WillReturnError(errors.New("error"))
   143  	files, err := folder.GetChildFiles()
   144  	asserts.Error(err)
   145  	asserts.Len(files, 0)
   146  	asserts.NoError(mock.ExpectationsWereMet())
   147  
   148  	// 找到了
   149  	mock.ExpectQuery("SELECT(.+)folder_id(.+)").WithArgs(1).WillReturnRows(sqlmock.NewRows([]string{"name", "id"}).AddRow("1.txt", 1).AddRow("2.txt", 2))
   150  	files, err = folder.GetChildFiles()
   151  	asserts.NoError(err)
   152  	asserts.Len(files, 2)
   153  	asserts.Equal("/123/456", files[0].Position)
   154  	asserts.NoError(mock.ExpectationsWereMet())
   155  
   156  }
   157  
   158  func TestGetFilesByIDs(t *testing.T) {
   159  	asserts := assert.New(t)
   160  
   161  	// 出错
   162  	{
   163  		mock.ExpectQuery("SELECT(.+)").
   164  			WithArgs(1, 2, 3, 1).
   165  			WillReturnError(errors.New("error"))
   166  		folders, err := GetFilesByIDs([]uint{1, 2, 3}, 1)
   167  		asserts.NoError(mock.ExpectationsWereMet())
   168  		asserts.Error(err)
   169  		asserts.Len(folders, 0)
   170  	}
   171  
   172  	// 部分找到
   173  	{
   174  		mock.ExpectQuery("SELECT(.+)").
   175  			WithArgs(1, 2, 3, 1).
   176  			WillReturnRows(sqlmock.NewRows([]string{"id", "name"}).AddRow(1, "1"))
   177  		folders, err := GetFilesByIDs([]uint{1, 2, 3}, 1)
   178  		asserts.NoError(mock.ExpectationsWereMet())
   179  		asserts.NoError(err)
   180  		asserts.Len(folders, 1)
   181  	}
   182  
   183  	// 忽略UID查找
   184  	{
   185  		mock.ExpectQuery("SELECT(.+)").
   186  			WithArgs(1, 2, 3).
   187  			WillReturnRows(sqlmock.NewRows([]string{"id", "name"}).AddRow(1, "1"))
   188  		folders, err := GetFilesByIDs([]uint{1, 2, 3}, 0)
   189  		asserts.NoError(mock.ExpectationsWereMet())
   190  		asserts.NoError(err)
   191  		asserts.Len(folders, 1)
   192  	}
   193  }
   194  
   195  func TestGetChildFilesOfFolders(t *testing.T) {
   196  	asserts := assert.New(t)
   197  	testFolder := []Folder{
   198  		Folder{
   199  			Model: gorm.Model{ID: 3},
   200  		},
   201  		Folder{
   202  			Model: gorm.Model{ID: 4},
   203  		}, Folder{
   204  			Model: gorm.Model{ID: 5},
   205  		},
   206  	}
   207  
   208  	// 出错
   209  	{
   210  		mock.ExpectQuery("SELECT(.+)folder_id").WithArgs(3, 4, 5).WillReturnError(errors.New("not found"))
   211  		files, err := GetChildFilesOfFolders(&testFolder)
   212  		asserts.Error(err)
   213  		asserts.Len(files, 0)
   214  		asserts.NoError(mock.ExpectationsWereMet())
   215  	}
   216  
   217  	// 找到2个
   218  	{
   219  		mock.ExpectQuery("SELECT(.+)folder_id").
   220  			WithArgs(3, 4, 5).
   221  			WillReturnRows(sqlmock.NewRows([]string{"id", "name"}).
   222  				AddRow(3, "3").
   223  				AddRow(4, "4"),
   224  			)
   225  		files, err := GetChildFilesOfFolders(&testFolder)
   226  		asserts.NoError(err)
   227  		asserts.Len(files, 2)
   228  		asserts.NoError(mock.ExpectationsWereMet())
   229  	}
   230  
   231  	// 全部找到
   232  	{
   233  		mock.ExpectQuery("SELECT(.+)folder_id").
   234  			WithArgs(3, 4, 5).
   235  			WillReturnRows(sqlmock.NewRows([]string{"id", "name"}).
   236  				AddRow(3, "3").
   237  				AddRow(4, "4").
   238  				AddRow(5, "5"),
   239  			)
   240  		files, err := GetChildFilesOfFolders(&testFolder)
   241  		asserts.NoError(err)
   242  		asserts.Len(files, 3)
   243  		asserts.NoError(mock.ExpectationsWereMet())
   244  	}
   245  }
   246  
   247  func TestGetUploadPlaceholderFiles(t *testing.T) {
   248  	a := assert.New(t)
   249  
   250  	mock.ExpectQuery("SELECT(.+)upload_session_id(.+)").
   251  		WithArgs(1).
   252  		WillReturnRows(sqlmock.NewRows([]string{"id", "name"}).AddRow(1, "1"))
   253  	files := GetUploadPlaceholderFiles(1)
   254  	a.NoError(mock.ExpectationsWereMet())
   255  	a.Len(files, 1)
   256  }
   257  
   258  func TestFile_GetPolicy(t *testing.T) {
   259  	asserts := assert.New(t)
   260  
   261  	// 空策略
   262  	{
   263  		file := File{
   264  			PolicyID: 23,
   265  		}
   266  		mock.ExpectQuery("SELECT(.+)policies(.+)").
   267  			WillReturnRows(
   268  				sqlmock.NewRows([]string{"id", "name"}).
   269  					AddRow(23, "name"),
   270  			)
   271  		file.GetPolicy()
   272  		asserts.NoError(mock.ExpectationsWereMet())
   273  		asserts.Equal(uint(23), file.Policy.ID)
   274  	}
   275  
   276  	// 非空策略
   277  	{
   278  		file := File{
   279  			PolicyID: 23,
   280  			Policy:   Policy{Model: gorm.Model{ID: 24}},
   281  		}
   282  		file.GetPolicy()
   283  		asserts.NoError(mock.ExpectationsWereMet())
   284  		asserts.Equal(uint(24), file.Policy.ID)
   285  	}
   286  }
   287  
   288  func TestRemoveFilesWithSoftLinks_EmptyArg(t *testing.T) {
   289  	asserts := assert.New(t)
   290  	// 传入空
   291  	{
   292  		mock.ExpectQuery("SELECT(.+)files(.+)")
   293  		file, err := RemoveFilesWithSoftLinks([]File{})
   294  		asserts.Error(mock.ExpectationsWereMet())
   295  		asserts.NoError(err)
   296  		asserts.Equal(len(file), 0)
   297  		DB.Find(&File{})
   298  	}
   299  }
   300  
   301  func TestRemoveFilesWithSoftLinks(t *testing.T) {
   302  	asserts := assert.New(t)
   303  	files := []File{
   304  		File{
   305  			Model:      gorm.Model{ID: 1},
   306  			SourceName: "1.txt",
   307  			PolicyID:   23,
   308  		},
   309  		File{
   310  			Model:      gorm.Model{ID: 2},
   311  			SourceName: "2.txt",
   312  			PolicyID:   24,
   313  		},
   314  	}
   315  
   316  	// 传入空文件列表
   317  	{
   318  		file, err := RemoveFilesWithSoftLinks([]File{})
   319  		asserts.NoError(err)
   320  		asserts.Empty(file)
   321  	}
   322  
   323  	// 全都没有
   324  	{
   325  		mock.ExpectQuery("SELECT(.+)files(.+)").
   326  			WithArgs("1.txt", 23, 1).
   327  			WillReturnRows(sqlmock.NewRows([]string{"id", "policy_id", "source_name"}))
   328  		mock.ExpectQuery("SELECT(.+)files(.+)").
   329  			WithArgs("2.txt", 24, 2).
   330  			WillReturnRows(sqlmock.NewRows([]string{"id", "policy_id", "source_name"}))
   331  		file, err := RemoveFilesWithSoftLinks(files)
   332  		asserts.NoError(mock.ExpectationsWereMet())
   333  		asserts.NoError(err)
   334  		asserts.Equal(files, file)
   335  	}
   336  
   337  	// 第二个是软链
   338  	{
   339  		mock.ExpectQuery("SELECT(.+)files(.+)").
   340  			WithArgs("1.txt", 23, 1).
   341  			WillReturnRows(sqlmock.NewRows([]string{"id", "policy_id", "source_name"}))
   342  		mock.ExpectQuery("SELECT(.+)files(.+)").
   343  			WithArgs("2.txt", 24, 2).
   344  			WillReturnRows(
   345  				sqlmock.NewRows([]string{"id", "policy_id", "source_name"}).
   346  					AddRow(3, 24, "2.txt"),
   347  			)
   348  		file, err := RemoveFilesWithSoftLinks(files)
   349  		asserts.NoError(mock.ExpectationsWereMet())
   350  		asserts.NoError(err)
   351  		asserts.Equal(files[:1], file)
   352  	}
   353  
   354  	// 第一个是软链
   355  	{
   356  		mock.ExpectQuery("SELECT(.+)files(.+)").
   357  			WithArgs("1.txt", 23, 1).
   358  			WillReturnRows(
   359  				sqlmock.NewRows([]string{"id", "policy_id", "source_name"}).
   360  					AddRow(3, 23, "1.txt"),
   361  			)
   362  		mock.ExpectQuery("SELECT(.+)files(.+)").
   363  			WithArgs("2.txt", 24, 2).
   364  			WillReturnRows(sqlmock.NewRows([]string{"id", "policy_id", "source_name"}))
   365  		file, err := RemoveFilesWithSoftLinks(files)
   366  		asserts.NoError(mock.ExpectationsWereMet())
   367  		asserts.NoError(err)
   368  		asserts.Equal(files[1:], file)
   369  	}
   370  	// 全部是软链
   371  	{
   372  		mock.ExpectQuery("SELECT(.+)files(.+)").
   373  			WithArgs("1.txt", 23, 1).
   374  			WillReturnRows(
   375  				sqlmock.NewRows([]string{"id", "policy_id", "source_name"}).
   376  					AddRow(3, 23, "1.txt"),
   377  			)
   378  		mock.ExpectQuery("SELECT(.+)files(.+)").
   379  			WithArgs("2.txt", 24, 2).
   380  			WillReturnRows(
   381  				sqlmock.NewRows([]string{"id", "policy_id", "source_name"}).
   382  					AddRow(3, 24, "2.txt"),
   383  			)
   384  		file, err := RemoveFilesWithSoftLinks(files)
   385  		asserts.NoError(mock.ExpectationsWereMet())
   386  		asserts.NoError(err)
   387  		asserts.Len(file, 0)
   388  	}
   389  }
   390  
   391  func TestDeleteFiles(t *testing.T) {
   392  	a := assert.New(t)
   393  
   394  	// uid 不一致
   395  	{
   396  		err := DeleteFiles([]*File{{UserID: 2}}, 1)
   397  		a.Contains("user id not consistent", err.Error())
   398  	}
   399  
   400  	// 删除失败
   401  	{
   402  		mock.ExpectBegin()
   403  		mock.ExpectExec("DELETE(.+)").
   404  			WillReturnError(errors.New("error"))
   405  		mock.ExpectRollback()
   406  		err := DeleteFiles([]*File{{UserID: 1}}, 1)
   407  		a.NoError(mock.ExpectationsWereMet())
   408  		a.Error(err)
   409  	}
   410  
   411  	// 无法变更用户容量
   412  	{
   413  		mock.ExpectBegin()
   414  		mock.ExpectExec("DELETE(.+)").
   415  			WillReturnResult(sqlmock.NewResult(1, 1))
   416  		mock.ExpectExec("UPDATE(.+)storage(.+)").WillReturnError(errors.New("error"))
   417  		mock.ExpectRollback()
   418  		err := DeleteFiles([]*File{{UserID: 1}}, 1)
   419  		a.NoError(mock.ExpectationsWereMet())
   420  		a.Error(err)
   421  	}
   422  
   423  	// 文件脏读
   424  	{
   425  		mock.ExpectBegin()
   426  		mock.ExpectExec("DELETE(.+)").
   427  			WillReturnResult(sqlmock.NewResult(1, 0))
   428  		mock.ExpectRollback()
   429  		err := DeleteFiles([]*File{{Size: 1, UserID: 1}, {Size: 2, UserID: 1}}, 1)
   430  		a.NoError(mock.ExpectationsWereMet())
   431  		a.Error(err)
   432  		a.Contains("file size is dirty", err.Error())
   433  	}
   434  
   435  	// 成功
   436  	{
   437  		mock.ExpectBegin()
   438  		mock.ExpectExec("DELETE(.+)").
   439  			WillReturnResult(sqlmock.NewResult(2, 1))
   440  		mock.ExpectExec("DELETE(.+)").
   441  			WillReturnResult(sqlmock.NewResult(2, 1))
   442  		mock.ExpectExec("UPDATE(.+)storage(.+)").WithArgs(uint64(3), sqlmock.AnyArg(), uint(1)).WillReturnResult(sqlmock.NewResult(1, 1))
   443  		mock.ExpectCommit()
   444  		err := DeleteFiles([]*File{{Size: 1, UserID: 1}, {Size: 2, UserID: 1}}, 1)
   445  		a.NoError(mock.ExpectationsWereMet())
   446  		a.NoError(err)
   447  	}
   448  
   449  	// 成功,  关联用户不存在
   450  	{
   451  		mock.ExpectBegin()
   452  		mock.ExpectExec("DELETE(.+)").
   453  			WillReturnResult(sqlmock.NewResult(2, 1))
   454  		mock.ExpectExec("DELETE(.+)").
   455  			WillReturnResult(sqlmock.NewResult(2, 1))
   456  		mock.ExpectCommit()
   457  		err := DeleteFiles([]*File{{Size: 1, UserID: 1}, {Size: 2, UserID: 1}}, 0)
   458  		a.NoError(mock.ExpectationsWereMet())
   459  		a.NoError(err)
   460  	}
   461  }
   462  
   463  func TestGetFilesByParentIDs(t *testing.T) {
   464  	asserts := assert.New(t)
   465  
   466  	mock.ExpectQuery("SELECT(.+)").
   467  		WithArgs(1, 4, 5, 6).
   468  		WillReturnRows(
   469  			sqlmock.NewRows([]string{"id", "name"}).
   470  				AddRow(4, "4.txt").
   471  				AddRow(5, "5.txt").
   472  				AddRow(6, "6.txt"),
   473  		)
   474  	files, err := GetFilesByParentIDs([]uint{4, 5, 6}, 1)
   475  	asserts.NoError(err)
   476  	asserts.NoError(mock.ExpectationsWereMet())
   477  	asserts.Len(files, 3)
   478  }
   479  
   480  func TestGetFilesByUploadSession(t *testing.T) {
   481  	a := assert.New(t)
   482  
   483  	mock.ExpectQuery("SELECT(.+)").
   484  		WithArgs(1, "sessionID").
   485  		WillReturnRows(
   486  			sqlmock.NewRows([]string{"id", "name"}).AddRow(4, "4.txt"))
   487  	files, err := GetFilesByUploadSession("sessionID", 1)
   488  	a.NoError(err)
   489  	a.NoError(mock.ExpectationsWereMet())
   490  	a.Equal("4.txt", files.Name)
   491  }
   492  
   493  func TestFile_Updates(t *testing.T) {
   494  	asserts := assert.New(t)
   495  	file := File{Model: gorm.Model{ID: 1}}
   496  
   497  	// rename
   498  	{
   499  		// not reset thumb
   500  		{
   501  			file := File{Model: gorm.Model{ID: 1}}
   502  			mock.ExpectBegin()
   503  			mock.ExpectExec("UPDATE(.+)files(.+)SET(.+)").WithArgs("", "newName", sqlmock.AnyArg(), 1).WillReturnResult(sqlmock.NewResult(1, 1))
   504  			mock.ExpectCommit()
   505  			err := file.Rename("newName")
   506  			asserts.NoError(mock.ExpectationsWereMet())
   507  			asserts.NoError(err)
   508  		}
   509  
   510  		// thumb not available, rename base name only
   511  		{
   512  			file := File{Model: gorm.Model{ID: 1}, Name: "1.txt", MetadataSerialized: map[string]string{
   513  				ThumbStatusMetadataKey: ThumbStatusNotAvailable,
   514  			},
   515  				Metadata: "{}"}
   516  			mock.ExpectBegin()
   517  			mock.ExpectExec("UPDATE(.+)files(.+)SET(.+)").WithArgs("{}", "newName.txt", sqlmock.AnyArg(), 1).WillReturnResult(sqlmock.NewResult(1, 1))
   518  			mock.ExpectCommit()
   519  			err := file.Rename("newName.txt")
   520  			asserts.NoError(mock.ExpectationsWereMet())
   521  			asserts.NoError(err)
   522  			asserts.Equal(ThumbStatusNotAvailable, file.MetadataSerialized[ThumbStatusMetadataKey])
   523  		}
   524  
   525  		// thumb not available, rename base name only
   526  		{
   527  			file := File{Model: gorm.Model{ID: 1}, Name: "1.txt", MetadataSerialized: map[string]string{
   528  				ThumbStatusMetadataKey: ThumbStatusNotAvailable,
   529  			}}
   530  			mock.ExpectBegin()
   531  			mock.ExpectExec("UPDATE(.+)files(.+)SET(.+)").WithArgs("{}", "newName.jpg", sqlmock.AnyArg(), 1).WillReturnResult(sqlmock.NewResult(1, 1))
   532  			mock.ExpectCommit()
   533  			err := file.Rename("newName.jpg")
   534  			asserts.NoError(mock.ExpectationsWereMet())
   535  			asserts.NoError(err)
   536  			asserts.Empty(file.MetadataSerialized[ThumbStatusMetadataKey])
   537  		}
   538  	}
   539  
   540  	// UpdatePicInfo
   541  	{
   542  		mock.ExpectBegin()
   543  		mock.ExpectExec("UPDATE(.+)").WithArgs("1,1", 1).WillReturnResult(sqlmock.NewResult(1, 1))
   544  		mock.ExpectCommit()
   545  		err := file.UpdatePicInfo("1,1")
   546  		asserts.NoError(mock.ExpectationsWereMet())
   547  		asserts.NoError(err)
   548  	}
   549  
   550  	// UpdateSourceName
   551  	{
   552  		mock.ExpectBegin()
   553  		mock.ExpectExec("UPDATE(.+)").WithArgs("", "newName", sqlmock.AnyArg(), 1).WillReturnResult(sqlmock.NewResult(1, 1))
   554  		mock.ExpectCommit()
   555  		err := file.UpdateSourceName("newName")
   556  		asserts.NoError(mock.ExpectationsWereMet())
   557  		asserts.NoError(err)
   558  	}
   559  }
   560  
   561  func TestFile_UpdateSize(t *testing.T) {
   562  	a := assert.New(t)
   563  
   564  	// 增加成功
   565  	{
   566  		file := File{Size: 10}
   567  		mock.ExpectBegin()
   568  		mock.ExpectExec("UPDATE(.+)files(.+)").WithArgs("", 11, sqlmock.AnyArg(), 10).WillReturnResult(sqlmock.NewResult(1, 1))
   569  		mock.ExpectExec("UPDATE(.+)storage(.+)+(.+)").WithArgs(uint64(1), sqlmock.AnyArg()).WillReturnResult(sqlmock.NewResult(1, 1))
   570  		mock.ExpectCommit()
   571  
   572  		a.NoError(file.UpdateSize(11))
   573  		a.NoError(mock.ExpectationsWereMet())
   574  	}
   575  
   576  	// 减少成功
   577  	{
   578  		file := File{Size: 10}
   579  		mock.ExpectBegin()
   580  		mock.ExpectExec("UPDATE(.+)files(.+)").WithArgs("", 8, sqlmock.AnyArg(), 10).WillReturnResult(sqlmock.NewResult(1, 1))
   581  		mock.ExpectExec("UPDATE(.+)storage(.+)-(.+)").WithArgs(uint64(2), sqlmock.AnyArg()).WillReturnResult(sqlmock.NewResult(1, 1))
   582  		mock.ExpectCommit()
   583  
   584  		a.NoError(file.UpdateSize(8))
   585  		a.NoError(mock.ExpectationsWereMet())
   586  	}
   587  
   588  	// 文件更新失败
   589  	{
   590  		file := File{Size: 10}
   591  		mock.ExpectBegin()
   592  		mock.ExpectExec("UPDATE(.+)files(.+)").WithArgs("", 8, sqlmock.AnyArg(), 10).WillReturnError(errors.New("error"))
   593  		mock.ExpectRollback()
   594  
   595  		a.Error(file.UpdateSize(8))
   596  		a.NoError(mock.ExpectationsWereMet())
   597  	}
   598  
   599  	// 用户容量更新失败
   600  	{
   601  		file := File{Size: 10}
   602  		mock.ExpectBegin()
   603  		mock.ExpectExec("UPDATE(.+)files(.+)").WithArgs("", 8, sqlmock.AnyArg(), 10).WillReturnResult(sqlmock.NewResult(1, 1))
   604  		mock.ExpectExec("UPDATE(.+)storage(.+)-(.+)").WithArgs(uint64(2), sqlmock.AnyArg()).WillReturnError(errors.New("error"))
   605  		mock.ExpectRollback()
   606  
   607  		a.Error(file.UpdateSize(8))
   608  		a.NoError(mock.ExpectationsWereMet())
   609  	}
   610  }
   611  
   612  func TestFile_PopChunkToFile(t *testing.T) {
   613  	a := assert.New(t)
   614  	timeNow := time.Now()
   615  	file := File{}
   616  	mock.ExpectBegin()
   617  	mock.ExpectExec("UPDATE(.+)files(.+)").WillReturnResult(sqlmock.NewResult(1, 1))
   618  	mock.ExpectCommit()
   619  	a.NoError(file.PopChunkToFile(&timeNow, "1,1"))
   620  }
   621  
   622  func TestFile_CanCopy(t *testing.T) {
   623  	a := assert.New(t)
   624  	file := File{}
   625  	a.True(file.CanCopy())
   626  	file.UploadSessionID = &file.Name
   627  	a.False(file.CanCopy())
   628  }
   629  
   630  func TestFile_FileInfoInterface(t *testing.T) {
   631  	asserts := assert.New(t)
   632  	file := File{
   633  		Model: gorm.Model{
   634  			UpdatedAt: time.Date(2019, 12, 21, 12, 40, 0, 0, time.UTC),
   635  		},
   636  		Name:       "test_name",
   637  		SourceName: "",
   638  		UserID:     0,
   639  		Size:       10,
   640  		PicInfo:    "",
   641  		FolderID:   0,
   642  		PolicyID:   0,
   643  		Policy:     Policy{},
   644  		Position:   "/test",
   645  	}
   646  
   647  	name := file.GetName()
   648  	asserts.Equal("test_name", name)
   649  
   650  	size := file.GetSize()
   651  	asserts.Equal(uint64(10), size)
   652  
   653  	asserts.Equal(time.Date(2019, 12, 21, 12, 40, 0, 0, time.UTC), file.ModTime())
   654  	asserts.False(file.IsDir())
   655  	asserts.Equal("/test", file.GetPosition())
   656  }
   657  
   658  func TestGetFilesByKeywords(t *testing.T) {
   659  	asserts := assert.New(t)
   660  
   661  	// 未指定用户
   662  	{
   663  		mock.ExpectQuery("SELECT(.+)").WithArgs("k1", "k2").WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(1))
   664  		res, err := GetFilesByKeywords(0, nil, "k1", "k2")
   665  		asserts.NoError(mock.ExpectationsWereMet())
   666  		asserts.NoError(err)
   667  		asserts.Len(res, 1)
   668  	}
   669  
   670  	// 指定用户
   671  	{
   672  		mock.ExpectQuery("SELECT(.+)").WithArgs(1, "k1", "k2").WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(1))
   673  		res, err := GetFilesByKeywords(1, nil, "k1", "k2")
   674  		asserts.NoError(mock.ExpectationsWereMet())
   675  		asserts.NoError(err)
   676  		asserts.Len(res, 1)
   677  	}
   678  
   679  	// 指定父目录
   680  	{
   681  		mock.ExpectQuery("SELECT(.+)").WithArgs(1, 12, "k1", "k2").WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(1))
   682  		res, err := GetFilesByKeywords(1, []uint{12}, "k1", "k2")
   683  		asserts.NoError(mock.ExpectationsWereMet())
   684  		asserts.NoError(err)
   685  		asserts.Len(res, 1)
   686  	}
   687  }
   688  
   689  func TestFile_CreateOrGetSourceLink(t *testing.T) {
   690  	a := assert.New(t)
   691  	file := &File{}
   692  	file.ID = 1
   693  
   694  	// 已存在,返回老的 SourceLink
   695  	{
   696  		mock.ExpectQuery("SELECT(.+)source_links(.+)").WithArgs(1).WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(2))
   697  		res, err := file.CreateOrGetSourceLink()
   698  		a.NoError(err)
   699  		a.EqualValues(2, res.ID)
   700  		a.NoError(mock.ExpectationsWereMet())
   701  	}
   702  
   703  	// 不存在,插入失败
   704  	{
   705  		expectedErr := errors.New("error")
   706  		mock.ExpectQuery("SELECT(.+)source_links(.+)").WithArgs(1).WillReturnRows(sqlmock.NewRows([]string{"id"}))
   707  		mock.ExpectBegin()
   708  		mock.ExpectExec("INSERT(.+)source_links(.+)").WillReturnError(expectedErr)
   709  		mock.ExpectRollback()
   710  		res, err := file.CreateOrGetSourceLink()
   711  		a.Nil(res)
   712  		a.ErrorIs(err, expectedErr)
   713  		a.NoError(mock.ExpectationsWereMet())
   714  	}
   715  
   716  	// 成功
   717  	{
   718  		mock.ExpectQuery("SELECT(.+)source_links(.+)").WithArgs(1).WillReturnRows(sqlmock.NewRows([]string{"id"}))
   719  		mock.ExpectBegin()
   720  		mock.ExpectExec("INSERT(.+)source_links(.+)").WillReturnResult(sqlmock.NewResult(2, 1))
   721  		mock.ExpectCommit()
   722  		res, err := file.CreateOrGetSourceLink()
   723  		a.NoError(err)
   724  		a.EqualValues(2, res.ID)
   725  		a.EqualValues(file.ID, res.File.ID)
   726  		a.NoError(mock.ExpectationsWereMet())
   727  	}
   728  }
   729  
   730  func TestFile_UpdateMetadata(t *testing.T) {
   731  	a := assert.New(t)
   732  	file := &File{}
   733  	file.ID = 1
   734  
   735  	// 更新失败
   736  	{
   737  		expectedErr := errors.New("error")
   738  		mock.ExpectBegin()
   739  		mock.ExpectExec("UPDATE(.+)files(.+)").WithArgs(sqlmock.AnyArg(), 1).WillReturnError(expectedErr)
   740  		mock.ExpectRollback()
   741  		a.ErrorIs(file.UpdateMetadata(map[string]string{"1": "1"}), expectedErr)
   742  		a.NoError(mock.ExpectationsWereMet())
   743  	}
   744  
   745  	// 成功
   746  	{
   747  		mock.ExpectBegin()
   748  		mock.ExpectExec("UPDATE(.+)files(.+)").WithArgs(sqlmock.AnyArg(), 1).WillReturnResult(sqlmock.NewResult(1, 1))
   749  		mock.ExpectCommit()
   750  		a.NoError(file.UpdateMetadata(map[string]string{"1": "1"}))
   751  		a.NoError(mock.ExpectationsWereMet())
   752  		a.Equal("1", file.MetadataSerialized["1"])
   753  	}
   754  }
   755  
   756  func TestFile_ShouldLoadThumb(t *testing.T) {
   757  	a := assert.New(t)
   758  	file := &File{
   759  		MetadataSerialized: map[string]string{},
   760  	}
   761  	file.ID = 1
   762  
   763  	// 无缩略图
   764  	{
   765  		file.MetadataSerialized[ThumbStatusMetadataKey] = ThumbStatusNotAvailable
   766  		a.False(file.ShouldLoadThumb())
   767  	}
   768  
   769  	// 有缩略图
   770  	{
   771  		file.MetadataSerialized[ThumbStatusMetadataKey] = ThumbStatusExist
   772  		a.True(file.ShouldLoadThumb())
   773  	}
   774  }
   775  
   776  func TestFile_ThumbFile(t *testing.T) {
   777  	a := assert.New(t)
   778  	file := &File{
   779  		SourceName:         "test",
   780  		MetadataSerialized: map[string]string{},
   781  	}
   782  	file.ID = 1
   783  
   784  	a.Equal("test._thumb", file.ThumbFile())
   785  }