mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-04 08:10:55 +00:00
189 lines
7.8 KiB
Go
189 lines
7.8 KiB
Go
package download
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"testing"
|
|
|
|
"github.com/GopeedLab/gopeed/internal/fetcher"
|
|
"github.com/GopeedLab/gopeed/pkg/base"
|
|
btProtocol "github.com/GopeedLab/gopeed/pkg/protocol/bt"
|
|
httpProtocol "github.com/GopeedLab/gopeed/pkg/protocol/http"
|
|
"github.com/dop251/goja"
|
|
)
|
|
|
|
func TestExtensionProtocolMethods(t *testing.T) {
|
|
for _, extra := range []any{nil, map[string]any{"header": map[string]any{"Keep": "yes"}}, &httpProtocol.ReqExtra{Header: map[string]string{"Keep": "yes"}}} {
|
|
vm := goja.New()
|
|
vm.SetFieldNameMapper(goja.TagFieldNameMapper("json", true))
|
|
req := &base.Request{Extra: extra}
|
|
task := &Task{Protocol: "http", Meta: &fetcher.FetcherMeta{Req: req, Opts: &base.Options{}}}
|
|
if err := vm.Set("task", newOnStartExtensionTask(task)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
_, err := vm.RunString(`task.meta.req.setMethod('POST'); task.meta.req.setBody('payload'); task.meta.req.putHeader('Authorization','Bearer token'); task.meta.req.putHeader('Remove','remove'); task.meta.req.delHeader('REMOVE');`)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := base.ParseReqExtra[httpProtocol.ReqExtra](req); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got := req.Extra.(*httpProtocol.ReqExtra)
|
|
if got.Method != "POST" || got.Body != "payload" || got.Header["Authorization"] != "Bearer token" {
|
|
t.Fatalf("mutation not applied: %#v", got)
|
|
}
|
|
if _, ok := got.Header["Remove"]; ok {
|
|
t.Fatal("header deletion failed")
|
|
}
|
|
if extra != nil && got.Header["Keep"] != "yes" {
|
|
t.Fatal("existing header lost")
|
|
}
|
|
}
|
|
vm := goja.New()
|
|
vm.SetFieldNameMapper(goja.TagFieldNameMapper("json", true))
|
|
req := &base.Request{Extra: &btProtocol.ReqExtra{Trackers: []string{"old"}}}
|
|
task := &Task{Protocol: "bt", Meta: &fetcher.FetcherMeta{Req: req, Opts: &base.Options{}}}
|
|
if err := vm.Set("task", newOnStartExtensionTask(task)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := vm.RunString(`task.meta.req.setTrackers(['new','another']);`); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got := req.Extra.(*btProtocol.ReqExtra).Trackers
|
|
if len(got) != 2 || got[0] != "new" || got[1] != "another" {
|
|
t.Fatalf("trackers = %#v", got)
|
|
}
|
|
}
|
|
|
|
func TestExtensionProtocolMethodsRejectInvalidMutation(t *testing.T) {
|
|
vm := goja.New()
|
|
vm.SetFieldNameMapper(goja.TagFieldNameMapper("json", true))
|
|
original := &httpProtocol.ReqExtra{Method: "POST", Header: map[string]string{"authorization": "old", "Keep": "yes"}}
|
|
req := &base.Request{Extra: original}
|
|
task := newOnStartExtensionTask(&Task{Protocol: "http", Meta: &fetcher.FetcherMeta{Req: req, Opts: &base.Options{}}})
|
|
if err := vm.Set("task", task); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, script := range []string{`task.meta.req.setHeaders({Keep:null})`, `task.meta.req.setHeaders({Keep:123})`, `task.meta.req.setHeaders({a:'1',A:'2'})`} {
|
|
if _, err := vm.RunString(script); err == nil {
|
|
t.Fatalf("accepted invalid mutation: %s", script)
|
|
}
|
|
if req.Extra != original || original.Header["Keep"] != "yes" {
|
|
t.Fatal("invalid operation changed original extra")
|
|
}
|
|
}
|
|
if _, err := vm.RunString(`task.meta.req.putHeader('Authorization','new');`); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got := req.Extra.(*httpProtocol.ReqExtra)
|
|
if len(got.Header) != 2 || got.Header["Authorization"] != "new" || original.Header["authorization"] != "old" {
|
|
t.Fatalf("header update = %#v", got.Header)
|
|
}
|
|
if _, err := vm.RunString(`task.meta.req.setHeaders({Only:'one'});`); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got = req.Extra.(*httpProtocol.ReqExtra)
|
|
if got.Method != "POST" || len(got.Header) != 1 {
|
|
t.Fatalf("setHeaders = %#v", got)
|
|
}
|
|
req.Extra = map[string]any{"header": 123}
|
|
if _, err := vm.RunString(`task.meta.req.setBody('new')`); err == nil {
|
|
t.Fatal("invalid protocol extra accepted")
|
|
}
|
|
if req.Extra.(map[string]any)["header"] != 123 {
|
|
t.Fatal("conversion failure mutated extra")
|
|
}
|
|
}
|
|
|
|
func TestExtensionProtocolMethodsOtherProtocolsAreNoOp(t *testing.T) {
|
|
for _, protocol := range []string{"http", "bt", "hls"} {
|
|
for _, onError := range []bool{false, true} {
|
|
t.Run(fmt.Sprintf("%s/onError=%v", protocol, onError), func(t *testing.T) {
|
|
vm := goja.New()
|
|
vm.SetFieldNameMapper(goja.TagFieldNameMapper("json", true))
|
|
// An invalid extra proves that unrelated methods skip conversion entirely.
|
|
original := map[string]any{"unchanged": true, "header": 123}
|
|
req := &base.Request{Extra: original}
|
|
task := &Task{Protocol: protocol, Meta: &fetcher.FetcherMeta{Req: req, Opts: &base.Options{}}}
|
|
var wrapper any = newOnStartExtensionTask(task)
|
|
if onError {
|
|
wrapper = newOnErrorExtensionTask(nil, task)
|
|
}
|
|
if err := vm.Set("task", wrapper); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if protocol != "http" {
|
|
if _, err := vm.RunString(`task.meta.req.setMethod('POST');task.meta.req.setBody('body');task.meta.req.setHeaders({a:null});task.meta.req.putHeader('A','value');task.meta.req.delHeader('A');`); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
if protocol != "bt" {
|
|
if _, err := vm.RunString(`task.meta.req.setTrackers(['udp://example.com']);`); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
if !reflect.DeepEqual(req.Extra, original) {
|
|
t.Fatalf("extra changed: %#v", req.Extra)
|
|
}
|
|
original["same-object"] = true
|
|
if req.Extra.(map[string]any)["same-object"] != true {
|
|
t.Fatal("no-op replaced extra")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestExtensionOnErrorRequestWritesToOriginalTask(t *testing.T) {
|
|
vm := goja.New()
|
|
vm.SetFieldNameMapper(goja.TagFieldNameMapper("json", true))
|
|
req := &base.Request{URL: "https://example.com", Extra: &httpProtocol.ReqExtra{Header: map[string]string{"Keep": "yes"}}}
|
|
task := &Task{Protocol: "http", Meta: &fetcher.FetcherMeta{Req: req, Opts: &base.Options{}}}
|
|
if err := vm.Set("task", newOnErrorExtensionTask(nil, task)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := vm.RunString(`
|
|
if (typeof task.continue !== 'function') throw new Error('missing continue');
|
|
if (typeof task.putHeader !== 'undefined') throw new Error('task still exposes protocol methods');
|
|
if (typeof task.req !== 'undefined') throw new Error('legacy task.req');
|
|
const request = task.meta.req;
|
|
if (request.url !== 'https://example.com' || request.extra.header.Keep !== 'yes') throw new Error('request data missing');
|
|
if (!task.meta.opts) throw new Error('metadata fields missing');
|
|
request.setHeaders({Keep:'new'});
|
|
request.putHeader('Authorization','Bearer new');
|
|
request.setMethod('POST');
|
|
if (typeof task.setUrl !== 'function' || typeof task.extra !== 'undefined') throw new Error('unexpected legacy task API');
|
|
request.setUrl('https://example.com/new');
|
|
request.setLabels({keep:'yes',remove:'yes'});
|
|
request.putLabel('new','value');
|
|
request.delLabel('remove');
|
|
if (request.url !== 'https://example.com/new' || request.labels.new !== 'value' || request.extra.method !== 'POST' || request.extra.header.Authorization !== 'Bearer new') throw new Error('request data did not refresh');
|
|
`); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !reflect.DeepEqual(req.Labels, map[string]string{"keep": "yes", "new": "value"}) {
|
|
t.Fatalf("labels = %#v", req.Labels)
|
|
}
|
|
got := req.Extra.(*httpProtocol.ReqExtra)
|
|
if got.Method != "POST" || got.Header["Keep"] != "new" || got.Header["Authorization"] != "Bearer new" || req.URL != "https://example.com/new" {
|
|
t.Fatalf("original request not updated: %#v, %#v", req, got)
|
|
}
|
|
}
|
|
|
|
func TestExtensionBTRequestInitializesNilExtra(t *testing.T) {
|
|
vm := goja.New()
|
|
vm.SetFieldNameMapper(goja.TagFieldNameMapper("json", true))
|
|
req := &base.Request{}
|
|
task := &Task{Protocol: "bt", Meta: &fetcher.FetcherMeta{Req: req, Opts: &base.Options{}}}
|
|
if err := vm.Set("task", newOnStartExtensionTask(task)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := vm.RunString(`task.meta.req.setTrackers(['udp://example.com']);`); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, ok := req.Extra.(*btProtocol.ReqExtra)
|
|
if !ok || !reflect.DeepEqual(got.Trackers, []string{"udp://example.com"}) {
|
|
t.Fatalf("extra = %#v", req.Extra)
|
|
}
|
|
}
|