368 lines
8.9 KiB
Go
368 lines
8.9 KiB
Go
package apis
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
import (
|
|
"github.com/ihexxa/quickshare/server/libs/cfg"
|
|
"github.com/ihexxa/quickshare/server/libs/encrypt"
|
|
"github.com/ihexxa/quickshare/server/libs/errutil"
|
|
"github.com/ihexxa/quickshare/server/libs/fileidx"
|
|
"github.com/ihexxa/quickshare/server/libs/httputil"
|
|
"github.com/ihexxa/quickshare/server/libs/httpworker"
|
|
"github.com/ihexxa/quickshare/server/libs/limiter"
|
|
"github.com/ihexxa/quickshare/server/libs/logutil"
|
|
"github.com/ihexxa/quickshare/server/libs/walls"
|
|
)
|
|
|
|
const testCap = 3
|
|
|
|
func initServiceForUploadTest(config *cfg.Config, indexMap map[string]*fileidx.FileInfo) *SrvShare {
|
|
logger := logutil.NewSlog(os.Stdout, config.AppName)
|
|
setLog := func(srv *SrvShare) {
|
|
srv.Log = logger
|
|
}
|
|
|
|
setWorkerPool := func(srv *SrvShare) {
|
|
workerPoolSize := config.WorkerPoolSize
|
|
taskQueueSize := config.TaskQueueSize
|
|
srv.WorkerPool = httpworker.NewWorkerPool(workerPoolSize, taskQueueSize, logger)
|
|
}
|
|
|
|
setWalls := func(srv *SrvShare) {
|
|
encrypterMaker := encrypt.JwtEncrypterMaker
|
|
ipLimiter := limiter.NewRateLimiter(config.LimiterCap, config.LimiterTtl, config.LimiterCyc, config.BucketCap, map[int16]int16{})
|
|
opLimiter := limiter.NewRateLimiter(config.LimiterCap, config.LimiterTtl, config.LimiterCyc, config.BucketCap, map[int16]int16{})
|
|
srv.Walls = walls.NewAccessWalls(config, ipLimiter, opLimiter, encrypterMaker)
|
|
}
|
|
|
|
setIndex := func(srv *SrvShare) {
|
|
srv.Index = fileidx.NewMemFileIndexWithMap(len(indexMap)+testCap, indexMap)
|
|
}
|
|
|
|
setFs := func(srv *SrvShare) {
|
|
srv.Fs = &stubFsUtil{}
|
|
}
|
|
|
|
setEncryptor := func(srv *SrvShare) {
|
|
srv.Encryptor = &encrypt.HmacEncryptor{Key: config.SecretKeyByte}
|
|
}
|
|
|
|
errChecker := errutil.NewErrChecker(!config.Production, logger)
|
|
setErr := func(srv *SrvShare) {
|
|
srv.Err = errChecker
|
|
}
|
|
|
|
return InitSrvShare(config, setIndex, setWalls, setWorkerPool, setFs, setEncryptor, setLog, setErr)
|
|
}
|
|
|
|
func TestStartUpload(t *testing.T) {
|
|
conf := cfg.NewConfig()
|
|
conf.Production = false
|
|
|
|
type Init struct {
|
|
IndexMap map[string]*fileidx.FileInfo
|
|
}
|
|
type Input struct {
|
|
FileName string
|
|
}
|
|
type Output struct {
|
|
Response interface{}
|
|
IndexMap map[string]*fileidx.FileInfo
|
|
}
|
|
type testCase struct {
|
|
Desc string
|
|
Init
|
|
Input
|
|
Output
|
|
}
|
|
|
|
testCases := []testCase{
|
|
testCase{
|
|
Desc: "invalid file name",
|
|
Init: Init{
|
|
IndexMap: map[string]*fileidx.FileInfo{},
|
|
},
|
|
Input: Input{
|
|
FileName: "",
|
|
},
|
|
Output: Output{
|
|
IndexMap: map[string]*fileidx.FileInfo{},
|
|
Response: httputil.Err400,
|
|
},
|
|
},
|
|
testCase{
|
|
Desc: "succeed to start uploading",
|
|
Init: Init{
|
|
IndexMap: map[string]*fileidx.FileInfo{},
|
|
},
|
|
Input: Input{
|
|
FileName: "filename",
|
|
},
|
|
Output: Output{
|
|
IndexMap: map[string]*fileidx.FileInfo{
|
|
DefaultId: &fileidx.FileInfo{
|
|
Id: DefaultId,
|
|
DownLimit: conf.DownLimit,
|
|
ModTime: time.Now().UnixNano(),
|
|
PathLocal: "filename",
|
|
Uploaded: 0,
|
|
State: fileidx.StateUploading,
|
|
},
|
|
},
|
|
Response: &ByteRange{
|
|
ShareId: DefaultId,
|
|
Start: 0,
|
|
Length: conf.MaxUpBytesPerSec,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, testCase := range testCases {
|
|
srv := initServiceForUploadTest(conf, testCase.Init.IndexMap)
|
|
|
|
// verify CreateFile
|
|
expectCreateFileName = filepath.Join(conf.PathLocal, testCase.FileName)
|
|
|
|
response := srv.startUpload(testCase.FileName)
|
|
|
|
// verify index
|
|
if !sameMap(srv.Index.List(), testCase.Output.IndexMap) {
|
|
t.Fatalf("startUpload: index not equal got: %v, %v, expect: %v", srv.Index.List(), response, testCase.Output.IndexMap)
|
|
}
|
|
|
|
// verify response
|
|
switch expectRes := testCase.Output.Response.(type) {
|
|
case *ByteRange:
|
|
res := response.(*ByteRange)
|
|
if res.ShareId != expectRes.ShareId ||
|
|
res.Start != expectRes.Start ||
|
|
res.Length != expectRes.Length {
|
|
t.Fatalf(fmt.Sprintf("startUpload: res=%v expect=%v", res, expectRes))
|
|
}
|
|
case httputil.MsgRes:
|
|
if response != expectRes {
|
|
t.Fatalf(fmt.Sprintf("startUpload: reponse=%v expectRes=%v", response, expectRes))
|
|
}
|
|
default:
|
|
t.Fatalf(fmt.Sprintf("startUpload: type not found: %T %T", testCase.Output.Response, httputil.Err400))
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestUpload(t *testing.T) {
|
|
conf := cfg.NewConfig()
|
|
conf.Production = false
|
|
|
|
type Init struct {
|
|
IndexMap map[string]*fileidx.FileInfo
|
|
}
|
|
type Input struct {
|
|
ShareId string
|
|
Start int64
|
|
Len int64
|
|
Chunk io.Reader
|
|
}
|
|
type Output struct {
|
|
IndexMap map[string]*fileidx.FileInfo
|
|
Response interface{}
|
|
}
|
|
type testCase struct {
|
|
Desc string
|
|
Init
|
|
Input
|
|
Output
|
|
}
|
|
|
|
testCases := []testCase{
|
|
testCase{
|
|
Desc: "shareid does not exist",
|
|
Init: Init{
|
|
IndexMap: map[string]*fileidx.FileInfo{},
|
|
},
|
|
Input: Input{
|
|
ShareId: DefaultId,
|
|
Start: 0,
|
|
Len: 1,
|
|
Chunk: strings.NewReader(""),
|
|
},
|
|
Output: Output{
|
|
IndexMap: map[string]*fileidx.FileInfo{},
|
|
Response: httputil.Err404,
|
|
},
|
|
},
|
|
testCase{
|
|
Desc: "succeed",
|
|
Init: Init{
|
|
IndexMap: map[string]*fileidx.FileInfo{
|
|
DefaultId: &fileidx.FileInfo{
|
|
Id: DefaultId,
|
|
DownLimit: conf.MaxShares,
|
|
PathLocal: "path/filename",
|
|
State: fileidx.StateUploading,
|
|
Uploaded: 0,
|
|
},
|
|
},
|
|
},
|
|
Input: Input{
|
|
ShareId: DefaultId,
|
|
Start: 0,
|
|
Len: 1,
|
|
Chunk: strings.NewReader("a"),
|
|
},
|
|
Output: Output{
|
|
IndexMap: map[string]*fileidx.FileInfo{
|
|
DefaultId: &fileidx.FileInfo{
|
|
Id: DefaultId,
|
|
DownLimit: conf.MaxShares,
|
|
PathLocal: "path/filename",
|
|
State: fileidx.StateUploading,
|
|
Uploaded: 1,
|
|
},
|
|
},
|
|
Response: &ByteRange{
|
|
ShareId: DefaultId,
|
|
Start: 1,
|
|
Length: conf.MaxUpBytesPerSec,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, testCase := range testCases {
|
|
srv := initServiceForUploadTest(conf, testCase.Init.IndexMap)
|
|
|
|
response := srv.upload(
|
|
testCase.Input.ShareId,
|
|
testCase.Input.Start,
|
|
testCase.Input.Len,
|
|
testCase.Input.Chunk,
|
|
)
|
|
|
|
// TODO: not verified copyChunk
|
|
|
|
// verify index
|
|
if !sameMap(srv.Index.List(), testCase.Output.IndexMap) {
|
|
t.Fatalf("upload: index not identical got: %v want: %v", srv.Index.List(), testCase.Output.IndexMap)
|
|
}
|
|
// verify response
|
|
switch response.(type) {
|
|
case *ByteRange:
|
|
br := testCase.Output.Response.(*ByteRange)
|
|
res := response.(*ByteRange)
|
|
if res.ShareId != br.ShareId || res.Start != br.Start || res.Length != br.Length {
|
|
t.Fatalf(fmt.Sprintf("upload: response=%v expectRes=%v", res, br))
|
|
}
|
|
default:
|
|
if response != testCase.Output.Response {
|
|
t.Fatalf(fmt.Sprintf("upload: response=%v expectRes=%v", response, testCase.Output.Response))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestFinishUpload(t *testing.T) {
|
|
conf := cfg.NewConfig()
|
|
conf.Production = false
|
|
|
|
type Init struct {
|
|
IndexMap map[string]*fileidx.FileInfo
|
|
}
|
|
type Input struct {
|
|
ShareId string
|
|
Start int64
|
|
Len int64
|
|
Chunk io.Reader
|
|
}
|
|
type Output struct {
|
|
IndexMap map[string]*fileidx.FileInfo
|
|
Response interface{}
|
|
}
|
|
type testCase struct {
|
|
Desc string
|
|
Init
|
|
Input
|
|
Output
|
|
}
|
|
|
|
testCases := []testCase{
|
|
testCase{
|
|
Desc: "success",
|
|
Init: Init{
|
|
IndexMap: map[string]*fileidx.FileInfo{
|
|
DefaultId: &fileidx.FileInfo{
|
|
Id: DefaultId,
|
|
DownLimit: conf.MaxShares,
|
|
PathLocal: "path/filename",
|
|
State: fileidx.StateUploading,
|
|
Uploaded: 1,
|
|
},
|
|
},
|
|
},
|
|
Input: Input{
|
|
ShareId: DefaultId,
|
|
},
|
|
Output: Output{
|
|
IndexMap: map[string]*fileidx.FileInfo{
|
|
DefaultId: &fileidx.FileInfo{
|
|
Id: DefaultId,
|
|
DownLimit: conf.MaxShares,
|
|
PathLocal: "path/filename",
|
|
State: fileidx.StateDone,
|
|
Uploaded: 1,
|
|
},
|
|
},
|
|
Response: &ShareInfo{
|
|
ShareId: DefaultId,
|
|
},
|
|
},
|
|
},
|
|
testCase{
|
|
Desc: "shareId exists",
|
|
Init: Init{
|
|
IndexMap: map[string]*fileidx.FileInfo{},
|
|
},
|
|
Input: Input{
|
|
ShareId: DefaultId,
|
|
},
|
|
Output: Output{
|
|
IndexMap: map[string]*fileidx.FileInfo{},
|
|
Response: httputil.Err404,
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, testCase := range testCases {
|
|
srv := initServiceForUploadTest(conf, testCase.Init.IndexMap)
|
|
|
|
response := srv.finishUpload(testCase.ShareId)
|
|
|
|
if !sameMap(srv.Index.List(), testCase.Output.IndexMap) {
|
|
t.Fatalf("finishUpload: index not identical got: %v, want: %v", srv.Index.List(), testCase.Output.IndexMap)
|
|
}
|
|
|
|
switch res := response.(type) {
|
|
case httputil.MsgRes:
|
|
expectRes := testCase.Output.Response.(httputil.MsgRes)
|
|
if res != expectRes {
|
|
t.Fatalf(fmt.Sprintf("finishUpload: reponse=%v expectRes=%v", res, expectRes))
|
|
}
|
|
case *ShareInfo:
|
|
info, found := testCase.Output.IndexMap[res.ShareId]
|
|
if !found || info.State != fileidx.StateDone {
|
|
// TODO: should use isValidUrl or better to verify result
|
|
t.Fatalf(fmt.Sprintf("finishUpload: share info is not correct: received: %v expect: %v", res.ShareId, testCase.ShareId))
|
|
}
|
|
default:
|
|
t.Fatalf(fmt.Sprintf("finishUpload: type not found: %T %T", response, testCase.Output.Response))
|
|
}
|
|
}
|
|
}
|