更新构建配置并补充测试

This commit is contained in:
sky22333
2026-05-06 19:16:27 +08:00
parent f5bc86ef79
commit d0b3c657cc
20 changed files with 771 additions and 191 deletions

View File

@@ -0,0 +1,30 @@
package handlers
import "testing"
func TestParseRegistryPath(t *testing.T) {
tests := []struct {
path string
image string
apiType string
reference string
}{
{"library/nginx/manifests/latest", "library/nginx", "manifests", "latest"},
{"library/nginx/blobs/sha256:abc", "library/nginx", "blobs", "sha256:abc"},
{"library/nginx/tags/list", "library/nginx", "tags", "list"},
}
for _, tt := range tests {
image, apiType, reference := parseRegistryPath(tt.path)
if image != tt.image || apiType != tt.apiType || reference != tt.reference {
t.Fatalf("parseRegistryPath(%q) = %q %q %q", tt.path, image, apiType, reference)
}
}
}
func TestParseRegistryPathInvalid(t *testing.T) {
image, apiType, reference := parseRegistryPath("library/nginx/unknown/latest")
if image != "" || apiType != "" || reference != "" {
t.Fatalf("invalid path parsed as %q %q %q", image, apiType, reference)
}
}

View File

@@ -0,0 +1,32 @@
package handlers
import "testing"
func TestCheckGitHubURL(t *testing.T) {
tests := []struct {
name string
url string
user string
repo string
}{
{"release", "https://github.com/user/repo/releases/download/v1/file.tar.gz", "user", "repo"},
{"raw", "https://raw.githubusercontent.com/user/repo/main/file.sh", "user", "repo"},
{"api", "https://api.github.com/repos/user/repo/releases/latest", "user", "repo"},
{"huggingface", "https://huggingface.co/user/model/resolve/main/file", "user", "model/resolve/main/file"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := CheckGitHubURL(tt.url)
if len(got) < 2 || got[0] != tt.user || got[1] != tt.repo {
t.Fatalf("CheckGitHubURL(%q) = %#v", tt.url, got)
}
})
}
}
func TestCheckGitHubURLRejectsOtherHosts(t *testing.T) {
if got := CheckGitHubURL("https://example.com/user/repo/file"); got != nil {
t.Fatalf("unexpected match: %#v", got)
}
}

View File

@@ -0,0 +1,60 @@
package handlers
import (
"testing"
"time"
)
func TestDownloadDebouncer(t *testing.T) {
d := NewDownloadDebouncer(time.Minute)
if !d.ShouldAllow("user", "content") {
t.Fatal("first request denied")
}
if d.ShouldAllow("user", "content") {
t.Fatal("duplicate request allowed")
}
if !d.ShouldAllow("other", "content") {
t.Fatal("different user denied")
}
}
func TestTokenStoreCreateConsume(t *testing.T) {
store := newTokenStore[SingleDownloadRequest]()
req := SingleDownloadRequest{Image: "nginx:latest", Platform: "linux/amd64", UseCompressedLayers: true}
token, err := store.create(req, "127.0.0.1", "ua")
if err != nil {
t.Fatal(err)
}
got, ok := store.consume(token, "127.0.0.1", "ua")
if !ok {
t.Fatal("token not consumed")
}
if got != req {
t.Fatalf("request = %#v, want %#v", got, req)
}
if _, ok := store.consume(token, "127.0.0.1", "ua"); ok {
t.Fatal("token consumed twice")
}
}
func TestTokenStoreRejectsDifferentClient(t *testing.T) {
store := newTokenStore[SingleDownloadRequest]()
token, err := store.create(SingleDownloadRequest{Image: "nginx:latest"}, "127.0.0.1", "ua")
if err != nil {
t.Fatal(err)
}
if _, ok := store.consume(token, "127.0.0.2", "ua"); ok {
t.Fatal("token accepted for different IP")
}
}
func TestGenerateContentFingerprintStable(t *testing.T) {
a := generateContentFingerprint([]string{"b:1", "a:1"}, "linux/amd64")
b := generateContentFingerprint([]string{"a:1", "b:1"}, "linux/amd64")
c := generateContentFingerprint([]string{"a:1", "b:1"}, "linux/arm64")
if a != b || a == c {
t.Fatalf("unexpected fingerprints: %q %q %q", a, b, c)
}
}

View File

@@ -0,0 +1,45 @@
package handlers
import (
"net/http"
"net/http/httptest"
"testing"
"time"
"github.com/gin-gonic/gin"
)
func TestNormalizeRepository(t *testing.T) {
official := &Repository{Name: "nginx", IsOfficial: true}
normalizeRepository(official)
if official.Namespace != "library" || official.Name != "library/nginx" {
t.Fatalf("official normalized to %#v", official)
}
userRepo := &Repository{Name: "owner/app", RepoOwner: "owner"}
normalizeRepository(userRepo)
if userRepo.Namespace != "owner" || userRepo.Name != "app" {
t.Fatalf("user repo normalized to %#v", userRepo)
}
}
func TestParsePaginationParams(t *testing.T) {
gin.SetMode(gin.TestMode)
req := httptest.NewRequest(http.MethodGet, "/?page=3&page_size=50", nil)
c, _ := gin.CreateTestContext(httptest.NewRecorder())
c.Request = req
page, pageSize := parsePaginationParams(c, 25)
if page != 3 || pageSize != 50 {
t.Fatalf("pagination = %d %d", page, pageSize)
}
}
func TestSearchCacheExpires(t *testing.T) {
cache := &Cache{data: make(map[string]cacheEntry), maxSize: 10}
cache.SetWithTTL("k", "v", -time.Second)
if got, ok := cache.Get("k"); ok || got != nil {
t.Fatalf("expired cache returned: %#v", got)
}
}