Scout/internal/httpapi/projects_test.go

154 lines
4.1 KiB
Go

package httpapi
import (
"bytes"
"encoding/json"
"io"
"mime/multipart"
"net/http"
"net/http/httptest"
"testing"
"scout/internal/registry"
)
func TestProjectRoutesKeepSamePackageNamesIsolated(t *testing.T) {
root := t.TempDir()
legacy, err := registry.New(root)
if err != nil {
t.Fatal(err)
}
projects, err := registry.NewProjectRegistry(root)
if err != nil {
t.Fatal(err)
}
if _, _, err := projects.Ensure("ssl", "SSL", "证书项目"); err != nil {
t.Fatal(err)
}
if _, _, err := projects.Ensure("smail", "Smail", "邮件项目"); err != nil {
t.Fatal(err)
}
server := httptest.NewServer((&Server{
Registry: legacy,
Projects: projects,
DeveloperToken: "test-token",
AllowLegacyToken: true,
}).Handler())
defer server.Close()
uploadProjectPackage(t, server.URL, "ssl", "shared", "1.0.0", "ssl-content")
uploadProjectPackage(t, server.URL, "smail", "shared", "1.0.0", "smail-content")
assertProjectPackageContent(t, server.URL+"/api/v1/projects/ssl/packages/shared/1.0.0/download?platform=linux&architecture=amd64", "ssl-content")
assertProjectPackageContent(t, server.URL+"/api/v1/projects/smail/packages/shared/1.0.0/download?platform=linux&architecture=amd64", "smail-content")
response, err := http.Get(server.URL + "/api/v1/projects")
if err != nil {
t.Fatal(err)
}
defer response.Body.Close()
var listed struct {
Projects []registry.Project `json:"projects"`
}
if err := json.NewDecoder(response.Body).Decode(&listed); err != nil {
t.Fatal(err)
}
if response.StatusCode != http.StatusOK || len(listed.Projects) != 3 {
t.Fatalf("项目列表错误:%d %+v", response.StatusCode, listed.Projects)
}
}
func uploadProjectPackage(t *testing.T, baseURL, project, name, version, content string) {
t.Helper()
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
for key, value := range map[string]string{
"name": name,
"version": version,
"platform": "linux",
"architecture": "amd64",
"status": "published",
} {
if err := writer.WriteField(key, value); err != nil {
t.Fatal(err)
}
}
file, err := writer.CreateFormFile("file", name+"-"+version+".pkg")
if err != nil {
t.Fatal(err)
}
if _, err := file.Write([]byte(content)); err != nil {
t.Fatal(err)
}
if err := writer.Close(); err != nil {
t.Fatal(err)
}
request, err := http.NewRequest(http.MethodPost, baseURL+"/api/v1/projects/"+project+"/packages/upload", body)
if err != nil {
t.Fatal(err)
}
request.Header.Set("Content-Type", writer.FormDataContentType())
request.Header.Set("Authorization", "Bearer test-token")
response, err := http.DefaultClient.Do(request)
if err != nil {
t.Fatal(err)
}
defer response.Body.Close()
if response.StatusCode != http.StatusCreated {
data, _ := io.ReadAll(response.Body)
t.Fatalf("项目上传失败:%d %s", response.StatusCode, data)
}
}
func assertProjectPackageContent(t *testing.T, endpoint, expected string) {
t.Helper()
response, err := http.Get(endpoint)
if err != nil {
t.Fatal(err)
}
defer response.Body.Close()
data, err := io.ReadAll(response.Body)
if err != nil {
t.Fatal(err)
}
if response.StatusCode != http.StatusOK || string(data) != expected {
t.Fatalf("项目包内容错误:%d %q", response.StatusCode, data)
}
}
func TestProjectRouteRejectsDisabledProject(t *testing.T) {
root := t.TempDir()
legacy, err := registry.New(root)
if err != nil {
t.Fatal(err)
}
projects, err := registry.NewProjectRegistry(root)
if err != nil {
t.Fatal(err)
}
if _, _, err := projects.Ensure("ssl", "SSL", "证书项目"); err != nil {
t.Fatal(err)
}
if _, err := projects.Update("ssl", registry.Project{
Name: "SSL",
Description: "已停用",
Status: "disabled",
}); err != nil {
t.Fatal(err)
}
server := httptest.NewServer((&Server{
Registry: legacy,
Projects: projects,
}).Handler())
defer server.Close()
response, err := http.Get(server.URL + "/api/v1/projects/ssl/packages")
if err != nil {
t.Fatal(err)
}
defer response.Body.Close()
if response.StatusCode != http.StatusForbidden {
t.Fatalf("停用项目应禁止访问:%d", response.StatusCode)
}
}