Scout/internal/httpapi/server_test.go
2026-08-31 15:59:52 +08:00

172 lines
4.8 KiB
Go

package httpapi
import (
"bytes"
"encoding/json"
"io"
"mime/multipart"
"net/http"
"net/http/httptest"
"net/url"
"os"
"path/filepath"
"testing"
"time"
"scout/internal/registry"
)
func TestUploadListLatestAndDownload(t *testing.T) {
store, err := registry.New(t.TempDir())
if err != nil {
t.Fatal(err)
}
server := httptest.NewServer((&Server{Registry: store, DeveloperToken: "测试令牌"}).Handler())
defer server.Close()
unauthorized, err := http.Post(server.URL+"/api/v1/packages/upload", "application/json", nil)
if err != nil {
t.Fatal(err)
}
if unauthorized.StatusCode != http.StatusUnauthorized {
t.Fatalf("未授权状态错误: %d", unauthorized.StatusCode)
}
unauthorized.Body.Close()
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
_ = writer.WriteField("name", "demo-core")
_ = writer.WriteField("version", "1.0.0")
_ = writer.WriteField("platform", "any")
_ = writer.WriteField("architecture", "universal")
fileWriter, err := writer.CreateFormFile("file", "demo.pkg")
if err != nil {
t.Fatal(err)
}
_, _ = fileWriter.Write([]byte("demo package"))
_ = writer.Close()
request, err := http.NewRequest(http.MethodPost, server.URL+"/api/v1/packages/upload", body)
if err != nil {
t.Fatal(err)
}
request.Header.Set("Content-Type", writer.FormDataContentType())
request.Header.Set("Authorization", "Bearer 测试令牌")
response, err := http.DefaultClient.Do(request)
if err != nil {
t.Fatal(err)
}
if response.StatusCode != http.StatusCreated {
t.Fatalf("上传状态错误: %d", response.StatusCode)
}
var uploaded registry.Package
if err := json.NewDecoder(response.Body).Decode(&uploaded); err != nil {
t.Fatal(err)
}
response.Body.Close()
if uploaded.Name != "demo-core" || uploaded.Version != "1.0.0" {
t.Fatalf("上传结果错误: %+v", uploaded)
}
listResponse, err := http.Get(server.URL + "/api/v1/packages")
if err != nil {
t.Fatal(err)
}
var listed struct {
Packages []registry.Package `json:"packages"`
}
if err := json.NewDecoder(listResponse.Body).Decode(&listed); err != nil {
t.Fatal(err)
}
listResponse.Body.Close()
if len(listed.Packages) != 1 {
t.Fatalf("包列表数量错误: %d", len(listed.Packages))
}
downloadResponse, err := http.Get(server.URL + "/api/v1/packages/demo-core/1.0.0/download")
if err != nil {
t.Fatal(err)
}
content, err := io.ReadAll(downloadResponse.Body)
if err != nil {
t.Fatal(err)
}
downloadResponse.Body.Close()
if downloadResponse.StatusCode != http.StatusOK || string(content) != "demo package" {
t.Fatalf("下载结果错误: %d %q", downloadResponse.StatusCode, content)
}
if downloadResponse.Header.Get("X-Scout-SHA256") != uploaded.SHA256 {
t.Fatal("下载校验值不一致")
}
}
func TestDownloadUsesFallbackFileNameForLegacyPackage(t *testing.T) {
root := t.TempDir()
versionDir := filepath.Join(root, "legacy-demo", "1.0.0")
if err := os.MkdirAll(versionDir, 0o755); err != nil {
t.Fatal(err)
}
legacy := registry.Package{
Name: "legacy-demo",
Version: "1.0.0",
Status: "published",
Size: 6,
UploadedAt: time.Now().UTC(),
}
metadata, err := json.Marshal(legacy)
if err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(versionDir, "metadata.json"), metadata, 0o644); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(versionDir, "package.bin"), []byte("legacy"), 0o644); err != nil {
t.Fatal(err)
}
store, err := registry.New(root)
if err != nil {
t.Fatal(err)
}
server := httptest.NewServer((&Server{Registry: store}).Handler())
defer server.Close()
response, err := http.Get(server.URL + "/api/v1/packages/legacy-demo/1.0.0/download")
if err != nil {
t.Fatal(err)
}
defer response.Body.Close()
if response.StatusCode != http.StatusOK {
t.Fatalf("历史包下载状态错误: %d", response.StatusCode)
}
if got := response.Header.Get("Content-Disposition"); got != `attachment; filename="legacy-demo-1.0.0.pkg"` {
t.Fatalf("历史包下载文件名错误: %s", got)
}
}
func TestStreamFiltersPackage(t *testing.T) {
store, err := registry.New(t.TempDir())
if err != nil {
t.Fatal(err)
}
server := httptest.NewServer((&Server{Registry: store, DeveloperToken: "测试令牌"}).Handler())
defer server.Close()
request, err := http.NewRequest(http.MethodGet, server.URL+"/api/v1/updates/stream?packages=target", nil)
if err != nil {
t.Fatal(err)
}
client := &http.Client{}
streamResponse, err := client.Do(request)
if err != nil {
t.Fatal(err)
}
defer streamResponse.Body.Close()
if streamResponse.StatusCode != http.StatusOK {
t.Fatalf("通知状态错误: %d", streamResponse.StatusCode)
}
if streamResponse.Header.Get("Content-Type") != "text/event-stream; charset=utf-8" {
t.Fatalf("通知类型错误: %s", streamResponse.Header.Get("Content-Type"))
}
_ = url.Values{}
}