Skip to content
This repository was archived by the owner on Dec 20, 2024. It is now read-only.

Commit 19f1613

Browse files
authored
Merge pull request #1275 from antsystem/feat/add-lru-queue-and-mockfileserver-prepare-pr
add lru queue and mockFileServer
2 parents 7856ccd + b3222f5 commit 19f1613

File tree

4 files changed

+576
-0
lines changed

4 files changed

+576
-0
lines changed

dfget/core/helper/helper_test.go

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,17 @@
1717
package helper
1818

1919
import (
20+
"context"
21+
"fmt"
22+
"io/ioutil"
2023
"reflect"
2124
"runtime"
2225
"strings"
2326
"testing"
2427

2528
"github.com/dragonflyoss/Dragonfly/dfget/config"
29+
"github.com/dragonflyoss/Dragonfly/pkg/httputils"
30+
2631
"github.com/go-check/check"
2732
)
2833

@@ -74,3 +79,115 @@ func (s *HelperTestSuite) TestDownloadPattern(c *check.C) {
7479
check.Commentf("f:%v pattern:%s", name(v.f), v.pattern))
7580
}
7681
}
82+
83+
func (s *HelperTestSuite) readFromFileServer(port int, path string, off int64, size int64) ([]byte, error) {
84+
url := fmt.Sprintf("http://127.0.0.1:%d/%s", port, path)
85+
header := map[string]string{}
86+
87+
if size > 0 {
88+
header["Range"] = fmt.Sprintf("bytes=%d-%d", off, off+size-1)
89+
}
90+
91+
resp, err := httputils.HTTPGet(url, header)
92+
if err != nil {
93+
return nil, err
94+
}
95+
96+
defer resp.Body.Close()
97+
98+
if resp.StatusCode >= 400 {
99+
return nil, fmt.Errorf("resp code %d", resp.StatusCode)
100+
}
101+
102+
return ioutil.ReadAll(resp.Body)
103+
}
104+
105+
func (s *HelperTestSuite) getRepeatStr(data []byte, size int64) []byte {
106+
for {
107+
if int64(len(data)) >= size {
108+
break
109+
}
110+
111+
newData := make([]byte, len(data)*2)
112+
copy(newData, data)
113+
copy(newData[len(data):], data)
114+
data = newData
115+
}
116+
117+
return data[:size]
118+
}
119+
120+
func (s *HelperTestSuite) TestMockFileServer(c *check.C) {
121+
var (
122+
data []byte
123+
err error
124+
)
125+
126+
// run server
127+
mfs := NewMockFileServer()
128+
err = mfs.StartServer(context.Background(), 10011)
129+
c.Assert(err, check.IsNil)
130+
131+
// register fileA
132+
err = mfs.RegisterFile("fileA", 100, "a")
133+
c.Assert(err, check.IsNil)
134+
135+
// test fileA
136+
// read 0-9
137+
data, err = s.readFromFileServer(mfs.Port, "fileA", 0, 10)
138+
c.Assert(err, check.IsNil)
139+
c.Assert(string(data), check.Equals, string(s.getRepeatStr([]byte("a"), 10)))
140+
141+
// read 1-20
142+
data, err = s.readFromFileServer(mfs.Port, "fileA", 1, 20)
143+
c.Assert(err, check.IsNil)
144+
c.Assert(string(data), check.Equals, string(s.getRepeatStr([]byte("a"), 20)))
145+
146+
// read 1-100
147+
data, err = s.readFromFileServer(mfs.Port, "fileA", 1, 99)
148+
c.Assert(err, check.IsNil)
149+
c.Assert(string(data), check.Equals, string(s.getRepeatStr([]byte("a"), 99)))
150+
151+
// read all
152+
data, err = s.readFromFileServer(mfs.Port, "fileA", 0, -1)
153+
c.Assert(err, check.IsNil)
154+
c.Assert(string(data), check.Equals, string(s.getRepeatStr([]byte("a"), 100)))
155+
156+
// read 0-99
157+
data, err = s.readFromFileServer(mfs.Port, "fileA", 0, 100)
158+
c.Assert(err, check.IsNil)
159+
c.Assert(string(data), check.Equals, string(s.getRepeatStr([]byte("a"), 100)))
160+
161+
// register fileB
162+
err = mfs.RegisterFile("fileB", 10000, "abcde")
163+
c.Assert(err, check.IsNil)
164+
165+
// read 0-9
166+
data, err = s.readFromFileServer(mfs.Port, "fileB", 0, 10)
167+
c.Assert(err, check.IsNil)
168+
c.Assert(string(data), check.Equals, string(s.getRepeatStr([]byte("abcde"), 10)))
169+
170+
// read 8-100
171+
data, err = s.readFromFileServer(mfs.Port, "fileB", 8, 93)
172+
c.Assert(err, check.IsNil)
173+
expectStr := s.getRepeatStr([]byte("abcde"), 101)
174+
c.Assert(string(data), check.Equals, string(expectStr[8:]))
175+
176+
// read 1000-9999
177+
data, err = s.readFromFileServer(mfs.Port, "fileB", 1000, 9000)
178+
c.Assert(err, check.IsNil)
179+
expectStr = s.getRepeatStr([]byte("abcde"), 10000)
180+
c.Assert(string(data), check.Equals, string(expectStr[1000:]))
181+
182+
// read 1001-9000
183+
data, err = s.readFromFileServer(mfs.Port, "fileB", 1001, 8000)
184+
c.Assert(err, check.IsNil)
185+
expectStr = s.getRepeatStr([]byte("abcde"), 9001)
186+
c.Assert(string(data), check.Equals, string(expectStr[1001:]))
187+
188+
// read all
189+
data, err = s.readFromFileServer(mfs.Port, "fileB", 0, -1)
190+
c.Assert(err, check.IsNil)
191+
expectStr = s.getRepeatStr([]byte("abcde"), 10000)
192+
c.Assert(string(data), check.Equals, string(expectStr))
193+
}

