mirror of https://github.com/Xhofe/alist
179 lines
4.5 KiB
Go
179 lines
4.5 KiB
Go
package net
|
|
|
|
//no http range
|
|
//
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"sync"
|
|
"testing"
|
|
|
|
"github.com/alist-org/alist/v3/pkg/http_range"
|
|
"github.com/sirupsen/logrus"
|
|
"golang.org/x/exp/slices"
|
|
)
|
|
|
|
var buf22MB = make([]byte, 1024*1024*22)
|
|
|
|
func dummyHttpRequest(data []byte, p http_range.Range) io.ReadCloser {
|
|
|
|
end := p.Start + p.Length - 1
|
|
|
|
if end >= int64(len(data)) {
|
|
end = int64(len(data))
|
|
}
|
|
|
|
bodyBytes := data[p.Start:end]
|
|
return io.NopCloser(bytes.NewReader(bodyBytes))
|
|
}
|
|
|
|
func TestDownloadOrder(t *testing.T) {
|
|
buff := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
|
|
downloader, invocations, ranges := newDownloadRangeClient(buff)
|
|
con, partSize := 3, 3
|
|
d := NewDownloader(func(d *Downloader) {
|
|
d.Concurrency = con
|
|
d.PartSize = partSize
|
|
d.HttpClient = downloader.HttpRequest
|
|
})
|
|
|
|
var start, length int64 = 2, 10
|
|
length2 := length
|
|
if length2 == -1 {
|
|
length2 = int64(len(buff)) - start
|
|
}
|
|
req := &HttpRequestParams{
|
|
Range: http_range.Range{Start: start, Length: length},
|
|
Size: int64(len(buff)),
|
|
}
|
|
readCloser, err := d.Download(context.Background(), req)
|
|
|
|
if err != nil {
|
|
t.Fatalf("expect no error, got %v", err)
|
|
}
|
|
resultBuf, err := io.ReadAll(readCloser)
|
|
if err != nil {
|
|
t.Fatalf("expect no error, got %v", err)
|
|
}
|
|
if exp, a := int(length), len(resultBuf); exp != a {
|
|
t.Errorf("expect buffer length=%d, got %d", exp, a)
|
|
}
|
|
chunkSize := int(length)/partSize + 1
|
|
if int(length)%partSize == 0 {
|
|
chunkSize--
|
|
}
|
|
if e, a := chunkSize, *invocations; e != a {
|
|
t.Errorf("expect %v API calls, got %v", e, a)
|
|
}
|
|
|
|
expectRngs := []string{"2-3", "5-3", "8-3", "11-1"}
|
|
for _, rng := range expectRngs {
|
|
if !slices.Contains(*ranges, rng) {
|
|
t.Errorf("expect range %v, but absent in return", rng)
|
|
}
|
|
}
|
|
if e, a := expectRngs, *ranges; len(e) != len(a) {
|
|
t.Errorf("expect %v ranges, got %v", e, a)
|
|
}
|
|
}
|
|
func init() {
|
|
Formatter := new(logrus.TextFormatter)
|
|
Formatter.TimestampFormat = "2006-01-02T15:04:05.999999999"
|
|
Formatter.FullTimestamp = true
|
|
Formatter.ForceColors = true
|
|
logrus.SetFormatter(Formatter)
|
|
logrus.SetLevel(logrus.DebugLevel)
|
|
logrus.Debugf("Download start")
|
|
}
|
|
|
|
func TestDownloadSingle(t *testing.T) {
|
|
buff := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
|
|
downloader, invocations, ranges := newDownloadRangeClient(buff)
|
|
con, partSize := 1, 3
|
|
d := NewDownloader(func(d *Downloader) {
|
|
d.Concurrency = con
|
|
d.PartSize = partSize
|
|
d.HttpClient = downloader.HttpRequest
|
|
})
|
|
|
|
var start, length int64 = 2, 10
|
|
req := &HttpRequestParams{
|
|
Range: http_range.Range{Start: start, Length: length},
|
|
Size: int64(len(buff)),
|
|
}
|
|
|
|
readCloser, err := d.Download(context.Background(), req)
|
|
|
|
if err != nil {
|
|
t.Fatalf("expect no error, got %v", err)
|
|
}
|
|
resultBuf, err := io.ReadAll(readCloser)
|
|
if err != nil {
|
|
t.Fatalf("expect no error, got %v", err)
|
|
}
|
|
if exp, a := int(length), len(resultBuf); exp != a {
|
|
t.Errorf("expect buffer length=%d, got %d", exp, a)
|
|
}
|
|
if e, a := 1, *invocations; e != a {
|
|
t.Errorf("expect %v API calls, got %v", e, a)
|
|
}
|
|
|
|
expectRngs := []string{"2-10"}
|
|
for _, rng := range expectRngs {
|
|
if !slices.Contains(*ranges, rng) {
|
|
t.Errorf("expect range %v, but absent in return", rng)
|
|
}
|
|
}
|
|
if e, a := expectRngs, *ranges; len(e) != len(a) {
|
|
t.Errorf("expect %v ranges, got %v", e, a)
|
|
}
|
|
}
|
|
|
|
type downloadCaptureClient struct {
|
|
mockedHttpRequest func(params *HttpRequestParams) (*http.Response, error)
|
|
GetObjectInvocations int
|
|
|
|
RetrievedRanges []string
|
|
|
|
lock sync.Mutex
|
|
}
|
|
|
|
func (c *downloadCaptureClient) HttpRequest(ctx context.Context, params *HttpRequestParams) (*http.Response, error) {
|
|
c.lock.Lock()
|
|
defer c.lock.Unlock()
|
|
|
|
c.GetObjectInvocations++
|
|
|
|
if ¶ms.Range != nil {
|
|
c.RetrievedRanges = append(c.RetrievedRanges, fmt.Sprintf("%d-%d", params.Range.Start, params.Range.Length))
|
|
}
|
|
|
|
return c.mockedHttpRequest(params)
|
|
}
|
|
|
|
func newDownloadRangeClient(data []byte) (*downloadCaptureClient, *int, *[]string) {
|
|
capture := &downloadCaptureClient{}
|
|
|
|
capture.mockedHttpRequest = func(params *HttpRequestParams) (*http.Response, error) {
|
|
start, fin := params.Range.Start, params.Range.Start+params.Range.Length
|
|
if params.Range.Length == -1 || fin >= int64(len(data)) {
|
|
fin = int64(len(data))
|
|
}
|
|
bodyBytes := data[start:fin]
|
|
|
|
header := &http.Header{}
|
|
header.Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", start, fin-1, len(data)))
|
|
return &http.Response{
|
|
Body: io.NopCloser(bytes.NewReader(bodyBytes)),
|
|
Header: *header,
|
|
ContentLength: int64(len(bodyBytes)),
|
|
}, nil
|
|
}
|
|
|
|
return capture, &capture.GetObjectInvocations, &capture.RetrievedRanges
|
|
}
|