90 lines
2.6 KiB
Go
90 lines
2.6 KiB
Go
package downloader
|
|
|
|
import (
|
|
"errors"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
func TestTaskValidateAndDerivedPaths(t *testing.T) {
|
|
task := validTaskForTest()
|
|
if err := task.Validate(); err != nil {
|
|
t.Fatalf("Validate() error = %v", err)
|
|
}
|
|
paths, err := DeriveTaskPaths(filepath.Join(t.TempDir(), "downloads"), task.RequestID)
|
|
if err != nil {
|
|
t.Fatalf("DeriveTaskPaths() error = %v", err)
|
|
}
|
|
for _, path := range []string{
|
|
paths.Metadata,
|
|
paths.Backup,
|
|
paths.Part,
|
|
paths.Completed,
|
|
} {
|
|
relative, err := filepath.Rel(paths.Root, path)
|
|
if err != nil || relative == ".." {
|
|
t.Fatalf("derived path escapes root: %s", path)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTaskRejectsInvalidFields(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
mutate func(*Task)
|
|
}{
|
|
{name: "request id", mutate: func(task *Task) { task.RequestID = "../escape" }},
|
|
{name: "app id", mutate: func(task *Task) { task.AppID = "Bad App" }},
|
|
{name: "URL", mutate: func(task *Task) { task.URL = "http://example.invalid/app.zip" }},
|
|
{name: "state", mutate: func(task *Task) { task.Status = "unknown" }},
|
|
{name: "negative done", mutate: func(task *Task) { task.Done = -1 }},
|
|
{name: "done exceeds total", mutate: func(task *Task) { task.Done = task.Total + 1 }},
|
|
{name: "unknown total value", mutate: func(task *Task) {
|
|
task.TotalKnown = false
|
|
task.Total = 10
|
|
}},
|
|
{name: "weak etag", mutate: func(task *Task) {
|
|
task.Validator = EntityValidator{ETag: `W/"weak"`}
|
|
}},
|
|
{name: "failed without code", mutate: func(task *Task) {
|
|
task.Status = StatusFailed
|
|
task.ErrorCode = ""
|
|
}},
|
|
}
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
task := validTaskForTest()
|
|
test.mutate(&task)
|
|
if err := task.Validate(); !errors.Is(err, ErrInvalidTask) {
|
|
t.Fatalf("Validate() error = %v, want %v", err, ErrInvalidTask)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestValidatorsMatchRejectsDifferentKinds(t *testing.T) {
|
|
expected := EntityValidator{ETag: `"v1"`}
|
|
if validatorsMatch(expected, EntityValidator{LastModified: "Wed, 16 Jul 2026 10:00:00 GMT"}) {
|
|
t.Fatal("ETag unexpectedly matched Last-Modified")
|
|
}
|
|
if validatorsMatch(expected, EntityValidator{ETag: `"v2"`}) {
|
|
t.Fatal("different ETags matched")
|
|
}
|
|
if !validatorsMatch(expected, EntityValidator{}) {
|
|
t.Fatal("absent response validator should not contradict If-Range")
|
|
}
|
|
}
|
|
|
|
func validTaskForTest() Task {
|
|
return Task{
|
|
SchemaVersion: TaskSchemaVersion,
|
|
RequestID: "request-001",
|
|
AppID: "json-parser",
|
|
URL: "https://download.invalid/json-parser.zip",
|
|
Status: StatusQueued,
|
|
TotalKnown: true,
|
|
Total: 42,
|
|
CreatedAt: "2026-07-16T00:00:00Z",
|
|
}
|
|
}
|