dfget/core/helper/test_helper.go

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,26 @@
1717
package helper
1818

1919
import (
20+
"context"
2021
"fmt"
2122
"io"
2223
"io/ioutil"
24+
"math"
2325
"math/rand"
26+
"net"
27+
"net/http"
2428
"os"
2529
"path/filepath"
30+
"strings"
31+
"sync"
2632

2733
api_types "github.com/dragonflyoss/Dragonfly/apis/types"
2834
"github.com/dragonflyoss/Dragonfly/dfget/config"
2935
"github.com/dragonflyoss/Dragonfly/dfget/core/api"
3036
"github.com/dragonflyoss/Dragonfly/dfget/types"
3137
"github.com/dragonflyoss/Dragonfly/pkg/constants"
3238
"github.com/dragonflyoss/Dragonfly/pkg/fileutils"
39+
"github.com/dragonflyoss/Dragonfly/pkg/httputils"
3340

3441
"github.com/sirupsen/logrus"
3542
)
@@ -210,3 +217,180 @@ func CreateRegisterFunc() RegisterFuncType {
210217
return nil, nil
211218
}
212219
}
220+
221+
// MockFileServer mocks the file server.
222+
type MockFileServer struct {
223+
sync.Mutex
224+
Port int
225+
fileMap map[string]*mockFile
226+
sr *http.Server
227+
}
228+
229+
func NewMockFileServer() *MockFileServer {
230+
return &MockFileServer{
231+
fileMap: make(map[string]*mockFile),
232+
}
233+
}
234+
235+
// StartServer asynchronously starts the server, it will not be blocked.
236+
func (fs *MockFileServer) StartServer(ctx context.Context, port int) error {
237+
addr, err := net.ResolveTCPAddr("", fmt.Sprintf(":%d", port))
238+
if err != nil {
239+
return err
240+
}
241+
242+
l, err := net.ListenTCP("tcp", addr)
243+
if err != nil {
244+
return err
245+
}
246+
247+
fs.Port = addr.Port
248+
sr := &http.Server{}
249+
sr.Handler = fs
250+
fs.sr = sr
251+
252+
go func() {
253+
if err := fs.sr.Serve(l); err != nil {
254+
panic(err)
255+
}
256+
}()
257+
258+
go func() {
259+
for {
260+
select {
261+
case <-ctx.Done():
262+
fs.sr.Close()
263+
return
264+
}
265+
}
266+
}()
267+
268+
return nil
269+
}
270+
271+
func (fs *MockFileServer) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
272+
var (
273+
err error
274+
reqRange *httputils.RangeStruct
275+
)
276+
277+
if req.Method != http.MethodGet {
278+
resp.WriteHeader(http.StatusNotFound)
279+
return
280+
}
281+
282+
path := req.URL.Path
283+
path = strings.Trim(path, "/")
284+
285+
fs.Lock()
286+
mf, exist := fs.fileMap[path]
287+
fs.Unlock()
288+
289+
if !exist {
290+
resp.WriteHeader(http.StatusNotFound)
291+
return
292+
}
293+
294+
rangeSt := []*httputils.RangeStruct{}
295+
rangeStr := req.Header.Get("Range")
296+
297+
if rangeStr != "" {
298+
rangeSt, err = httputils.GetRangeSE(rangeStr, math.MaxInt64)
299+
if err != nil {
300+
resp.WriteHeader(http.StatusBadRequest)
301+
return
302+
}
303+
}
304+
305+
if len(rangeSt) > 0 {
306+
reqRange = rangeSt[0]
307+
}
308+
309+
fs.MockResp(resp, mf, reqRange)
310+
}
311+
312+
func (fs *MockFileServer) RegisterFile(path string, size int64, repeatStr string) error {
313+
fs.Lock()
314+
defer fs.Unlock()
315+
316+
path = strings.Trim(path, "/")
317+
_, exist := fs.fileMap[path]
318+
if exist {
319+
return os.ErrExist
320+
}
321+
322+
data := []byte(repeatStr)
323+
if len(data) < 1024 {
324+
for {
325+
newData := make([]byte, len(data)*2)
326+
copy(newData, data)
327+
copy(newData[len(data):], data)
328+
data = newData
329+
330+
if len(data) >= 1024 {
331+
break
332+
}
333+
}
334+
}
335+
336+
fs.fileMap[path] = &mockFile{
337+
path: path,
338+
size: size,
339+
repeatStr: data,
340+
}
341+
342+
return nil
343+
}
344+
345+
func (fs *MockFileServer) UnRegisterFile(path string) {
346+
fs.Lock()
347+
defer fs.Unlock()
348+
349+
delete(fs.fileMap, strings.Trim(path, "/"))
350+
}
351+
352+
func (fs *MockFileServer) MockResp(resp http.ResponseWriter, mf *mockFile, rangeSt *httputils.RangeStruct) {
353+
var (
354+
respCode int
355+
start int64
356+
end = mf.size - 1
357+
)
358+
if rangeSt != nil {
359+
start = rangeSt.StartIndex
360+
if rangeSt.EndIndex < end {
361+
end = rangeSt.EndIndex
362+
}
363+
respCode = http.StatusPartialContent
364+
} else {
365+
respCode = http.StatusOK
366+
}
367+
368+
resp.Header().Set("Content-Length", fmt.Sprintf("%d", end-start+1))
369+
resp.WriteHeader(respCode)
370+
371+
repeatStrLen := int64(len(mf.repeatStr))
372+
strIndex := start % int64(repeatStrLen)
373+
374+
for {
375+
if start > end {
376+
break
377+
}
378+
379+
copyDataLen := repeatStrLen - strIndex
380+
if copyDataLen > (end - start + 1) {
381+
copyDataLen = end - start + 1
382+
}
383+
384+
resp.Write(mf.repeatStr[strIndex : copyDataLen+strIndex])
385+
strIndex = 0
386+
start += copyDataLen
387+
}
388+
389+
return
390+
}
391+
392+
type mockFile struct {
393+
path string
394+
size int64
395+
repeatStr []byte
396+
}

0 commit comments

Comments
 (0)