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

     1  package filesystem
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"errors"
     7  	"github.com/cloudreve/Cloudreve/v3/pkg/util"
     8  	testMock "github.com/stretchr/testify/mock"
     9  	"io"
    10  	"os"
    11  	"path/filepath"
    12  	"runtime"
    13  	"strings"
    14  	"testing"
    15  
    16  	"github.com/DATA-DOG/go-sqlmock"
    17  	model "github.com/cloudreve/Cloudreve/v3/models"
    18  	"github.com/cloudreve/Cloudreve/v3/pkg/cache"
    19  	"github.com/cloudreve/Cloudreve/v3/pkg/filesystem/fsctx"
    20  	"github.com/jinzhu/gorm"
    21  	"github.com/stretchr/testify/assert"
    22  )
    23  
    24  func TestFileSystem_Compress(t *testing.T) {
    25  	asserts := assert.New(t)
    26  	ctx := context.Background()
    27  	fs := FileSystem{
    28  		User: &model.User{Model: gorm.Model{ID: 1}},
    29  	}
    30  
    31  	// 成功
    32  	{
    33  		// 查找压缩父目录
    34  		mock.ExpectQuery("SELECT(.+)folders(.+)").
    35  			WithArgs(1, 1).
    36  			WillReturnRows(sqlmock.NewRows([]string{"id", "name"}).AddRow(1, "parent"))
    37  		// 查找顶级待压缩文件
    38  		mock.ExpectQuery("SELECT(.+)files(.+)").
    39  			WithArgs(1, 1).
    40  			WillReturnRows(
    41  				sqlmock.NewRows(
    42  					[]string{"id", "name", "source_name", "policy_id"}).
    43  					AddRow(1, "1.txt", "tests/file1.txt", 1),
    44  			)
    45  		asserts.NoError(cache.Set("setting_temp_path", "tests", -1))
    46  		// 查找父目录子文件
    47  		mock.ExpectQuery("SELECT(.+)files(.+)").
    48  			WithArgs(1).
    49  			WillReturnRows(sqlmock.NewRows([]string{"id", "name", "source_name", "policy_id"}))
    50  		// 查找子目录
    51  		mock.ExpectQuery("SELECT(.+)folders(.+)").
    52  			WithArgs(1).
    53  			WillReturnRows(sqlmock.NewRows([]string{"id", "name"}).AddRow(2, "sub"))
    54  		// 查找子目录子文件
    55  		mock.ExpectQuery("SELECT(.+)files(.+)").
    56  			WithArgs(2).
    57  			WillReturnRows(
    58  				sqlmock.NewRows([]string{"id", "name", "source_name", "policy_id"}).
    59  					AddRow(2, "2.txt", "tests/file2.txt", 1),
    60  			)
    61  		// 查找上传策略
    62  		asserts.NoError(cache.Set("policy_1", model.Policy{Type: "local"}, -1))
    63  		w := &bytes.Buffer{}
    64  
    65  		err := fs.Compress(ctx, w, []uint{1}, []uint{1}, true)
    66  		asserts.NoError(err)
    67  		asserts.NotEmpty(w.Len())
    68  	}
    69  
    70  	// 上下文取消
    71  	{
    72  		ctx, cancel := context.WithCancel(context.Background())
    73  		cancel()
    74  		// 查找压缩父目录
    75  		mock.ExpectQuery("SELECT(.+)folders(.+)").
    76  			WithArgs(1, 1).
    77  			WillReturnRows(sqlmock.NewRows([]string{"id", "name"}).AddRow(1, "parent"))
    78  		// 查找顶级待压缩文件
    79  		mock.ExpectQuery("SELECT(.+)files(.+)").
    80  			WithArgs(1, 1).
    81  			WillReturnRows(
    82  				sqlmock.NewRows(
    83  					[]string{"id", "name", "source_name", "policy_id"}).
    84  					AddRow(1, "1.txt", "tests/file1.txt", 1),
    85  			)
    86  		asserts.NoError(cache.Set("setting_temp_path", "tests", -1))
    87  
    88  		w := &bytes.Buffer{}
    89  		err := fs.Compress(ctx, w, []uint{1}, []uint{1}, true)
    90  		asserts.Error(err)
    91  		asserts.NotEmpty(w.Len())
    92  	}
    93  
    94  	// 限制父目录
    95  	{
    96  		ctx := context.WithValue(context.Background(), fsctx.LimitParentCtx, &model.Folder{
    97  			Model: gorm.Model{ID: 3},
    98  		})
    99  		// 查找压缩父目录
   100  		mock.ExpectQuery("SELECT(.+)folders(.+)").
   101  			WithArgs(1, 1).
   102  			WillReturnRows(sqlmock.NewRows([]string{"id", "name", "parent_id"}).AddRow(1, "parent", 3))
   103  		// 查找顶级待压缩文件
   104  		mock.ExpectQuery("SELECT(.+)files(.+)").
   105  			WithArgs(1, 1).
   106  			WillReturnRows(
   107  				sqlmock.NewRows(
   108  					[]string{"id", "name", "source_name", "policy_id"}).
   109  					AddRow(1, "1.txt", "tests/file1.txt", 1),
   110  			)
   111  		asserts.NoError(cache.Set("setting_temp_path", "tests", -1))
   112  
   113  		w := &bytes.Buffer{}
   114  		err := fs.Compress(ctx, w, []uint{1}, []uint{1}, true)
   115  		asserts.Error(err)
   116  		asserts.Equal(ErrObjectNotExist, err)
   117  		asserts.Empty(w.Len())
   118  	}
   119  
   120  }
   121  
   122  type MockNopRSC string
   123  
   124  func (m MockNopRSC) Read(b []byte) (int, error) {
   125  	return 0, errors.New("read error")
   126  }
   127  
   128  func (m MockNopRSC) Seek(n int64, offset int) (int64, error) {
   129  	return 0, errors.New("read error")
   130  }
   131  
   132  func (m MockNopRSC) Close() error {
   133  	return errors.New("read error")
   134  }
   135  
   136  type MockRSC struct {
   137  	rs io.ReadSeeker
   138  }
   139  
   140  func (m MockRSC) Read(b []byte) (int, error) {
   141  	return m.rs.Read(b)
   142  }
   143  
   144  func (m MockRSC) Seek(n int64, offset int) (int64, error) {
   145  	return m.rs.Seek(n, offset)
   146  }
   147  
   148  func (m MockRSC) Close() error {
   149  	return nil
   150  }
   151  
   152  var basepath string
   153  
   154  func init() {
   155  	_, currentFile, _, _ := runtime.Caller(0)
   156  	basepath = filepath.Dir(currentFile)
   157  }
   158  
   159  func Path(rel string) string {
   160  	return filepath.Join(basepath, rel)
   161  }
   162  
   163  func TestFileSystem_Decompress(t *testing.T) {
   164  	asserts := assert.New(t)
   165  	ctx := context.Background()
   166  	fs := FileSystem{
   167  		User: &model.User{Model: gorm.Model{ID: 1}},
   168  	}
   169  	os.RemoveAll(util.RelativePath("tests/decompress"))
   170  
   171  	// 压缩文件不存在
   172  	{
   173  		// 查找根目录
   174  		mock.ExpectQuery("SELECT(.+)folders(.+)").
   175  			WillReturnRows(sqlmock.NewRows([]string{"id", "name"}).AddRow(1, "/"))
   176  		// 查找压缩文件,未找到
   177  		mock.ExpectQuery("SELECT(.+)files(.+)").
   178  			WillReturnRows(sqlmock.NewRows([]string{"id", "name"}))
   179  		err := fs.Decompress(ctx, "/1.zip", "/", "")
   180  		asserts.NoError(mock.ExpectationsWereMet())
   181  		asserts.Error(err)
   182  	}
   183  
   184  	// 无法下载压缩文件
   185  	{
   186  		fs.FileTarget = []model.File{{SourceName: "1.zip", Policy: model.Policy{Type: "mock"}}}
   187  		fs.FileTarget[0].Policy.ID = 1
   188  		testHandler := new(FileHeaderMock)
   189  		testHandler.On("Get", testMock.Anything, "1.zip").Return(MockRSC{}, errors.New("error"))
   190  		fs.Handler = testHandler
   191  		err := fs.Decompress(ctx, "/1.zip", "/", "")
   192  		asserts.NoError(mock.ExpectationsWereMet())
   193  		asserts.Error(err)
   194  		asserts.EqualError(err, "error")
   195  	}
   196  
   197  	// 无法创建临时压缩文件
   198  	{
   199  		cache.Set("setting_temp_path", "/tests:", 0)
   200  		fs.FileTarget = []model.File{{SourceName: "1.zip", Policy: model.Policy{Type: "mock"}}}
   201  		fs.FileTarget[0].Policy.ID = 1
   202  		testHandler := new(FileHeaderMock)
   203  		testHandler.On("Get", testMock.Anything, "1.zip").Return(MockRSC{}, nil)
   204  		fs.Handler = testHandler
   205  		err := fs.Decompress(ctx, "/1.zip", "/", "")
   206  		asserts.NoError(mock.ExpectationsWereMet())
   207  		asserts.Error(err)
   208  	}
   209  
   210  	// 无法写入压缩文件
   211  	{
   212  		cache.Set("setting_temp_path", "tests", 0)
   213  		fs.FileTarget = []model.File{{SourceName: "1.zip", Policy: model.Policy{Type: "mock"}}}
   214  		fs.FileTarget[0].Policy.ID = 1
   215  		testHandler := new(FileHeaderMock)
   216  		testHandler.On("Get", testMock.Anything, "1.zip").Return(MockNopRSC("1"), nil)
   217  		fs.Handler = testHandler
   218  		err := fs.Decompress(ctx, "/1.zip", "/", "")
   219  		asserts.NoError(mock.ExpectationsWereMet())
   220  		asserts.Error(err)
   221  		asserts.Contains(err.Error(), "read error")
   222  	}
   223  
   224  	// 无法重设上传策略
   225  	{
   226  		cache.Set("setting_temp_path", "tests", 0)
   227  		fs.FileTarget = []model.File{{SourceName: "1.zip", Policy: model.Policy{Type: "mock"}}}
   228  		fs.FileTarget[0].Policy.ID = 1
   229  		testHandler := new(FileHeaderMock)
   230  		testHandler.On("Get", testMock.Anything, "1.zip").Return(MockRSC{rs: strings.NewReader("read")}, nil)
   231  		fs.Handler = testHandler
   232  		err := fs.Decompress(ctx, "/1.zip", "/", "")
   233  		asserts.NoError(mock.ExpectationsWereMet())
   234  		asserts.Error(err)
   235  		asserts.True(util.IsEmpty(util.RelativePath("tests/decompress")))
   236  	}
   237  
   238  	// 无法上传,容量不足
   239  	{
   240  		cache.Set("setting_max_parallel_transfer", "1", 0)
   241  		zipFile, _ := os.Open(Path("tests/test.zip"))
   242  		fs.FileTarget = []model.File{{SourceName: "1.zip", Policy: model.Policy{Type: "mock"}}}
   243  		fs.FileTarget[0].Policy.ID = 1
   244  		fs.User.Policy.Type = "mock"
   245  		testHandler := new(FileHeaderMock)
   246  		testHandler.On("Get", testMock.Anything, "1.zip").Return(zipFile, nil)
   247  		fs.Handler = testHandler
   248  
   249  		fs.Decompress(ctx, "/1.zip", "/", "")
   250  
   251  		zipFile.Close()
   252  
   253  		asserts.NoError(mock.ExpectationsWereMet())
   254  		testHandler.AssertExpectations(t)
   255  	}
   256  }