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

     1  package onedrive
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"github.com/cloudreve/Cloudreve/v3/pkg/filesystem/chunk"
     8  	"github.com/cloudreve/Cloudreve/v3/pkg/filesystem/chunk/backoff"
     9  	"github.com/cloudreve/Cloudreve/v3/pkg/filesystem/fsctx"
    10  	"github.com/cloudreve/Cloudreve/v3/pkg/mq"
    11  	"io"
    12  	"io/ioutil"
    13  	"net/http"
    14  	"strings"
    15  	"testing"
    16  	"time"
    17  
    18  	model "github.com/cloudreve/Cloudreve/v3/models"
    19  	"github.com/cloudreve/Cloudreve/v3/pkg/cache"
    20  	"github.com/cloudreve/Cloudreve/v3/pkg/request"
    21  	"github.com/stretchr/testify/assert"
    22  	testMock "github.com/stretchr/testify/mock"
    23  )
    24  
    25  func TestRequest(t *testing.T) {
    26  	asserts := assert.New(t)
    27  	client := Client{
    28  		Policy:   &model.Policy{},
    29  		ClientID: "TestRequest",
    30  		Credential: &Credential{
    31  			ExpiresIn:    time.Now().Add(time.Duration(100) * time.Hour).Unix(),
    32  			AccessToken:  "AccessToken",
    33  			RefreshToken: "RefreshToken",
    34  		},
    35  	}
    36  
    37  	// 请求发送失败
    38  	{
    39  		clientMock := ClientMock{}
    40  		clientMock.On(
    41  			"Request",
    42  			"POST",
    43  			"http://dev.com",
    44  			testMock.Anything,
    45  			testMock.Anything,
    46  		).Return(&request.Response{
    47  			Err: errors.New("error"),
    48  		})
    49  		client.Request = clientMock
    50  		res, err := client.request(context.Background(), "POST", "http://dev.com", strings.NewReader(""))
    51  		clientMock.AssertExpectations(t)
    52  		asserts.Error(err)
    53  		asserts.Empty(res)
    54  		asserts.Equal("error", err.Error())
    55  	}
    56  
    57  	// 无法更新凭证
    58  	{
    59  		client.Credential.RefreshToken = ""
    60  		client.Credential.AccessToken = ""
    61  		res, err := client.request(context.Background(), "POST", "http://dev.com", strings.NewReader(""))
    62  		asserts.Error(err)
    63  		asserts.Empty(res)
    64  		client.Credential.RefreshToken = "RefreshToken"
    65  		client.Credential.AccessToken = "AccessToken"
    66  	}
    67  
    68  	// 无法获取响应正文
    69  	{
    70  		clientMock := ClientMock{}
    71  		clientMock.On(
    72  			"Request",
    73  			"POST",
    74  			"http://dev.com",
    75  			testMock.Anything,
    76  			testMock.Anything,
    77  		).Return(&request.Response{
    78  			Err: nil,
    79  			Response: &http.Response{
    80  				StatusCode: 200,
    81  				Body:       ioutil.NopCloser(mockReader("")),
    82  			},
    83  		})
    84  		client.Request = clientMock
    85  		res, err := client.request(context.Background(), "POST", "http://dev.com", strings.NewReader(""))
    86  		clientMock.AssertExpectations(t)
    87  		asserts.Error(err)
    88  		asserts.Empty(res)
    89  	}
    90  
    91  	// OneDrive返回错误
    92  	{
    93  		clientMock := ClientMock{}
    94  		clientMock.On(
    95  			"Request",
    96  			"POST",
    97  			"http://dev.com",
    98  			testMock.Anything,
    99  			testMock.Anything,
   100  		).Return(&request.Response{
   101  			Err: nil,
   102  			Response: &http.Response{
   103  				StatusCode: 400,
   104  				Body:       ioutil.NopCloser(strings.NewReader(`{"error":{"message":"error msg"}}`)),
   105  			},
   106  		})
   107  		client.Request = clientMock
   108  		res, err := client.request(context.Background(), "POST", "http://dev.com", strings.NewReader(""))
   109  		clientMock.AssertExpectations(t)
   110  		asserts.Error(err)
   111  		asserts.Empty(res)
   112  		asserts.Equal("error msg", err.Error())
   113  	}
   114  
   115  	// OneDrive返回429错误
   116  	{
   117  		header := http.Header{}
   118  		header.Add("retry-after", "120")
   119  		clientMock := ClientMock{}
   120  		clientMock.On(
   121  			"Request",
   122  			"POST",
   123  			"http://dev.com",
   124  			testMock.Anything,
   125  			testMock.Anything,
   126  		).Return(&request.Response{
   127  			Err: nil,
   128  			Response: &http.Response{
   129  				StatusCode: 429,
   130  				Header:     header,
   131  				Body:       ioutil.NopCloser(strings.NewReader(`{"error":{"message":"error msg"}}`)),
   132  			},
   133  		})
   134  		client.Request = clientMock
   135  		res, err := client.request(context.Background(), "POST", "http://dev.com", strings.NewReader(""))
   136  		clientMock.AssertExpectations(t)
   137  		asserts.Error(err)
   138  		asserts.Empty(res)
   139  		var retryErr *backoff.RetryableError
   140  		asserts.ErrorAs(err, &retryErr)
   141  		asserts.EqualValues(time.Duration(120)*time.Second, retryErr.RetryAfter)
   142  	}
   143  
   144  	// OneDrive返回未知响应
   145  	{
   146  		clientMock := ClientMock{}
   147  		clientMock.On(
   148  			"Request",
   149  			"POST",
   150  			"http://dev.com",
   151  			testMock.Anything,
   152  			testMock.Anything,
   153  		).Return(&request.Response{
   154  			Err: nil,
   155  			Response: &http.Response{
   156  				StatusCode: 400,
   157  				Body:       ioutil.NopCloser(strings.NewReader(`???`)),
   158  			},
   159  		})
   160  		client.Request = clientMock
   161  		res, err := client.request(context.Background(), "POST", "http://dev.com", strings.NewReader(""))
   162  		clientMock.AssertExpectations(t)
   163  		asserts.Error(err)
   164  		asserts.Empty(res)
   165  	}
   166  }
   167  
   168  func TestFileInfo_GetSourcePath(t *testing.T) {
   169  	asserts := assert.New(t)
   170  
   171  	// 成功
   172  	{
   173  		fileInfo := FileInfo{
   174  			Name: "%e6%96%87%e4%bb%b6%e5%90%8d.jpg",
   175  			ParentReference: parentReference{
   176  				Path: "/drive/root:/123/32%201",
   177  			},
   178  		}
   179  		asserts.Equal("123/32 1/%e6%96%87%e4%bb%b6%e5%90%8d.jpg", fileInfo.GetSourcePath())
   180  	}
   181  
   182  	// 失败
   183  	{
   184  		fileInfo := FileInfo{
   185  			Name: "123.jpg",
   186  			ParentReference: parentReference{
   187  				Path: "/drive/root:/123/%e6%96%87%e4%bb%b6%e5%90%8g",
   188  			},
   189  		}
   190  		asserts.Equal("", fileInfo.GetSourcePath())
   191  	}
   192  }
   193  
   194  func TestClient_GetRequestURL(t *testing.T) {
   195  	asserts := assert.New(t)
   196  	client, _ := NewClient(&model.Policy{})
   197  
   198  	// 出错
   199  	{
   200  		client.Endpoints.EndpointURL = string([]byte{0x7f})
   201  		asserts.Equal("", client.getRequestURL("123"))
   202  	}
   203  
   204  	// 使用DriverResource
   205  	{
   206  		client.Endpoints.EndpointURL = "https://graph.microsoft.com/v1.0"
   207  		asserts.Equal("https://graph.microsoft.com/v1.0/me/drive/123", client.getRequestURL("123"))
   208  	}
   209  
   210  	// 不使用DriverResource
   211  	{
   212  		client.Endpoints.EndpointURL = "https://graph.microsoft.com/v1.0"
   213  		asserts.Equal("https://graph.microsoft.com/v1.0/123", client.getRequestURL("123", WithDriverResource(false)))
   214  	}
   215  }
   216  
   217  func TestClient_GetSiteIDByURL(t *testing.T) {
   218  	asserts := assert.New(t)
   219  	client, _ := NewClient(&model.Policy{})
   220  	client.Credential.AccessToken = "AccessToken"
   221  
   222  	// 请求失败
   223  	{
   224  		client.Credential.ExpiresIn = 0
   225  		res, err := client.GetSiteIDByURL(context.Background(), "https://cquedu.sharepoint.com")
   226  		asserts.Error(err)
   227  		asserts.Empty(res)
   228  
   229  	}
   230  
   231  	// 返回未知响应
   232  	{
   233  		client.Credential.ExpiresIn = time.Now().Add(time.Duration(100) * time.Hour).Unix()
   234  		clientMock := ClientMock{}
   235  		clientMock.On(
   236  			"Request",
   237  			"GET",
   238  			testMock.Anything,
   239  			testMock.Anything,
   240  			testMock.Anything,
   241  		).Return(&request.Response{
   242  			Err: nil,
   243  			Response: &http.Response{
   244  				StatusCode: 200,
   245  				Body:       ioutil.NopCloser(strings.NewReader(`???`)),
   246  			},
   247  		})
   248  		client.Request = clientMock
   249  		res, err := client.GetSiteIDByURL(context.Background(), "https://cquedu.sharepoint.com")
   250  		clientMock.AssertExpectations(t)
   251  		asserts.Error(err)
   252  		asserts.Empty(res)
   253  	}
   254  
   255  	// 返回正常
   256  	{
   257  		client.Credential.ExpiresIn = time.Now().Add(time.Duration(100) * time.Hour).Unix()
   258  		clientMock := ClientMock{}
   259  		clientMock.On(
   260  			"Request",
   261  			"GET",
   262  			testMock.Anything,
   263  			testMock.Anything,
   264  			testMock.Anything,
   265  		).Return(&request.Response{
   266  			Err: nil,
   267  			Response: &http.Response{
   268  				StatusCode: 200,
   269  				Body:       ioutil.NopCloser(strings.NewReader(`{"id":"123321"}`)),
   270  			},
   271  		})
   272  		client.Request = clientMock
   273  		res, err := client.GetSiteIDByURL(context.Background(), "https://cquedu.sharepoint.com")
   274  		clientMock.AssertExpectations(t)
   275  		asserts.NoError(err)
   276  		asserts.NotEmpty(res)
   277  		asserts.Equal("123321", res)
   278  	}
   279  }
   280  
   281  func TestClient_Meta(t *testing.T) {
   282  	asserts := assert.New(t)
   283  	client, _ := NewClient(&model.Policy{})
   284  	client.Credential.AccessToken = "AccessToken"
   285  
   286  	// 请求失败
   287  	{
   288  		client.Credential.ExpiresIn = 0
   289  		res, err := client.Meta(context.Background(), "", "123")
   290  		asserts.Error(err)
   291  		asserts.Nil(res)
   292  
   293  	}
   294  
   295  	// 返回未知响应
   296  	{
   297  		client.Credential.ExpiresIn = time.Now().Add(time.Duration(100) * time.Hour).Unix()
   298  		clientMock := ClientMock{}
   299  		clientMock.On(
   300  			"Request",
   301  			"GET",
   302  			testMock.Anything,
   303  			testMock.Anything,
   304  			testMock.Anything,
   305  		).Return(&request.Response{
   306  			Err: nil,
   307  			Response: &http.Response{
   308  				StatusCode: 200,
   309  				Body:       ioutil.NopCloser(strings.NewReader(`???`)),
   310  			},
   311  		})
   312  		client.Request = clientMock
   313  		res, err := client.Meta(context.Background(), "", "123")
   314  		clientMock.AssertExpectations(t)
   315  		asserts.Error(err)
   316  		asserts.Nil(res)
   317  	}
   318  
   319  	// 返回正常
   320  	{
   321  		client.Credential.ExpiresIn = time.Now().Add(time.Duration(100) * time.Hour).Unix()
   322  		clientMock := ClientMock{}
   323  		clientMock.On(
   324  			"Request",
   325  			"GET",
   326  			testMock.Anything,
   327  			testMock.Anything,
   328  			testMock.Anything,
   329  		).Return(&request.Response{
   330  			Err: nil,
   331  			Response: &http.Response{
   332  				StatusCode: 200,
   333  				Body:       ioutil.NopCloser(strings.NewReader(`{"name":"123321"}`)),
   334  			},
   335  		})
   336  		client.Request = clientMock
   337  		res, err := client.Meta(context.Background(), "", "123")
   338  		clientMock.AssertExpectations(t)
   339  		asserts.NoError(err)
   340  		asserts.NotNil(res)
   341  		asserts.Equal("123321", res.Name)
   342  	}
   343  
   344  	// 返回正常, 使用资源id
   345  	{
   346  		client.Credential.ExpiresIn = time.Now().Add(time.Duration(100) * time.Hour).Unix()
   347  		clientMock := ClientMock{}
   348  		clientMock.On(
   349  			"Request",
   350  			"GET",
   351  			testMock.Anything,
   352  			testMock.Anything,
   353  			testMock.Anything,
   354  		).Return(&request.Response{
   355  			Err: nil,
   356  			Response: &http.Response{
   357  				StatusCode: 200,
   358  				Body:       ioutil.NopCloser(strings.NewReader(`{"name":"123321"}`)),
   359  			},
   360  		})
   361  		client.Request = clientMock
   362  		res, err := client.Meta(context.Background(), "123321", "123")
   363  		clientMock.AssertExpectations(t)
   364  		asserts.NoError(err)
   365  		asserts.NotNil(res)
   366  		asserts.Equal("123321", res.Name)
   367  	}
   368  }
   369  
   370  func TestClient_CreateUploadSession(t *testing.T) {
   371  	asserts := assert.New(t)
   372  	client, _ := NewClient(&model.Policy{})
   373  	client.Credential.AccessToken = "AccessToken"
   374  
   375  	// 请求失败
   376  	{
   377  		client.Credential.ExpiresIn = 0
   378  		res, err := client.CreateUploadSession(context.Background(), "123.jpg")
   379  		asserts.Error(err)
   380  		asserts.Empty(res)
   381  
   382  	}
   383  
   384  	// 返回未知响应
   385  	{
   386  		client.Credential.ExpiresIn = time.Now().Add(time.Duration(100) * time.Hour).Unix()
   387  		clientMock := ClientMock{}
   388  		clientMock.On(
   389  			"Request",
   390  			"POST",
   391  			testMock.Anything,
   392  			testMock.Anything,
   393  			testMock.Anything,
   394  		).Return(&request.Response{
   395  			Err: nil,
   396  			Response: &http.Response{
   397  				StatusCode: 200,
   398  				Body:       ioutil.NopCloser(strings.NewReader(`???`)),
   399  			},
   400  		})
   401  		client.Request = clientMock
   402  		res, err := client.CreateUploadSession(context.Background(), "123.jpg")
   403  		clientMock.AssertExpectations(t)
   404  		asserts.Error(err)
   405  		asserts.Empty(res)
   406  	}
   407  
   408  	// 返回正常
   409  	{
   410  		client.Credential.ExpiresIn = time.Now().Add(time.Duration(100) * time.Hour).Unix()
   411  		clientMock := ClientMock{}
   412  		clientMock.On(
   413  			"Request",
   414  			"POST",
   415  			testMock.Anything,
   416  			testMock.Anything,
   417  			testMock.Anything,
   418  		).Return(&request.Response{
   419  			Err: nil,
   420  			Response: &http.Response{
   421  				StatusCode: 200,
   422  				Body:       ioutil.NopCloser(strings.NewReader(`{"uploadUrl":"123321"}`)),
   423  			},
   424  		})
   425  		client.Request = clientMock
   426  		res, err := client.CreateUploadSession(context.Background(), "123.jpg", WithConflictBehavior("fail"))
   427  		clientMock.AssertExpectations(t)
   428  		asserts.NoError(err)
   429  		asserts.NotNil(res)
   430  		asserts.Equal("123321", res)
   431  	}
   432  }
   433  
   434  func TestClient_GetUploadSessionStatus(t *testing.T) {
   435  	asserts := assert.New(t)
   436  	client, _ := NewClient(&model.Policy{})
   437  	client.Credential.AccessToken = "AccessToken"
   438  
   439  	// 请求失败
   440  	{
   441  		client.Credential.ExpiresIn = 0
   442  		res, err := client.GetUploadSessionStatus(context.Background(), "http://dev.com")
   443  		asserts.Error(err)
   444  		asserts.Empty(res)
   445  
   446  	}
   447  
   448  	// 返回未知响应
   449  	{
   450  		client.Credential.ExpiresIn = time.Now().Add(time.Duration(100) * time.Hour).Unix()
   451  		clientMock := ClientMock{}
   452  		clientMock.On(
   453  			"Request",
   454  			"GET",
   455  			"http://dev.com",
   456  			testMock.Anything,
   457  			testMock.Anything,
   458  		).Return(&request.Response{
   459  			Err: nil,
   460  			Response: &http.Response{
   461  				StatusCode: 200,
   462  				Body:       ioutil.NopCloser(strings.NewReader(`???`)),
   463  			},
   464  		})
   465  		client.Request = clientMock
   466  		res, err := client.GetUploadSessionStatus(context.Background(), "http://dev.com")
   467  		clientMock.AssertExpectations(t)
   468  		asserts.Error(err)
   469  		asserts.Nil(res)
   470  	}
   471  
   472  	// 返回正常
   473  	{
   474  		client.Credential.ExpiresIn = time.Now().Add(time.Duration(100) * time.Hour).Unix()
   475  		clientMock := ClientMock{}
   476  		clientMock.On(
   477  			"Request",
   478  			"GET",
   479  			"http://dev.com",
   480  			testMock.Anything,
   481  			testMock.Anything,
   482  		).Return(&request.Response{
   483  			Err: nil,
   484  			Response: &http.Response{
   485  				StatusCode: 200,
   486  				Body:       ioutil.NopCloser(strings.NewReader(`{"uploadUrl":"123321"}`)),
   487  			},
   488  		})
   489  		client.Request = clientMock
   490  		res, err := client.GetUploadSessionStatus(context.Background(), "http://dev.com")
   491  		clientMock.AssertExpectations(t)
   492  		asserts.NoError(err)
   493  		asserts.NotNil(res)
   494  		asserts.Equal("123321", res.UploadURL)
   495  	}
   496  }
   497  
   498  func TestClient_UploadChunk(t *testing.T) {
   499  	asserts := assert.New(t)
   500  	client, _ := NewClient(&model.Policy{})
   501  	client.Credential.AccessToken = "AccessToken"
   502  	client.Credential.ExpiresIn = time.Now().Add(time.Duration(100) * time.Hour).Unix()
   503  	cg := chunk.NewChunkGroup(&fsctx.FileStream{Size: 15}, 10, &backoff.ConstantBackoff{}, false)
   504  
   505  	// 非最后分片,正常
   506  	{
   507  		cg.Next()
   508  		client.Credential.ExpiresIn = time.Now().Add(time.Duration(100) * time.Hour).Unix()
   509  		clientMock := ClientMock{}
   510  		clientMock.On(
   511  			"Request",
   512  			"PUT",
   513  			"http://dev.com",
   514  			testMock.Anything,
   515  			testMock.Anything,
   516  			testMock.Anything,
   517  			testMock.Anything,
   518  			testMock.Anything,
   519  			testMock.Anything,
   520  		).Return(&request.Response{
   521  			Err: nil,
   522  			Response: &http.Response{
   523  				StatusCode: 200,
   524  				Body:       ioutil.NopCloser(strings.NewReader(`{"uploadUrl":"http://dev.com/2"}`)),
   525  			},
   526  		})
   527  		client.Request = clientMock
   528  		res, err := client.UploadChunk(context.Background(), "http://dev.com", strings.NewReader("1234567890"), cg)
   529  		clientMock.AssertExpectations(t)
   530  		asserts.NoError(err)
   531  		asserts.Equal("http://dev.com/2", res.UploadURL)
   532  	}
   533  
   534  	// 非最后分片,异常响应
   535  	{
   536  		client.Credential.ExpiresIn = time.Now().Add(time.Duration(100) * time.Hour).Unix()
   537  		clientMock := ClientMock{}
   538  		clientMock.On(
   539  			"Request",
   540  			"PUT",
   541  			"http://dev.com",
   542  			testMock.Anything,
   543  			testMock.Anything,
   544  		).Return(&request.Response{
   545  			Err: nil,
   546  			Response: &http.Response{
   547  				StatusCode: 200,
   548  				Body:       ioutil.NopCloser(strings.NewReader(`???`)),
   549  			},
   550  		})
   551  		client.Request = clientMock
   552  		res, err := client.UploadChunk(context.Background(), "http://dev.com", strings.NewReader("1234567890"), cg)
   553  		clientMock.AssertExpectations(t)
   554  		asserts.Error(err)
   555  		asserts.Nil(res)
   556  	}
   557  
   558  	// 最后分片,正常
   559  	{
   560  		cg.Next()
   561  		client.Credential.ExpiresIn = time.Now().Add(time.Duration(100) * time.Hour).Unix()
   562  		clientMock := ClientMock{}
   563  		clientMock.On(
   564  			"Request",
   565  			"PUT",
   566  			"http://dev.com",
   567  			testMock.Anything,
   568  			testMock.Anything,
   569  		).Return(&request.Response{
   570  			Err: nil,
   571  			Response: &http.Response{
   572  				StatusCode: 200,
   573  				Body:       ioutil.NopCloser(strings.NewReader(`???`)),
   574  			},
   575  		})
   576  		client.Request = clientMock
   577  		res, err := client.UploadChunk(context.Background(), "http://dev.com", strings.NewReader("12345"), cg)
   578  		clientMock.AssertExpectations(t)
   579  		asserts.NoError(err)
   580  		asserts.Nil(res)
   581  	}
   582  
   583  	// 最后分片,失败
   584  	{
   585  		cache.Set("setting_chunk_retries", "1", 0)
   586  		client.Credential.ExpiresIn = 0
   587  		go func() {
   588  			time.Sleep(time.Duration(2) * time.Second)
   589  			client.Credential.ExpiresIn = time.Now().Add(time.Duration(100) * time.Hour).Unix()
   590  		}()
   591  		clientMock := ClientMock{}
   592  		client.Request = clientMock
   593  		res, err := client.UploadChunk(context.Background(), "http://dev.com", strings.NewReader("12345"), cg)
   594  		clientMock.AssertExpectations(t)
   595  		asserts.Error(err)
   596  		asserts.Nil(res)
   597  	}
   598  }
   599  
   600  func TestClient_Upload(t *testing.T) {
   601  	asserts := assert.New(t)
   602  	client, _ := NewClient(&model.Policy{})
   603  	client.Credential.AccessToken = "AccessToken"
   604  	client.Credential.ExpiresIn = time.Now().Add(time.Duration(100) * time.Hour).Unix()
   605  	ctx := context.Background()
   606  	cache.Set("setting_chunk_retries", "1", 0)
   607  	cache.Set("setting_use_temp_chunk_buffer", "false", 0)
   608  
   609  	// 小文件,简单上传,失败
   610  	{
   611  		client.Credential.ExpiresIn = 0
   612  		err := client.Upload(ctx, &fsctx.FileStream{
   613  			Size: 5,
   614  			File: io.NopCloser(strings.NewReader("12345")),
   615  		})
   616  		asserts.Error(err)
   617  	}
   618  
   619  	// 无法创建分片会话
   620  	{
   621  		client.Credential.ExpiresIn = time.Now().Add(time.Duration(100) * time.Hour).Unix()
   622  		clientMock := ClientMock{}
   623  		clientMock.On(
   624  			"Request",
   625  			"POST",
   626  			testMock.Anything,
   627  			testMock.Anything,
   628  			testMock.Anything,
   629  		).Return(&request.Response{
   630  			Err: nil,
   631  			Response: &http.Response{
   632  				StatusCode: 400,
   633  				Body:       ioutil.NopCloser(strings.NewReader(`{"uploadUrl":"123321"}`)),
   634  			},
   635  		})
   636  		client.Request = clientMock
   637  		err := client.Upload(context.Background(), &fsctx.FileStream{
   638  			Size: SmallFileSize + 1,
   639  			File: io.NopCloser(strings.NewReader("12345")),
   640  		})
   641  		clientMock.AssertExpectations(t)
   642  		asserts.Error(err)
   643  	}
   644  
   645  	// 分片上传失败
   646  	{
   647  		client.Credential.ExpiresIn = time.Now().Add(time.Duration(100) * time.Hour).Unix()
   648  		clientMock := ClientMock{}
   649  		clientMock.On(
   650  			"Request",
   651  			"POST",
   652  			testMock.Anything,
   653  			testMock.Anything,
   654  			testMock.Anything,
   655  		).Return(&request.Response{
   656  			Err: nil,
   657  			Response: &http.Response{
   658  				StatusCode: 200,
   659  				Body:       ioutil.NopCloser(strings.NewReader(`{"uploadUrl":"123321"}`)),
   660  			},
   661  		})
   662  		clientMock.On(
   663  			"Request",
   664  			"PUT",
   665  			testMock.Anything,
   666  			testMock.Anything,
   667  			testMock.Anything,
   668  		).Return(&request.Response{
   669  			Err: nil,
   670  			Response: &http.Response{
   671  				StatusCode: 400,
   672  				Body:       ioutil.NopCloser(strings.NewReader(`{"uploadUrl":"123321"}`)),
   673  			},
   674  		})
   675  		client.Request = clientMock
   676  		err := client.Upload(context.Background(), &fsctx.FileStream{
   677  			Size: SmallFileSize + 1,
   678  			File: io.NopCloser(strings.NewReader("12345")),
   679  		})
   680  		clientMock.AssertExpectations(t)
   681  		asserts.Error(err)
   682  		asserts.Contains(err.Error(), "failed to upload chunk")
   683  	}
   684  
   685  }
   686  
   687  func TestClient_SimpleUpload(t *testing.T) {
   688  	asserts := assert.New(t)
   689  	client, _ := NewClient(&model.Policy{})
   690  	client.Credential.AccessToken = "AccessToken"
   691  	client.Credential.ExpiresIn = time.Now().Add(time.Duration(100) * time.Hour).Unix()
   692  	cache.Set("setting_chunk_retries", "1", 0)
   693  
   694  	// 请求失败
   695  	{
   696  		client.Credential.ExpiresIn = 0
   697  		res, err := client.SimpleUpload(context.Background(), "123.jpg", strings.NewReader("123"), 3)
   698  		asserts.Error(err)
   699  		asserts.Nil(res)
   700  	}
   701  
   702  	// 返回未知响应
   703  	{
   704  		client.Credential.ExpiresIn = time.Now().Add(time.Duration(100) * time.Hour).Unix()
   705  		clientMock := ClientMock{}
   706  		clientMock.On(
   707  			"Request",
   708  			"PUT",
   709  			testMock.Anything,
   710  			testMock.Anything,
   711  			testMock.Anything,
   712  		).Return(&request.Response{
   713  			Err: nil,
   714  			Response: &http.Response{
   715  				StatusCode: 200,
   716  				Body:       ioutil.NopCloser(strings.NewReader(`???`)),
   717  			},
   718  		})
   719  		client.Request = clientMock
   720  		res, err := client.SimpleUpload(context.Background(), "123.jpg", strings.NewReader("123"), 3)
   721  		clientMock.AssertExpectations(t)
   722  		asserts.Error(err)
   723  		asserts.Nil(res)
   724  	}
   725  
   726  	// 返回正常
   727  	{
   728  		client.Credential.ExpiresIn = time.Now().Add(time.Duration(100) * time.Hour).Unix()
   729  		clientMock := ClientMock{}
   730  		clientMock.On(
   731  			"Request",
   732  			"PUT",
   733  			testMock.Anything,
   734  			testMock.Anything,
   735  			testMock.Anything,
   736  		).Return(&request.Response{
   737  			Err: nil,
   738  			Response: &http.Response{
   739  				StatusCode: 200,
   740  				Body:       ioutil.NopCloser(strings.NewReader(`{"name":"123321"}`)),
   741  			},
   742  		})
   743  		client.Request = clientMock
   744  		res, err := client.SimpleUpload(context.Background(), "123.jpg", strings.NewReader("123"), 3)
   745  		clientMock.AssertExpectations(t)
   746  		asserts.NoError(err)
   747  		asserts.NotNil(res)
   748  		asserts.Equal("123321", res.Name)
   749  	}
   750  }
   751  
   752  func TestClient_DeleteUploadSession(t *testing.T) {
   753  	asserts := assert.New(t)
   754  	client, _ := NewClient(&model.Policy{})
   755  	client.Credential.AccessToken = "AccessToken"
   756  
   757  	// 请求失败
   758  	{
   759  		client.Credential.ExpiresIn = 0
   760  		err := client.DeleteUploadSession(context.Background(), "123.jpg")
   761  		asserts.Error(err)
   762  
   763  	}
   764  
   765  	// 返回正常
   766  	{
   767  		client.Credential.ExpiresIn = time.Now().Add(time.Duration(100) * time.Hour).Unix()
   768  		clientMock := ClientMock{}
   769  		clientMock.On(
   770  			"Request",
   771  			"DELETE",
   772  			testMock.Anything,
   773  			testMock.Anything,
   774  			testMock.Anything,
   775  		).Return(&request.Response{
   776  			Err: nil,
   777  			Response: &http.Response{
   778  				StatusCode: 204,
   779  				Body:       ioutil.NopCloser(strings.NewReader(``)),
   780  			},
   781  		})
   782  		client.Request = clientMock
   783  		err := client.DeleteUploadSession(context.Background(), "123.jpg")
   784  		clientMock.AssertExpectations(t)
   785  		asserts.NoError(err)
   786  	}
   787  }
   788  
   789  func TestClient_BatchDelete(t *testing.T) {
   790  	asserts := assert.New(t)
   791  	client, _ := NewClient(&model.Policy{})
   792  	client.Credential.AccessToken = "AccessToken"
   793  
   794  	// 小于20个,失败1个
   795  	{
   796  		client.Credential.ExpiresIn = time.Now().Add(time.Duration(100) * time.Hour).Unix()
   797  		clientMock := ClientMock{}
   798  		clientMock.On(
   799  			"Request",
   800  			"POST",
   801  			testMock.Anything,
   802  			testMock.Anything,
   803  			testMock.Anything,
   804  		).Return(&request.Response{
   805  			Err: nil,
   806  			Response: &http.Response{
   807  				StatusCode: 200,
   808  				Body:       ioutil.NopCloser(strings.NewReader(`{"responses":[{"id":"2","status":400}]}`)),
   809  			},
   810  		})
   811  		client.Request = clientMock
   812  		res, err := client.BatchDelete(context.Background(), []string{"1", "2", "3", "1", "2"})
   813  		clientMock.AssertExpectations(t)
   814  		asserts.Error(err)
   815  		asserts.Equal([]string{"2"}, res)
   816  	}
   817  }
   818  
   819  func TestClient_Delete(t *testing.T) {
   820  	asserts := assert.New(t)
   821  	client, _ := NewClient(&model.Policy{})
   822  	client.Credential.AccessToken = "AccessToken"
   823  
   824  	// 请求失败
   825  	{
   826  		client.Credential.ExpiresIn = 0
   827  		res, err := client.Delete(context.Background(), []string{"1", "2", "3"})
   828  		asserts.Error(err)
   829  		asserts.Len(res, 3)
   830  	}
   831  
   832  	// 返回未知响应
   833  	{
   834  		client.Credential.ExpiresIn = time.Now().Add(time.Duration(100) * time.Hour).Unix()
   835  		clientMock := ClientMock{}
   836  		clientMock.On(
   837  			"Request",
   838  			"POST",
   839  			testMock.Anything,
   840  			testMock.Anything,
   841  			testMock.Anything,
   842  		).Return(&request.Response{
   843  			Err: nil,
   844  			Response: &http.Response{
   845  				StatusCode: 200,
   846  				Body:       ioutil.NopCloser(strings.NewReader(`???`)),
   847  			},
   848  		})
   849  		client.Request = clientMock
   850  		res, err := client.Delete(context.Background(), []string{"1", "2", "3"})
   851  		clientMock.AssertExpectations(t)
   852  		asserts.Error(err)
   853  		asserts.Len(res, 3)
   854  	}
   855  
   856  	// 成功2两个文件
   857  	{
   858  		client.Credential.ExpiresIn = time.Now().Add(time.Duration(100) * time.Hour).Unix()
   859  		clientMock := ClientMock{}
   860  		clientMock.On(
   861  			"Request",
   862  			"POST",
   863  			testMock.Anything,
   864  			testMock.Anything,
   865  			testMock.Anything,
   866  		).Return(&request.Response{
   867  			Err: nil,
   868  			Response: &http.Response{
   869  				StatusCode: 200,
   870  				Body:       ioutil.NopCloser(strings.NewReader(`{"responses":[{"id":"2","status":400}]}`)),
   871  			},
   872  		})
   873  		client.Request = clientMock
   874  		res, err := client.Delete(context.Background(), []string{"1", "2", "3"})
   875  		clientMock.AssertExpectations(t)
   876  		asserts.Error(err)
   877  		asserts.Equal([]string{"2"}, res)
   878  	}
   879  }
   880  
   881  func TestClient_ListChildren(t *testing.T) {
   882  	asserts := assert.New(t)
   883  	client, _ := NewClient(&model.Policy{})
   884  	client.Credential.AccessToken = "AccessToken"
   885  
   886  	// 根目录,请求失败,重测试
   887  	{
   888  		client.Credential.ExpiresIn = 0
   889  		res, err := client.ListChildren(context.Background(), "/")
   890  		asserts.Error(err)
   891  		asserts.Empty(res)
   892  	}
   893  
   894  	// 非根目录,未知响应
   895  	{
   896  		client.Credential.ExpiresIn = time.Now().Add(time.Duration(100) * time.Hour).Unix()
   897  		clientMock := ClientMock{}
   898  		clientMock.On(
   899  			"Request",
   900  			"GET",
   901  			testMock.Anything,
   902  			testMock.Anything,
   903  			testMock.Anything,
   904  		).Return(&request.Response{
   905  			Err: nil,
   906  			Response: &http.Response{
   907  				StatusCode: 200,
   908  				Body:       ioutil.NopCloser(strings.NewReader(`???`)),
   909  			},
   910  		})
   911  		client.Request = clientMock
   912  		res, err := client.ListChildren(context.Background(), "/uploads")
   913  		asserts.Error(err)
   914  		asserts.Empty(res)
   915  	}
   916  
   917  	// 非根目录,成功
   918  	{
   919  		client.Credential.ExpiresIn = time.Now().Add(time.Duration(100) * time.Hour).Unix()
   920  		clientMock := ClientMock{}
   921  		clientMock.On(
   922  			"Request",
   923  			"GET",
   924  			testMock.Anything,
   925  			testMock.Anything,
   926  			testMock.Anything,
   927  		).Return(&request.Response{
   928  			Err: nil,
   929  			Response: &http.Response{
   930  				StatusCode: 200,
   931  				Body:       ioutil.NopCloser(strings.NewReader(`{"value":[{}]}`)),
   932  			},
   933  		})
   934  		client.Request = clientMock
   935  		res, err := client.ListChildren(context.Background(), "/uploads")
   936  		asserts.NoError(err)
   937  		asserts.Len(res, 1)
   938  	}
   939  }
   940  
   941  func TestClient_GetThumbURL(t *testing.T) {
   942  	asserts := assert.New(t)
   943  	client, _ := NewClient(&model.Policy{})
   944  	client.Credential.AccessToken = "AccessToken"
   945  
   946  	// 请求失败
   947  	{
   948  		client.Credential.ExpiresIn = 0
   949  		res, err := client.GetThumbURL(context.Background(), "123,jpg", 1, 1)
   950  		asserts.Error(err)
   951  		asserts.Empty(res)
   952  	}
   953  
   954  	// 未知响应
   955  	{
   956  		client.Credential.ExpiresIn = time.Now().Add(time.Duration(100) * time.Hour).Unix()
   957  		clientMock := ClientMock{}
   958  		clientMock.On(
   959  			"Request",
   960  			"GET",
   961  			testMock.Anything,
   962  			testMock.Anything,
   963  			testMock.Anything,
   964  		).Return(&request.Response{
   965  			Err: nil,
   966  			Response: &http.Response{
   967  				StatusCode: 200,
   968  				Body:       ioutil.NopCloser(strings.NewReader(`???`)),
   969  			},
   970  		})
   971  		client.Request = clientMock
   972  		res, err := client.GetThumbURL(context.Background(), "123,jpg", 1, 1)
   973  		asserts.Error(err)
   974  		asserts.Empty(res)
   975  	}
   976  
   977  	// 世纪互联 成功
   978  	{
   979  		client.Credential.ExpiresIn = time.Now().Add(time.Duration(100) * time.Hour).Unix()
   980  		client.Endpoints.isInChina = true
   981  		clientMock := ClientMock{}
   982  		clientMock.On(
   983  			"Request",
   984  			"GET",
   985  			testMock.Anything,
   986  			testMock.Anything,
   987  			testMock.Anything,
   988  		).Return(&request.Response{
   989  			Err: nil,
   990  			Response: &http.Response{
   991  				StatusCode: 200,
   992  				Body:       ioutil.NopCloser(strings.NewReader(`{"url":"thumb"}`)),
   993  			},
   994  		})
   995  		client.Request = clientMock
   996  		res, err := client.GetThumbURL(context.Background(), "123,jpg", 1, 1)
   997  		asserts.NoError(err)
   998  		asserts.Equal("thumb", res)
   999  	}
  1000  
  1001  	// 非世纪互联 成功
  1002  	{
  1003  		client.Credential.ExpiresIn = time.Now().Add(time.Duration(100) * time.Hour).Unix()
  1004  		client.Endpoints.isInChina = false
  1005  		clientMock := ClientMock{}
  1006  		clientMock.On(
  1007  			"Request",
  1008  			"GET",
  1009  			testMock.Anything,
  1010  			testMock.Anything,
  1011  			testMock.Anything,
  1012  		).Return(&request.Response{
  1013  			Err: nil,
  1014  			Response: &http.Response{
  1015  				StatusCode: 200,
  1016  				Body:       ioutil.NopCloser(strings.NewReader(`{"value":[{"large":{"url":"thumb"}}]}`)),
  1017  			},
  1018  		})
  1019  		client.Request = clientMock
  1020  		res, err := client.GetThumbURL(context.Background(), "123,jpg", 1, 1)
  1021  		asserts.NoError(err)
  1022  		asserts.Equal("thumb", res)
  1023  	}
  1024  }
  1025  
  1026  func TestClient_MonitorUpload(t *testing.T) {
  1027  	asserts := assert.New(t)
  1028  	client, _ := NewClient(&model.Policy{})
  1029  	client.Credential.ExpiresIn = time.Now().Add(time.Duration(100) * time.Hour).Unix()
  1030  
  1031  	// 客户端完成回调
  1032  	{
  1033  		cache.Set("setting_onedrive_monitor_timeout", "600", 0)
  1034  		cache.Set("setting_onedrive_callback_check", "20", 0)
  1035  		asserts.NotPanics(func() {
  1036  			go func() {
  1037  				time.Sleep(time.Duration(1) * time.Second)
  1038  				mq.GlobalMQ.Publish("key", mq.Message{})
  1039  			}()
  1040  			client.MonitorUpload("url", "key", "path", 10, 10)
  1041  		})
  1042  	}
  1043  
  1044  	// 上传会话到期,仍未完成上传,创建占位符
  1045  	{
  1046  		cache.Set("setting_onedrive_monitor_timeout", "600", 0)
  1047  		cache.Set("setting_onedrive_callback_check", "20", 0)
  1048  		asserts.NotPanics(func() {
  1049  			client.MonitorUpload("url", "key", "path", 10, 0)
  1050  		})
  1051  	}
  1052  
  1053  	fmt.Println("测试:上传已完成,未发送回调")
  1054  	// 上传已完成,未发送回调
  1055  	{
  1056  		cache.Set("setting_onedrive_monitor_timeout", "0", 0)
  1057  		cache.Set("setting_onedrive_callback_check", "0", 0)
  1058  
  1059  		client.Credential.ExpiresIn = time.Now().Add(time.Duration(100) * time.Hour).Unix()
  1060  		client.Credential.AccessToken = "1"
  1061  		clientMock := ClientMock{}
  1062  		clientMock.On(
  1063  			"Request",
  1064  			"GET",
  1065  			testMock.Anything,
  1066  			testMock.Anything,
  1067  			testMock.Anything,
  1068  		).Return(&request.Response{
  1069  			Err: nil,
  1070  			Response: &http.Response{
  1071  				StatusCode: 404,
  1072  				Body:       ioutil.NopCloser(strings.NewReader(`{"error":{"code":"itemNotFound"}}`)),
  1073  			},
  1074  		})
  1075  		clientMock.On(
  1076  			"Request",
  1077  			"POST",
  1078  			testMock.Anything,
  1079  			testMock.Anything,
  1080  			testMock.Anything,
  1081  		).Return(&request.Response{
  1082  			Err: nil,
  1083  			Response: &http.Response{
  1084  				StatusCode: 404,
  1085  				Body:       ioutil.NopCloser(strings.NewReader(`{"error":{"code":"itemNotFound"}}`)),
  1086  			},
  1087  		})
  1088  		client.Request = clientMock
  1089  		cache.Set("callback_key3", "ok", 0)
  1090  
  1091  		asserts.NotPanics(func() {
  1092  			client.MonitorUpload("url", "key3", "path", 10, 10)
  1093  		})
  1094  
  1095  		clientMock.AssertExpectations(t)
  1096  	}
  1097  
  1098  	fmt.Println("测试:上传仍未开始")
  1099  	// 上传仍未开始
  1100  	{
  1101  		cache.Set("setting_onedrive_monitor_timeout", "0", 0)
  1102  		cache.Set("setting_onedrive_callback_check", "0", 0)
  1103  
  1104  		client.Credential.ExpiresIn = time.Now().Add(time.Duration(100) * time.Hour).Unix()
  1105  		client.Credential.AccessToken = "1"
  1106  		clientMock := ClientMock{}
  1107  		clientMock.On(
  1108  			"Request",
  1109  			"GET",
  1110  			testMock.Anything,
  1111  			testMock.Anything,
  1112  			testMock.Anything,
  1113  		).Return(&request.Response{
  1114  			Err: nil,
  1115  			Response: &http.Response{
  1116  				StatusCode: 200,
  1117  				Body:       ioutil.NopCloser(strings.NewReader(`{"nextExpectedRanges":["0-"]}`)),
  1118  			},
  1119  		})
  1120  		clientMock.On(
  1121  			"Request",
  1122  			"DELETE",
  1123  			testMock.Anything,
  1124  			testMock.Anything,
  1125  			testMock.Anything,
  1126  		).Return(&request.Response{
  1127  			Err: nil,
  1128  			Response: &http.Response{
  1129  				StatusCode: 200,
  1130  				Body:       ioutil.NopCloser(strings.NewReader(``)),
  1131  			},
  1132  		})
  1133  		clientMock.On(
  1134  			"Request",
  1135  			"PUT",
  1136  			testMock.Anything,
  1137  			testMock.Anything,
  1138  			testMock.Anything,
  1139  		).Return(&request.Response{
  1140  			Err: nil,
  1141  			Response: &http.Response{
  1142  				StatusCode: 200,
  1143  				Body:       ioutil.NopCloser(strings.NewReader(`{}`)),
  1144  			},
  1145  		})
  1146  		client.Request = clientMock
  1147  
  1148  		asserts.NotPanics(func() {
  1149  			client.MonitorUpload("url", "key4", "path", 10, 10)
  1150  		})
  1151  
  1152  		clientMock.AssertExpectations(t)
  1153  	}
  1154  
  1155  }