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

     1  package remote
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"github.com/cloudreve/Cloudreve/v3/pkg/filesystem/driver"
     7  	"github.com/cloudreve/Cloudreve/v3/pkg/mocks/remoteclientmock"
     8  	"github.com/cloudreve/Cloudreve/v3/pkg/serializer"
     9  	"io"
    10  	"io/ioutil"
    11  	"net/http"
    12  	"strings"
    13  	"testing"
    14  
    15  	model "github.com/cloudreve/Cloudreve/v3/models"
    16  	"github.com/cloudreve/Cloudreve/v3/pkg/auth"
    17  	"github.com/cloudreve/Cloudreve/v3/pkg/cache"
    18  	"github.com/cloudreve/Cloudreve/v3/pkg/filesystem/fsctx"
    19  	"github.com/cloudreve/Cloudreve/v3/pkg/request"
    20  	"github.com/stretchr/testify/assert"
    21  	testMock "github.com/stretchr/testify/mock"
    22  )
    23  
    24  func TestNewDriver(t *testing.T) {
    25  	a := assert.New(t)
    26  
    27  	// remoteClient 初始化失败
    28  	{
    29  		d, err := NewDriver(&model.Policy{Server: string([]byte{0x7f})})
    30  		a.Error(err)
    31  		a.Nil(d)
    32  	}
    33  
    34  	// 成功
    35  	{
    36  		d, err := NewDriver(&model.Policy{})
    37  		a.NoError(err)
    38  		a.NotNil(d)
    39  	}
    40  }
    41  
    42  func TestHandler_Source(t *testing.T) {
    43  	asserts := assert.New(t)
    44  	auth.General = auth.HMACAuth{SecretKey: []byte("test")}
    45  
    46  	// 无法获取上下文
    47  	{
    48  		handler := Driver{
    49  			Policy:       &model.Policy{Server: "/"},
    50  			AuthInstance: auth.HMACAuth{},
    51  		}
    52  		ctx := context.Background()
    53  		res, err := handler.Source(ctx, "", 0, true, 0)
    54  		asserts.NoError(err)
    55  		asserts.NotEmpty(res)
    56  	}
    57  
    58  	// 成功
    59  	{
    60  		handler := Driver{
    61  			Policy:       &model.Policy{Server: "/"},
    62  			AuthInstance: auth.HMACAuth{},
    63  		}
    64  		file := model.File{
    65  			SourceName: "1.txt",
    66  		}
    67  		ctx := context.WithValue(context.Background(), fsctx.FileModelCtx, file)
    68  		res, err := handler.Source(ctx, "", 10, true, 0)
    69  		asserts.NoError(err)
    70  		asserts.Contains(res, "api/v3/slave/download/0")
    71  	}
    72  
    73  	// 成功 自定义CDN
    74  	{
    75  		handler := Driver{
    76  			Policy:       &model.Policy{Server: "/", BaseURL: "https://cqu.edu.cn"},
    77  			AuthInstance: auth.HMACAuth{},
    78  		}
    79  		file := model.File{
    80  			SourceName: "1.txt",
    81  		}
    82  		ctx := context.WithValue(context.Background(), fsctx.FileModelCtx, file)
    83  		res, err := handler.Source(ctx, "", 10, true, 0)
    84  		asserts.NoError(err)
    85  		asserts.Contains(res, "api/v3/slave/download/0")
    86  		asserts.Contains(res, "https://cqu.edu.cn")
    87  	}
    88  
    89  	// 解析失败 自定义CDN
    90  	{
    91  		handler := Driver{
    92  			Policy:       &model.Policy{Server: "/", BaseURL: string([]byte{0x7f})},
    93  			AuthInstance: auth.HMACAuth{},
    94  		}
    95  		file := model.File{
    96  			SourceName: "1.txt",
    97  		}
    98  		ctx := context.WithValue(context.Background(), fsctx.FileModelCtx, file)
    99  		res, err := handler.Source(ctx, "", 10, true, 0)
   100  		asserts.Error(err)
   101  		asserts.Empty(res)
   102  	}
   103  
   104  	// 成功 预览
   105  	{
   106  		handler := Driver{
   107  			Policy:       &model.Policy{Server: "/"},
   108  			AuthInstance: auth.HMACAuth{},
   109  		}
   110  		file := model.File{
   111  			SourceName: "1.txt",
   112  		}
   113  		ctx := context.WithValue(context.Background(), fsctx.FileModelCtx, file)
   114  		res, err := handler.Source(ctx, "", 10, false, 0)
   115  		asserts.NoError(err)
   116  		asserts.Contains(res, "api/v3/slave/source/0")
   117  	}
   118  }
   119  
   120  type ClientMock struct {
   121  	testMock.Mock
   122  }
   123  
   124  func (m ClientMock) Request(method, target string, body io.Reader, opts ...request.Option) *request.Response {
   125  	args := m.Called(method, target, body, opts)
   126  	return args.Get(0).(*request.Response)
   127  }
   128  
   129  func TestHandler_Delete(t *testing.T) {
   130  	asserts := assert.New(t)
   131  	handler := Driver{
   132  		Policy: &model.Policy{
   133  			SecretKey: "test",
   134  			Server:    "http://test.com",
   135  		},
   136  		AuthInstance: auth.HMACAuth{},
   137  	}
   138  	ctx := context.Background()
   139  	cache.Set("setting_slave_api_timeout", "60", 0)
   140  
   141  	// 成功
   142  	{
   143  		clientMock := ClientMock{}
   144  		clientMock.On(
   145  			"Request",
   146  			"POST",
   147  			"http://test.com/api/v3/slave/delete",
   148  			testMock.Anything,
   149  			testMock.Anything,
   150  		).Return(&request.Response{
   151  			Err: nil,
   152  			Response: &http.Response{
   153  				StatusCode: 200,
   154  				Body:       ioutil.NopCloser(strings.NewReader(`{"code":0}`)),
   155  			},
   156  		})
   157  		handler.Client = clientMock
   158  		failed, err := handler.Delete(ctx, []string{"/test1.txt", "test2.txt"})
   159  		clientMock.AssertExpectations(t)
   160  		asserts.NoError(err)
   161  		asserts.Len(failed, 0)
   162  
   163  	}
   164  
   165  	// 结果解析失败
   166  	{
   167  		clientMock := ClientMock{}
   168  		clientMock.On(
   169  			"Request",
   170  			"POST",
   171  			"http://test.com/api/v3/slave/delete",
   172  			testMock.Anything,
   173  			testMock.Anything,
   174  		).Return(&request.Response{
   175  			Err: nil,
   176  			Response: &http.Response{
   177  				StatusCode: 200,
   178  				Body:       ioutil.NopCloser(strings.NewReader(`{"code":203}`)),
   179  			},
   180  		})
   181  		handler.Client = clientMock
   182  		failed, err := handler.Delete(ctx, []string{"/test1.txt", "test2.txt"})
   183  		clientMock.AssertExpectations(t)
   184  		asserts.Error(err)
   185  		asserts.Len(failed, 2)
   186  	}
   187  
   188  	// 一个失败
   189  	{
   190  		clientMock := ClientMock{}
   191  		clientMock.On(
   192  			"Request",
   193  			"POST",
   194  			"http://test.com/api/v3/slave/delete",
   195  			testMock.Anything,
   196  			testMock.Anything,
   197  		).Return(&request.Response{
   198  			Err: nil,
   199  			Response: &http.Response{
   200  				StatusCode: 200,
   201  				Body:       ioutil.NopCloser(strings.NewReader(`{"code":203,"data":"{\"files\":[\"1\"]}"}`)),
   202  			},
   203  		})
   204  		handler.Client = clientMock
   205  		failed, err := handler.Delete(ctx, []string{"/test1.txt", "test2.txt"})
   206  		clientMock.AssertExpectations(t)
   207  		asserts.Error(err)
   208  		asserts.Len(failed, 1)
   209  	}
   210  }
   211  
   212  func TestDriver_List(t *testing.T) {
   213  	asserts := assert.New(t)
   214  	handler := Driver{
   215  		Policy: &model.Policy{
   216  			SecretKey: "test",
   217  			Server:    "http://test.com",
   218  		},
   219  		AuthInstance: auth.HMACAuth{},
   220  	}
   221  	ctx := context.Background()
   222  	cache.Set("setting_slave_api_timeout", "60", 0)
   223  
   224  	// 成功
   225  	{
   226  		clientMock := ClientMock{}
   227  		clientMock.On(
   228  			"Request",
   229  			"POST",
   230  			"http://test.com/api/v3/slave/list",
   231  			testMock.Anything,
   232  			testMock.Anything,
   233  		).Return(&request.Response{
   234  			Err: nil,
   235  			Response: &http.Response{
   236  				StatusCode: 200,
   237  				Body:       ioutil.NopCloser(strings.NewReader(`{"code":0,"data":"[{}]"}`)),
   238  			},
   239  		})
   240  		handler.Client = clientMock
   241  		res, err := handler.List(ctx, "/", true)
   242  		clientMock.AssertExpectations(t)
   243  		asserts.NoError(err)
   244  		asserts.Len(res, 1)
   245  
   246  	}
   247  
   248  	// 响应解析失败
   249  	{
   250  		clientMock := ClientMock{}
   251  		clientMock.On(
   252  			"Request",
   253  			"POST",
   254  			"http://test.com/api/v3/slave/list",
   255  			testMock.Anything,
   256  			testMock.Anything,
   257  		).Return(&request.Response{
   258  			Err: nil,
   259  			Response: &http.Response{
   260  				StatusCode: 200,
   261  				Body:       ioutil.NopCloser(strings.NewReader(`{"code":0,"data":"233"}`)),
   262  			},
   263  		})
   264  		handler.Client = clientMock
   265  		res, err := handler.List(ctx, "/", true)
   266  		clientMock.AssertExpectations(t)
   267  		asserts.Error(err)
   268  		asserts.Len(res, 0)
   269  	}
   270  
   271  	// 从机返回错误
   272  	{
   273  		clientMock := ClientMock{}
   274  		clientMock.On(
   275  			"Request",
   276  			"POST",
   277  			"http://test.com/api/v3/slave/list",
   278  			testMock.Anything,
   279  			testMock.Anything,
   280  		).Return(&request.Response{
   281  			Err: nil,
   282  			Response: &http.Response{
   283  				StatusCode: 200,
   284  				Body:       ioutil.NopCloser(strings.NewReader(`{"code":203}`)),
   285  			},
   286  		})
   287  		handler.Client = clientMock
   288  		res, err := handler.List(ctx, "/", true)
   289  		clientMock.AssertExpectations(t)
   290  		asserts.Error(err)
   291  		asserts.Len(res, 0)
   292  	}
   293  }
   294  
   295  func TestHandler_Get(t *testing.T) {
   296  	asserts := assert.New(t)
   297  	handler := Driver{
   298  		Policy: &model.Policy{
   299  			SecretKey: "test",
   300  			Server:    "http://test.com",
   301  		},
   302  		AuthInstance: auth.HMACAuth{},
   303  	}
   304  	ctx := context.Background()
   305  
   306  	// 成功
   307  	{
   308  		ctx = context.WithValue(ctx, fsctx.UserCtx, model.User{})
   309  		clientMock := ClientMock{}
   310  		clientMock.On(
   311  			"Request",
   312  			"GET",
   313  			testMock.Anything,
   314  			nil,
   315  			testMock.Anything,
   316  		).Return(&request.Response{
   317  			Err: nil,
   318  			Response: &http.Response{
   319  				StatusCode: 200,
   320  				Body:       ioutil.NopCloser(strings.NewReader(`{"code":0}`)),
   321  			},
   322  		})
   323  		handler.Client = clientMock
   324  		resp, err := handler.Get(ctx, "/test.txt")
   325  		clientMock.AssertExpectations(t)
   326  		asserts.NotNil(resp)
   327  		asserts.NoError(err)
   328  	}
   329  
   330  	// 请求失败
   331  	{
   332  		ctx = context.WithValue(ctx, fsctx.UserCtx, model.User{})
   333  		clientMock := ClientMock{}
   334  		clientMock.On(
   335  			"Request",
   336  			"GET",
   337  			testMock.Anything,
   338  			nil,
   339  			testMock.Anything,
   340  		).Return(&request.Response{
   341  			Err: nil,
   342  			Response: &http.Response{
   343  				StatusCode: 404,
   344  				Body:       ioutil.NopCloser(strings.NewReader(`{"code":0}`)),
   345  			},
   346  		})
   347  		handler.Client = clientMock
   348  		resp, err := handler.Get(ctx, "/test.txt")
   349  		clientMock.AssertExpectations(t)
   350  		asserts.Nil(resp)
   351  		asserts.Error(err)
   352  	}
   353  }
   354  
   355  func TestHandler_Put(t *testing.T) {
   356  	a := assert.New(t)
   357  	handler, _ := NewDriver(&model.Policy{
   358  		Type:      "remote",
   359  		SecretKey: "test",
   360  		Server:    "http://test.com",
   361  	})
   362  	clientMock := &remoteclientmock.RemoteClientMock{}
   363  	handler.uploadClient = clientMock
   364  	clientMock.On("Upload", testMock.Anything, testMock.Anything).Return(errors.New("error"))
   365  	a.Error(handler.Put(context.Background(), &fsctx.FileStream{}))
   366  	clientMock.AssertExpectations(t)
   367  }
   368  
   369  func TestHandler_Thumb(t *testing.T) {
   370  	asserts := assert.New(t)
   371  	handler := Driver{
   372  		Policy: &model.Policy{
   373  			Type:      "remote",
   374  			SecretKey: "test",
   375  			Server:    "http://test.com",
   376  			OptionsSerialized: model.PolicyOption{
   377  				ThumbExts: []string{"txt"},
   378  			},
   379  		},
   380  		AuthInstance: auth.HMACAuth{},
   381  	}
   382  	file := &model.File{
   383  		Name:       "1.txt",
   384  		SourceName: "1.txt",
   385  	}
   386  	ctx := context.Background()
   387  	asserts.NoError(cache.Set("setting_preview_timeout", "60", 0))
   388  
   389  	// no error
   390  	{
   391  		resp, err := handler.Thumb(ctx, file)
   392  		asserts.NoError(err)
   393  		asserts.True(resp.Redirect)
   394  	}
   395  
   396  	// ext not support
   397  	{
   398  		file.Name = "1.jpg"
   399  		resp, err := handler.Thumb(ctx, file)
   400  		asserts.ErrorIs(err, driver.ErrorThumbNotSupported)
   401  		asserts.Nil(resp)
   402  	}
   403  }
   404  
   405  func TestHandler_Token(t *testing.T) {
   406  	a := assert.New(t)
   407  	handler, _ := NewDriver(&model.Policy{})
   408  
   409  	// 无法创建上传会话
   410  	{
   411  		clientMock := &remoteclientmock.RemoteClientMock{}
   412  		handler.uploadClient = clientMock
   413  		clientMock.On("CreateUploadSession", testMock.Anything, testMock.Anything, int64(10), false).Return(errors.New("error"))
   414  		res, err := handler.Token(context.Background(), 10, &serializer.UploadSession{}, &fsctx.FileStream{})
   415  		a.Error(err)
   416  		a.Contains(err.Error(), "error")
   417  		a.Nil(res)
   418  		clientMock.AssertExpectations(t)
   419  	}
   420  
   421  	// 无法创建上传地址
   422  	{
   423  		clientMock := &remoteclientmock.RemoteClientMock{}
   424  		handler.uploadClient = clientMock
   425  		clientMock.On("CreateUploadSession", testMock.Anything, testMock.Anything, int64(10), false).Return(nil)
   426  		clientMock.On("GetUploadURL", int64(10), "").Return("", "", errors.New("error"))
   427  		res, err := handler.Token(context.Background(), 10, &serializer.UploadSession{}, &fsctx.FileStream{})
   428  		a.Error(err)
   429  		a.Contains(err.Error(), "error")
   430  		a.Nil(res)
   431  		clientMock.AssertExpectations(t)
   432  	}
   433  
   434  	// 成功
   435  	{
   436  		clientMock := &remoteclientmock.RemoteClientMock{}
   437  		handler.uploadClient = clientMock
   438  		clientMock.On("CreateUploadSession", testMock.Anything, testMock.Anything, int64(10), false).Return(nil)
   439  		clientMock.On("GetUploadURL", int64(10), "").Return("1", "2", nil)
   440  		res, err := handler.Token(context.Background(), 10, &serializer.UploadSession{}, &fsctx.FileStream{})
   441  		a.NoError(err)
   442  		a.NotNil(res)
   443  		a.Equal("1", res.UploadURLs[0])
   444  		a.Equal("2", res.Credential)
   445  		clientMock.AssertExpectations(t)
   446  	}
   447  }
   448  
   449  func TestDriver_CancelToken(t *testing.T) {
   450  	a := assert.New(t)
   451  	handler, _ := NewDriver(&model.Policy{})
   452  
   453  	clientMock := &remoteclientmock.RemoteClientMock{}
   454  	handler.uploadClient = clientMock
   455  	clientMock.On("DeleteUploadSession", testMock.Anything, "key").Return(errors.New("error"))
   456  	err := handler.CancelToken(context.Background(), &serializer.UploadSession{Key: "key"})
   457  	a.Error(err)
   458  	a.Contains(err.Error(), "error")
   459  	clientMock.AssertExpectations(t)
   460  }