mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-04 15:49:49 +00:00
828 lines
23 KiB
Go
828 lines
23 KiB
Go
package download
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/GopeedLab/gopeed/internal/fetcher"
|
|
"github.com/GopeedLab/gopeed/pkg/base"
|
|
)
|
|
|
|
var mockFetcherMeta = fetcher.FetcherMeta{
|
|
Req: &base.Request{
|
|
URL: "https://example.com/test.zip",
|
|
},
|
|
Opts: &base.Options{
|
|
Path: "/downloads",
|
|
},
|
|
Res: &base.Resource{
|
|
Size: 1024 * 1024,
|
|
Files: []*base.FileInfo{
|
|
{Name: "test.zip", Size: 1024 * 1024},
|
|
},
|
|
},
|
|
}
|
|
|
|
func TestWebhook_TriggerOnDone(t *testing.T) {
|
|
receivedData := make(chan *WebhookData, 1)
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPost {
|
|
t.Errorf("Expected POST request, got %s", r.Method)
|
|
}
|
|
if r.Header.Get("Content-Type") != "application/json" {
|
|
t.Errorf("Expected Content-Type application/json, got %s", r.Header.Get("Content-Type"))
|
|
}
|
|
var data WebhookData
|
|
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
|
|
t.Errorf("Failed to decode data: %v", err)
|
|
return
|
|
}
|
|
receivedData <- &data
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
defer server.Close()
|
|
|
|
setupWebhookTest(t, func(downloader *Downloader) {
|
|
// Configure webhook URLs
|
|
cfg, _ := downloader.GetConfig()
|
|
cfg.Webhook = &base.WebhookConfig{
|
|
Enable: true,
|
|
URLs: []string{server.URL},
|
|
}
|
|
downloader.PutConfig(cfg)
|
|
|
|
// Create a mock task
|
|
task := NewTask()
|
|
task.Protocol = "http"
|
|
task.Meta = &mockFetcherMeta
|
|
|
|
// Trigger webhook
|
|
downloader.triggerWebhooks(WebhookEventDownloadDone, task, nil)
|
|
|
|
select {
|
|
case data := <-receivedData:
|
|
if data.Event != WebhookEventDownloadDone {
|
|
t.Errorf("Expected event 'DOWNLOAD_DONE', got '%s'", data.Event)
|
|
}
|
|
if data.Payload == nil || data.Payload.Task == nil {
|
|
t.Error("Expected payload.task to be present")
|
|
} else if data.Payload.Task.ID != task.ID {
|
|
t.Errorf("Expected task ID '%s', got '%s'", task.ID, data.Payload.Task.ID)
|
|
}
|
|
if data.Time == 0 {
|
|
t.Error("Expected time to be set")
|
|
}
|
|
case <-time.After(2 * time.Second):
|
|
t.Error("Timeout waiting for webhook")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestWebhook_TriggerOnError(t *testing.T) {
|
|
receivedData := make(chan *WebhookData, 1)
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
var data WebhookData
|
|
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
|
|
t.Errorf("Failed to decode data: %v", err)
|
|
return
|
|
}
|
|
receivedData <- &data
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
defer server.Close()
|
|
|
|
setupWebhookTest(t, func(downloader *Downloader) {
|
|
// Configure webhook URLs
|
|
cfg, _ := downloader.GetConfig()
|
|
cfg.Webhook = &base.WebhookConfig{
|
|
Enable: true,
|
|
URLs: []string{server.URL},
|
|
}
|
|
downloader.PutConfig(cfg)
|
|
|
|
// Create a mock task
|
|
task := NewTask()
|
|
task.Protocol = "http"
|
|
task.Meta = &mockFetcherMeta
|
|
|
|
// Trigger webhook with error
|
|
testError := http.ErrServerClosed
|
|
downloader.triggerWebhooks(WebhookEventDownloadError, task, testError)
|
|
|
|
select {
|
|
case data := <-receivedData:
|
|
if data.Event != WebhookEventDownloadError {
|
|
t.Errorf("Expected event 'DOWNLOAD_ERROR', got '%s'", data.Event)
|
|
}
|
|
if data.Payload == nil || data.Payload.Task == nil {
|
|
t.Error("Expected payload.task to be present")
|
|
}
|
|
case <-time.After(2 * time.Second):
|
|
t.Error("Timeout waiting for webhook")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestWebhook_SendTestWebhook(t *testing.T) {
|
|
receivedData := make(chan *WebhookData, 1)
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
var data WebhookData
|
|
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
|
|
t.Errorf("Failed to decode data: %v", err)
|
|
return
|
|
}
|
|
receivedData <- &data
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
defer server.Close()
|
|
|
|
setupWebhookTest(t, func(downloader *Downloader) {
|
|
// Configure webhook URLs
|
|
cfg, _ := downloader.GetConfig()
|
|
cfg.Webhook = &base.WebhookConfig{
|
|
Enable: true,
|
|
URLs: []string{server.URL},
|
|
}
|
|
downloader.PutConfig(cfg)
|
|
|
|
// Send test webhook
|
|
err := downloader.SendTestWebhook()
|
|
if err != nil {
|
|
t.Errorf("SendTestWebhook failed: %v", err)
|
|
}
|
|
|
|
select {
|
|
case data := <-receivedData:
|
|
if data.Event != WebhookEventDownloadDone {
|
|
t.Errorf("Expected event 'DOWNLOAD_DONE', got '%s'", data.Event)
|
|
}
|
|
if data.Payload == nil || data.Payload.Task == nil {
|
|
t.Error("Expected payload.task to be present")
|
|
}
|
|
if data.Time == 0 {
|
|
t.Error("Expected time to be set")
|
|
}
|
|
case <-time.After(2 * time.Second):
|
|
t.Error("Timeout waiting for webhook")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestWebhook_NoWebhookConfigured(t *testing.T) {
|
|
setupWebhookTest(t, func(downloader *Downloader) {
|
|
// Create a mock task
|
|
task := NewTask()
|
|
task.Protocol = "http"
|
|
task.Meta = &mockFetcherMeta
|
|
|
|
// Trigger webhook (should not panic with no webhooks configured)
|
|
downloader.triggerWebhooks(WebhookEventDownloadDone, task, nil)
|
|
|
|
// Send test webhook (should not panic)
|
|
err := downloader.SendTestWebhook()
|
|
if err != nil {
|
|
t.Errorf("SendTestWebhook failed: %v", err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestWebhook_MultipleUrls(t *testing.T) {
|
|
count := 0
|
|
server1 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
count++
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
defer server1.Close()
|
|
server2 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
count++
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
defer server2.Close()
|
|
|
|
setupWebhookTest(t, func(downloader *Downloader) {
|
|
// Configure multiple webhook URLs
|
|
cfg, _ := downloader.GetConfig()
|
|
cfg.Webhook = &base.WebhookConfig{
|
|
Enable: true,
|
|
URLs: []string{server1.URL, server2.URL},
|
|
}
|
|
downloader.PutConfig(cfg)
|
|
|
|
// Create a mock task
|
|
task := NewTask()
|
|
task.Protocol = "http"
|
|
task.Meta = &mockFetcherMeta
|
|
|
|
// Trigger webhook
|
|
downloader.triggerWebhooks(WebhookEventDownloadDone, task, nil)
|
|
|
|
// Wait for webhooks
|
|
time.Sleep(500 * time.Millisecond)
|
|
|
|
if count != 2 {
|
|
t.Errorf("Expected 2 webhook calls, got %d", count)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestWebhook_TestWebhookFailsOnNon200(t *testing.T) {
|
|
// Test that SendTestWebhook returns error for non-200 status codes
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusInternalServerError) // 500
|
|
}))
|
|
defer server.Close()
|
|
|
|
setupWebhookTest(t, func(downloader *Downloader) {
|
|
// Configure webhook URLs
|
|
cfg, _ := downloader.GetConfig()
|
|
cfg.Webhook = &base.WebhookConfig{
|
|
Enable: true,
|
|
URLs: []string{server.URL},
|
|
}
|
|
downloader.PutConfig(cfg)
|
|
|
|
// Send test webhook - should fail with non-200 status
|
|
err := downloader.SendTestWebhook()
|
|
if err == nil {
|
|
t.Error("Expected SendTestWebhook to return error for non-200 status")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestWebhook_TestWebhookFailsOn201(t *testing.T) {
|
|
// Test that SendTestWebhook returns error for 201 (only 200 is success)
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusCreated) // 201
|
|
}))
|
|
defer server.Close()
|
|
|
|
setupWebhookTest(t, func(downloader *Downloader) {
|
|
// Configure webhook URLs
|
|
cfg, _ := downloader.GetConfig()
|
|
cfg.Webhook = &base.WebhookConfig{
|
|
Enable: true,
|
|
URLs: []string{server.URL},
|
|
}
|
|
downloader.PutConfig(cfg)
|
|
|
|
// Send test webhook - should fail with 201 status (only 200 is success)
|
|
err := downloader.SendTestWebhook()
|
|
if err == nil {
|
|
t.Error("Expected SendTestWebhook to return error for 201 status")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestWebhook_TestWebhookUrl(t *testing.T) {
|
|
receivedData := make(chan *WebhookData, 1)
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
var data WebhookData
|
|
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
|
|
t.Errorf("Failed to decode data: %v", err)
|
|
return
|
|
}
|
|
receivedData <- &data
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
defer server.Close()
|
|
|
|
setupWebhookTest(t, func(downloader *Downloader) {
|
|
// Test single URL
|
|
err := downloader.TestWebhookUrl(server.URL)
|
|
if err != nil {
|
|
t.Errorf("TestWebhookUrl failed: %v", err)
|
|
}
|
|
|
|
select {
|
|
case data := <-receivedData:
|
|
if data.Event != WebhookEventDownloadDone {
|
|
t.Errorf("Expected event 'DOWNLOAD_DONE', got '%s'", data.Event)
|
|
}
|
|
if data.Payload == nil || data.Payload.Task == nil {
|
|
t.Error("Expected payload.task to be present")
|
|
}
|
|
case <-time.After(2 * time.Second):
|
|
t.Error("Timeout waiting for webhook")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestWebhook_TestWebhookUrlEmpty(t *testing.T) {
|
|
setupWebhookTest(t, func(downloader *Downloader) {
|
|
// Test with empty URL - should return error
|
|
err := downloader.TestWebhookUrl("")
|
|
if err == nil {
|
|
t.Error("Expected TestWebhookUrl to return error for empty URL")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestWebhook_GetWebhookUrls_EmptyConfig(t *testing.T) {
|
|
setupWebhookTest(t, func(downloader *Downloader) {
|
|
urls := downloader.getWebhookUrls()
|
|
if urls != nil {
|
|
t.Errorf("Expected nil, got %v", urls)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestWebhook_GetWebhookUrls_NoExtraField(t *testing.T) {
|
|
setupWebhookTest(t, func(downloader *Downloader) {
|
|
cfg, _ := downloader.GetConfig()
|
|
cfg.Webhook = nil
|
|
downloader.PutConfig(cfg)
|
|
|
|
urls := downloader.getWebhookUrls()
|
|
if urls != nil {
|
|
t.Errorf("Expected nil, got %v", urls)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestWebhook_GetWebhookUrls_NoWebhookUrlsKey(t *testing.T) {
|
|
setupWebhookTest(t, func(downloader *Downloader) {
|
|
cfg, _ := downloader.GetConfig()
|
|
cfg.Webhook = &base.WebhookConfig{Enable: true} // No URLs set
|
|
downloader.PutConfig(cfg)
|
|
|
|
urls := downloader.getWebhookUrls()
|
|
if urls != nil {
|
|
t.Errorf("Expected nil, got %v", urls)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestWebhook_GetWebhookUrls_StringSlice(t *testing.T) {
|
|
setupWebhookTest(t, func(downloader *Downloader) {
|
|
cfg, _ := downloader.GetConfig()
|
|
cfg.Webhook = &base.WebhookConfig{
|
|
Enable: true,
|
|
URLs: []string{"http://example.com", "http://example2.com"},
|
|
}
|
|
downloader.PutConfig(cfg)
|
|
|
|
urls := downloader.getWebhookUrls()
|
|
if len(urls) != 2 {
|
|
t.Errorf("Expected 2 URLs, got %d", len(urls))
|
|
}
|
|
if urls[0] != "http://example.com" || urls[1] != "http://example2.com" {
|
|
t.Errorf("URLs don't match expected values: %v", urls)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestWebhook_GetWebhookUrls_InterfaceSlice(t *testing.T) {
|
|
setupWebhookTest(t, func(downloader *Downloader) {
|
|
cfg, _ := downloader.GetConfig()
|
|
cfg.Webhook = &base.WebhookConfig{
|
|
Enable: true,
|
|
URLs: []string{"http://example.com", "http://example2.com"},
|
|
}
|
|
downloader.PutConfig(cfg)
|
|
|
|
urls := downloader.getWebhookUrls()
|
|
if len(urls) != 2 {
|
|
t.Errorf("Expected 2 URLs, got %d", len(urls))
|
|
}
|
|
if urls[0] != "http://example.com" || urls[1] != "http://example2.com" {
|
|
t.Errorf("URLs don't match expected values: %v", urls)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestWebhook_GetWebhookUrls_EmptyStringSlice(t *testing.T) {
|
|
setupWebhookTest(t, func(downloader *Downloader) {
|
|
cfg, _ := downloader.GetConfig()
|
|
cfg.Extra = make(map[string]any)
|
|
cfg.Webhook.URLs = []string{}
|
|
downloader.PutConfig(cfg)
|
|
|
|
urls := downloader.getWebhookUrls()
|
|
if urls != nil {
|
|
t.Errorf("Expected nil, got %v", urls)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestWebhook_GetWebhookUrls_InterfaceSliceWithEmptyStrings(t *testing.T) {
|
|
setupWebhookTest(t, func(downloader *Downloader) {
|
|
cfg, _ := downloader.GetConfig()
|
|
cfg.Webhook = &base.WebhookConfig{
|
|
Enable: true,
|
|
URLs: []string{"", "", ""},
|
|
}
|
|
downloader.PutConfig(cfg)
|
|
|
|
urls := downloader.getWebhookUrls()
|
|
if urls != nil {
|
|
t.Errorf("Expected nil for all empty strings, got %v", urls)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestWebhook_GetWebhookUrls_InterfaceSliceMixedTypes(t *testing.T) {
|
|
setupWebhookTest(t, func(downloader *Downloader) {
|
|
cfg, _ := downloader.GetConfig()
|
|
cfg.Webhook = &base.WebhookConfig{
|
|
Enable: true,
|
|
URLs: []string{"http://example.com", "", "http://example2.com", ""},
|
|
}
|
|
downloader.PutConfig(cfg)
|
|
|
|
urls := downloader.getWebhookUrls()
|
|
if len(urls) != 2 {
|
|
t.Errorf("Expected 2 valid URLs (ignoring empty strings), got %d: %v", len(urls), urls)
|
|
}
|
|
if urls[0] != "http://example.com" || urls[1] != "http://example2.com" {
|
|
t.Errorf("URLs don't match expected values: %v", urls)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestWebhook_GetWebhookUrls_InvalidType(t *testing.T) {
|
|
setupWebhookTest(t, func(downloader *Downloader) {
|
|
cfg, _ := downloader.GetConfig()
|
|
cfg.Webhook = &base.WebhookConfig{Enable: false} // Disabled webhook
|
|
downloader.PutConfig(cfg)
|
|
|
|
urls := downloader.getWebhookUrls()
|
|
if urls != nil {
|
|
t.Errorf("Expected nil for disabled webhook, got %v", urls)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestWebhook_GetWebhookUrls_DisabledWebhook(t *testing.T) {
|
|
setupWebhookTest(t, func(downloader *Downloader) {
|
|
cfg, _ := downloader.GetConfig()
|
|
cfg.Webhook = &base.WebhookConfig{
|
|
Enable: false,
|
|
URLs: []string{"http://example.com"},
|
|
}
|
|
downloader.PutConfig(cfg)
|
|
|
|
urls := downloader.getWebhookUrls()
|
|
if urls != nil {
|
|
t.Errorf("Expected nil for disabled webhook even with URLs, got %v", urls)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestWebhook_SendWebhookToUrl_Success(t *testing.T) {
|
|
receivedData := make(chan *WebhookData, 1)
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
// Verify headers
|
|
if r.Header.Get("Content-Type") != "application/json" {
|
|
t.Errorf("Expected Content-Type application/json, got %s", r.Header.Get("Content-Type"))
|
|
}
|
|
if r.Header.Get("User-Agent") != "Gopeed-Webhook/1.0" {
|
|
t.Errorf("Expected User-Agent Gopeed-Webhook/1.0, got %s", r.Header.Get("User-Agent"))
|
|
}
|
|
|
|
var data WebhookData
|
|
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
|
|
t.Errorf("Failed to decode data: %v", err)
|
|
return
|
|
}
|
|
receivedData <- &data
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
defer server.Close()
|
|
|
|
setupWebhookTest(t, func(downloader *Downloader) {
|
|
task := NewTask()
|
|
task.Protocol = "http"
|
|
task.Meta = &mockFetcherMeta
|
|
|
|
data := &WebhookData{
|
|
Event: WebhookEventDownloadDone,
|
|
Time: time.Now().UnixMilli(),
|
|
Payload: &WebhookPayload{
|
|
Task: task,
|
|
},
|
|
}
|
|
|
|
statusCode, err := downloader.sendWebhookToUrl(server.URL, data)
|
|
if err != nil {
|
|
t.Errorf("sendWebhookToUrl failed: %v", err)
|
|
}
|
|
if statusCode != http.StatusOK {
|
|
t.Errorf("Expected status 200, got %d", statusCode)
|
|
}
|
|
|
|
select {
|
|
case received := <-receivedData:
|
|
if received.Event != WebhookEventDownloadDone {
|
|
t.Errorf("Expected event DOWNLOAD_DONE, got %s", received.Event)
|
|
}
|
|
case <-time.After(1 * time.Second):
|
|
t.Error("Timeout waiting for webhook")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestWebhook_SendWebhookToUrl_EmptyUrl(t *testing.T) {
|
|
setupWebhookTest(t, func(downloader *Downloader) {
|
|
data := &WebhookData{
|
|
Event: WebhookEventDownloadDone,
|
|
Time: time.Now().UnixMilli(),
|
|
}
|
|
|
|
_, err := downloader.sendWebhookToUrl("", data)
|
|
if err == nil {
|
|
t.Error("Expected error for empty URL")
|
|
}
|
|
if err.Error() != "webhook URL is empty" {
|
|
t.Errorf("Expected 'webhook URL is empty' error, got: %v", err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestWebhook_SendWebhookToUrl_InvalidUrl(t *testing.T) {
|
|
setupWebhookTest(t, func(downloader *Downloader) {
|
|
data := &WebhookData{
|
|
Event: WebhookEventDownloadDone,
|
|
Time: time.Now().UnixMilli(),
|
|
}
|
|
|
|
_, err := downloader.sendWebhookToUrl("://invalid-url", data)
|
|
if err == nil {
|
|
t.Error("Expected error for invalid URL")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestWebhook_SendWebhookToUrl_NonExistentHost(t *testing.T) {
|
|
setupWebhookTest(t, func(downloader *Downloader) {
|
|
data := &WebhookData{
|
|
Event: WebhookEventDownloadDone,
|
|
Time: time.Now().UnixMilli(),
|
|
}
|
|
|
|
_, err := downloader.sendWebhookToUrl("http://non-existent-host-12345.example", data)
|
|
if err == nil {
|
|
t.Error("Expected error for non-existent host")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestWebhook_SendWebhookToUrl_Timeout(t *testing.T) {
|
|
// Create a server that delays response beyond webhook timeout
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
time.Sleep(15 * time.Second) // Longer than webhookTimeout (10s)
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
defer server.Close()
|
|
|
|
setupWebhookTest(t, func(downloader *Downloader) {
|
|
data := &WebhookData{
|
|
Event: WebhookEventDownloadDone,
|
|
Time: time.Now().UnixMilli(),
|
|
}
|
|
|
|
_, err := downloader.sendWebhookToUrl(server.URL, data)
|
|
if err == nil {
|
|
t.Error("Expected timeout error")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestWebhook_SendWebhookToUrl_VariousStatusCodes(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
statusCode int
|
|
}{
|
|
{"200 OK", http.StatusOK},
|
|
{"201 Created", http.StatusCreated},
|
|
{"204 No Content", http.StatusNoContent},
|
|
{"400 Bad Request", http.StatusBadRequest},
|
|
{"404 Not Found", http.StatusNotFound},
|
|
{"500 Internal Server Error", http.StatusInternalServerError},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(tc.statusCode)
|
|
}))
|
|
defer server.Close()
|
|
|
|
setupWebhookTest(t, func(downloader *Downloader) {
|
|
data := &WebhookData{
|
|
Event: WebhookEventDownloadDone,
|
|
Time: time.Now().UnixMilli(),
|
|
}
|
|
|
|
statusCode, err := downloader.sendWebhookToUrl(server.URL, data)
|
|
if err != nil {
|
|
t.Errorf("sendWebhookToUrl failed: %v", err)
|
|
}
|
|
if statusCode != tc.statusCode {
|
|
t.Errorf("Expected status %d, got %d", tc.statusCode, statusCode)
|
|
}
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestWebhook_TriggerWebhooks_EmptyUrlSkipped(t *testing.T) {
|
|
requestCount := 0
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
requestCount++
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
defer server.Close()
|
|
|
|
setupWebhookTest(t, func(downloader *Downloader) {
|
|
cfg, _ := downloader.GetConfig()
|
|
cfg.Webhook = &base.WebhookConfig{
|
|
Enable: true,
|
|
URLs: []string{server.URL, "", server.URL},
|
|
}
|
|
downloader.PutConfig(cfg)
|
|
|
|
task := NewTask()
|
|
task.Protocol = "http"
|
|
task.Meta = &mockFetcherMeta
|
|
|
|
downloader.triggerWebhooks(WebhookEventDownloadDone, task, nil)
|
|
|
|
time.Sleep(500 * time.Millisecond)
|
|
|
|
if requestCount != 2 {
|
|
t.Errorf("Expected 2 requests (empty URL should be skipped), got %d", requestCount)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestWebhook_WebhookDataStructure(t *testing.T) {
|
|
receivedData := make(chan *WebhookData, 1)
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
var data WebhookData
|
|
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
|
|
t.Errorf("Failed to decode data: %v", err)
|
|
return
|
|
}
|
|
receivedData <- &data
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
defer server.Close()
|
|
|
|
setupWebhookTest(t, func(downloader *Downloader) {
|
|
cfg, _ := downloader.GetConfig()
|
|
cfg.Webhook = &base.WebhookConfig{
|
|
Enable: true,
|
|
URLs: []string{server.URL},
|
|
}
|
|
downloader.PutConfig(cfg)
|
|
|
|
task := NewTask()
|
|
task.Protocol = "http"
|
|
task.Status = base.DownloadStatusDone
|
|
task.Meta = &mockFetcherMeta
|
|
|
|
downloader.triggerWebhooks(WebhookEventDownloadDone, task, nil)
|
|
|
|
select {
|
|
case data := <-receivedData:
|
|
// Verify event
|
|
if data.Event != WebhookEventDownloadDone {
|
|
t.Errorf("Expected event DOWNLOAD_DONE, got %s", data.Event)
|
|
}
|
|
// Verify time is set
|
|
if data.Time == 0 {
|
|
t.Error("Expected time to be set")
|
|
}
|
|
// Verify payload
|
|
if data.Payload == nil {
|
|
t.Error("Expected payload to be present")
|
|
}
|
|
if data.Payload.Task == nil {
|
|
t.Error("Expected task in payload to be present")
|
|
}
|
|
// Verify task is cloned (has same ID but different pointer)
|
|
if data.Payload.Task.ID != task.ID {
|
|
t.Errorf("Expected task ID %s, got %s", task.ID, data.Payload.Task.ID)
|
|
}
|
|
case <-time.After(2 * time.Second):
|
|
t.Error("Timeout waiting for webhook")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestWebhook_SendTestWebhook_EmptyUrls(t *testing.T) {
|
|
setupWebhookTest(t, func(downloader *Downloader) {
|
|
cfg, _ := downloader.GetConfig()
|
|
cfg.Extra = make(map[string]any)
|
|
cfg.Webhook.URLs = []string{}
|
|
downloader.PutConfig(cfg)
|
|
|
|
err := downloader.SendTestWebhook()
|
|
if err != nil {
|
|
t.Errorf("Expected no error for empty URLs, got: %v", err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestWebhook_SendTestWebhook_MixedResults(t *testing.T) {
|
|
// First server returns 200
|
|
server1 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
defer server1.Close()
|
|
|
|
// Second server returns 500
|
|
server2 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
}))
|
|
defer server2.Close()
|
|
|
|
setupWebhookTest(t, func(downloader *Downloader) {
|
|
cfg, _ := downloader.GetConfig()
|
|
cfg.Webhook = &base.WebhookConfig{
|
|
Enable: true,
|
|
URLs: []string{server1.URL, server2.URL},
|
|
}
|
|
downloader.PutConfig(cfg)
|
|
|
|
// Should fail because server2 returns 500
|
|
err := downloader.SendTestWebhook()
|
|
if err == nil {
|
|
t.Error("Expected error when one server returns non-200 status")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestWebhook_TestWebhookUrl_InvalidUrl(t *testing.T) {
|
|
setupWebhookTest(t, func(downloader *Downloader) {
|
|
err := downloader.TestWebhookUrl("://invalid")
|
|
if err == nil {
|
|
t.Error("Expected error for invalid URL")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestWebhook_TestWebhookUrl_VerifyTestPayload(t *testing.T) {
|
|
receivedData := make(chan *WebhookData, 1)
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
var data WebhookData
|
|
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
|
|
t.Errorf("Failed to decode data: %v", err)
|
|
return
|
|
}
|
|
receivedData <- &data
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
defer server.Close()
|
|
|
|
setupWebhookTest(t, func(downloader *Downloader) {
|
|
err := downloader.TestWebhookUrl(server.URL)
|
|
if err != nil {
|
|
t.Errorf("TestWebhookUrl failed: %v", err)
|
|
}
|
|
|
|
select {
|
|
case data := <-receivedData:
|
|
// Verify it's a test webhook
|
|
if data.Event != WebhookEventDownloadDone {
|
|
t.Errorf("Expected event DOWNLOAD_DONE, got %s", data.Event)
|
|
}
|
|
if data.Payload == nil || data.Payload.Task == nil {
|
|
t.Error("Expected payload with task")
|
|
}
|
|
// Verify test task properties
|
|
task := data.Payload.Task
|
|
if task.Protocol != "http" {
|
|
t.Errorf("Expected protocol 'http', got '%s'", task.Protocol)
|
|
}
|
|
if task.Status != base.DownloadStatusDone {
|
|
t.Errorf("Expected status Done, got %s", task.Status)
|
|
}
|
|
if task.Meta == nil || task.Meta.Req == nil {
|
|
t.Error("Expected meta and request in test task")
|
|
}
|
|
if task.Meta.Req.URL != "https://example.com/test-file.zip" {
|
|
t.Errorf("Expected test URL, got %s", task.Meta.Req.URL)
|
|
}
|
|
case <-time.After(2 * time.Second):
|
|
t.Error("Timeout waiting for webhook")
|
|
}
|
|
})
|
|
}
|
|
|
|
func setupWebhookTest(t *testing.T, fn func(downloader *Downloader)) {
|
|
defaultDownloader.Setup()
|
|
defaultDownloader.cfg.StorageDir = ".test_storage"
|
|
defaultDownloader.cfg.DownloadDir = ".test_download"
|
|
defer func() {
|
|
defaultDownloader.Clear()
|
|
os.RemoveAll(defaultDownloader.cfg.StorageDir)
|
|
os.RemoveAll(defaultDownloader.cfg.DownloadDir)
|
|
}()
|
|
fn(defaultDownloader)
|
|
}
|