mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-07 17:10:29 +00:00
151 lines
4.5 KiB
Go
151 lines
4.5 KiB
Go
package download
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/GopeedLab/gopeed/pkg/base"
|
|
media "github.com/GopeedLab/gopeed/pkg/download/engine/ffmpeg"
|
|
)
|
|
|
|
func TestQueuedMergeReportsInputProgress(t *testing.T) {
|
|
for _, mode := range []string{"streams", "http"} {
|
|
t.Run(mode, func(t *testing.T) {
|
|
release1, err := media.Acquire(context.Background())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer release1()
|
|
release2, err := media.Acquire(context.Background())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer release2()
|
|
video, err := os.ReadFile("engine/testdata/ffmpeg/video.mp4")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
audio, err := os.ReadFile("engine/testdata/ffmpeg/audio.mp4")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
b := video
|
|
if r.URL.Path == "/audio" {
|
|
b = audio
|
|
}
|
|
http.ServeContent(w, r, "media", time.Time{}, bytes.NewReader(b))
|
|
}))
|
|
defer server.Close()
|
|
d := NewDownloader(&DownloaderConfig{Storage: NewMemStorage(), StorageDir: t.TempDir(), TempDir: t.TempDir(), RefreshInterval: 50})
|
|
if err := d.Setup(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer d.Clear()
|
|
e, _ := d.newExtensionEngine()
|
|
defer e.Close()
|
|
e.Runtime.Set("videoBytes", e.Runtime.NewArrayBuffer(video))
|
|
e.Runtime.Set("audioBytes", e.Runtime.NewArrayBuffer(audio))
|
|
e.Runtime.Set("mode", mode)
|
|
e.Runtime.Set("sourceURL", server.URL)
|
|
result, err := e.RunString(`__gopeed_blob_create_object_url(()=>{
|
|
const source=b=>new ReadableStream({start(c){c.enqueue(new Uint8Array(b));c.close();}});
|
|
return __gopeed_ffmpeg.merge(mode==='http'?{video:{url:sourceURL+'/video'},audio:{url:sourceURL+'/audio'}}:
|
|
{inputs:()=>({video:source(videoBytes),audio:source(audioBytes)})});
|
|
},{contentType:'video/mp4'})`)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
output := t.TempDir()
|
|
id, err := d.CreateDirect(&base.Request{URL: fmt.Sprint(result)}, &base.Options{Path: output, Name: "merged.mp4"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
deadline := time.Now().Add(5 * time.Second)
|
|
for {
|
|
task := d.GetTask(id)
|
|
task.lock.Lock()
|
|
task.statusLock.Lock()
|
|
status, downloaded := task.Status, task.Progress.Downloaded
|
|
total := int64(0)
|
|
if task.Meta.Res != nil {
|
|
total = task.Meta.Res.Size
|
|
}
|
|
task.statusLock.Unlock()
|
|
task.lock.Unlock()
|
|
if downloaded == int64(len(video)+len(audio)) {
|
|
if status != base.DownloadStatusRunning || total != 0 {
|
|
t.Fatalf("queued task: status=%v total=%d", status, total)
|
|
}
|
|
break
|
|
}
|
|
if time.Now().After(deadline) {
|
|
t.Fatalf("input progress not reported: status=%v bytes=%d", status, downloaded)
|
|
}
|
|
time.Sleep(20 * time.Millisecond)
|
|
}
|
|
task := d.GetTask(id)
|
|
if mode == "streams" {
|
|
time.Sleep(16 * time.Second)
|
|
} else {
|
|
time.Sleep(200 * time.Millisecond)
|
|
}
|
|
task.lock.Lock()
|
|
task.statusLock.Lock()
|
|
speed := task.Progress.Speed
|
|
task.statusLock.Unlock()
|
|
task.lock.Unlock()
|
|
// Once the upstream is drained, waiting for FFmpeg is still a running task.
|
|
if speed < 0 || (mode == "streams" && speed != 0) {
|
|
t.Fatal("negative queued speed", speed)
|
|
}
|
|
release1()
|
|
deadline = time.Now().Add(100 * time.Second)
|
|
for d.taskStatus(task) != base.DownloadStatusDone {
|
|
if time.Now().After(deadline) {
|
|
t.Fatal("merge did not complete")
|
|
}
|
|
time.Sleep(20 * time.Millisecond)
|
|
}
|
|
// Done is published before extension hooks finish. Let the watcher
|
|
// release its Blob/session before tearing down the downloader.
|
|
deadline = time.Now().Add(5 * time.Second)
|
|
for {
|
|
if _, active := d.watchedTasks.Load(id); !active {
|
|
break
|
|
}
|
|
if time.Now().After(deadline) {
|
|
t.Fatal("completion hooks did not finish")
|
|
}
|
|
time.Sleep(10 * time.Millisecond)
|
|
}
|
|
body, err := os.ReadFile(filepath.Join(output, "merged.mp4"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !bytes.Contains(body, []byte("moof")) {
|
|
t.Fatal("invalid merged output")
|
|
}
|
|
task.lock.Lock()
|
|
task.statusLock.Lock()
|
|
downloaded, total := task.Progress.Downloaded, task.Meta.Res.Size
|
|
task.statusLock.Unlock()
|
|
task.lock.Unlock()
|
|
if downloaded != int64(len(body)) || total != int64(len(body)) {
|
|
t.Fatal("completion did not use output size", downloaded, total, len(body))
|
|
}
|
|
files, err := os.ReadDir(d.cfg.TempDir)
|
|
if err != nil || len(files) != 0 {
|
|
t.Fatal("temporary media leaked", files, err)
|
|
}
|
|
})
|
|
}
|
|
}
|