Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alist-org
GitHub Repository: alist-org/alist
Path: blob/main/internal/net/request_test.go
1560 views
1
package net
2
3
//no http range
4
//
5
6
import (
7
"bytes"
8
"context"
9
"fmt"
10
"io"
11
"net/http"
12
"sync"
13
"testing"
14
15
"github.com/alist-org/alist/v3/pkg/http_range"
16
"github.com/sirupsen/logrus"
17
"golang.org/x/exp/slices"
18
)
19
20
var buf22MB = make([]byte, 1024*1024*22)
21
22
func dummyHttpRequest(data []byte, p http_range.Range) io.ReadCloser {
23
24
end := p.Start + p.Length - 1
25
26
if end >= int64(len(data)) {
27
end = int64(len(data))
28
}
29
30
bodyBytes := data[p.Start:end]
31
return io.NopCloser(bytes.NewReader(bodyBytes))
32
}
33
34
func TestDownloadOrder(t *testing.T) {
35
buff := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
36
downloader, invocations, ranges := newDownloadRangeClient(buff)
37
con, partSize := 3, 3
38
d := NewDownloader(func(d *Downloader) {
39
d.Concurrency = con
40
d.PartSize = partSize
41
d.HttpClient = downloader.HttpRequest
42
})
43
44
var start, length int64 = 2, 10
45
length2 := length
46
if length2 == -1 {
47
length2 = int64(len(buff)) - start
48
}
49
req := &HttpRequestParams{
50
Range: http_range.Range{Start: start, Length: length},
51
Size: int64(len(buff)),
52
}
53
readCloser, err := d.Download(context.Background(), req)
54
55
if err != nil {
56
t.Fatalf("expect no error, got %v", err)
57
}
58
resultBuf, err := io.ReadAll(readCloser)
59
if err != nil {
60
t.Fatalf("expect no error, got %v", err)
61
}
62
if exp, a := int(length), len(resultBuf); exp != a {
63
t.Errorf("expect buffer length=%d, got %d", exp, a)
64
}
65
chunkSize := int(length)/partSize + 1
66
if int(length)%partSize == 0 {
67
chunkSize--
68
}
69
if e, a := chunkSize, *invocations; e != a {
70
t.Errorf("expect %v API calls, got %v", e, a)
71
}
72
73
expectRngs := []string{"2-3", "5-3", "8-3", "11-1"}
74
for _, rng := range expectRngs {
75
if !slices.Contains(*ranges, rng) {
76
t.Errorf("expect range %v, but absent in return", rng)
77
}
78
}
79
if e, a := expectRngs, *ranges; len(e) != len(a) {
80
t.Errorf("expect %v ranges, got %v", e, a)
81
}
82
}
83
func init() {
84
Formatter := new(logrus.TextFormatter)
85
Formatter.TimestampFormat = "2006-01-02T15:04:05.999999999"
86
Formatter.FullTimestamp = true
87
Formatter.ForceColors = true
88
logrus.SetFormatter(Formatter)
89
logrus.SetLevel(logrus.DebugLevel)
90
logrus.Debugf("Download start")
91
}
92
93
func TestDownloadSingle(t *testing.T) {
94
buff := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
95
downloader, invocations, ranges := newDownloadRangeClient(buff)
96
con, partSize := 1, 3
97
d := NewDownloader(func(d *Downloader) {
98
d.Concurrency = con
99
d.PartSize = partSize
100
d.HttpClient = downloader.HttpRequest
101
})
102
103
var start, length int64 = 2, 10
104
req := &HttpRequestParams{
105
Range: http_range.Range{Start: start, Length: length},
106
Size: int64(len(buff)),
107
}
108
109
readCloser, err := d.Download(context.Background(), req)
110
111
if err != nil {
112
t.Fatalf("expect no error, got %v", err)
113
}
114
resultBuf, err := io.ReadAll(readCloser)
115
if err != nil {
116
t.Fatalf("expect no error, got %v", err)
117
}
118
if exp, a := int(length), len(resultBuf); exp != a {
119
t.Errorf("expect buffer length=%d, got %d", exp, a)
120
}
121
if e, a := 1, *invocations; e != a {
122
t.Errorf("expect %v API calls, got %v", e, a)
123
}
124
125
expectRngs := []string{"2-10"}
126
for _, rng := range expectRngs {
127
if !slices.Contains(*ranges, rng) {
128
t.Errorf("expect range %v, but absent in return", rng)
129
}
130
}
131
if e, a := expectRngs, *ranges; len(e) != len(a) {
132
t.Errorf("expect %v ranges, got %v", e, a)
133
}
134
}
135
136
type downloadCaptureClient struct {
137
mockedHttpRequest func(params *HttpRequestParams) (*http.Response, error)
138
GetObjectInvocations int
139
140
RetrievedRanges []string
141
142
lock sync.Mutex
143
}
144
145
func (c *downloadCaptureClient) HttpRequest(ctx context.Context, params *HttpRequestParams) (*http.Response, error) {
146
c.lock.Lock()
147
defer c.lock.Unlock()
148
149
c.GetObjectInvocations++
150
151
if &params.Range != nil {
152
c.RetrievedRanges = append(c.RetrievedRanges, fmt.Sprintf("%d-%d", params.Range.Start, params.Range.Length))
153
}
154
155
return c.mockedHttpRequest(params)
156
}
157
158
func newDownloadRangeClient(data []byte) (*downloadCaptureClient, *int, *[]string) {
159
capture := &downloadCaptureClient{}
160
161
capture.mockedHttpRequest = func(params *HttpRequestParams) (*http.Response, error) {
162
start, fin := params.Range.Start, params.Range.Start+params.Range.Length
163
if params.Range.Length == -1 || fin >= int64(len(data)) {
164
fin = int64(len(data))
165
}
166
bodyBytes := data[start:fin]
167
168
header := &http.Header{}
169
header.Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", start, fin-1, len(data)))
170
return &http.Response{
171
Body: io.NopCloser(bytes.NewReader(bodyBytes)),
172
Header: *header,
173
ContentLength: int64(len(bodyBytes)),
174
}, nil
175
}
176
177
return capture, &capture.GetObjectInvocations, &capture.RetrievedRanges
178
}
179
180