更新构建配置并补充测试

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
+86
View File
@@ -0,0 +1,86 @@
package utils
import (
"os"
"path/filepath"
"testing"
"hubproxy/config"
)
func TestParseDockerImage(t *testing.T) {
tests := []struct {
name string
image string
namespace string
repository string
tag string
fullName string
}{
{"official", "nginx", "library", "nginx", "latest", "library/nginx"},
{"tagged", "redis:7", "library", "redis", "7", "library/redis"},
{"namespaced", "user/app:v1", "user", "app", "v1", "user/app"},
{"registry", "ghcr.io/user/app:v2", "user", "app", "v2", "user/app"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := GlobalAccessController.ParseDockerImage(tt.image)
if got.Namespace != tt.namespace || got.Repository != tt.repository || got.Tag != tt.tag || got.FullName != tt.fullName {
t.Fatalf("ParseDockerImage(%q) = %#v", tt.image, got)
}
})
}
}
func TestDockerAccessLists(t *testing.T) {
path := filepath.Join(t.TempDir(), "config.toml")
data := []byte(`
[access]
whiteList = ["library/*", "good/*"]
blackList = ["good/bad"]
`)
if err := os.WriteFile(path, data, 0644); err != nil {
t.Fatal(err)
}
t.Setenv("CONFIG_PATH", path)
if err := config.LoadConfig(); err != nil {
t.Fatal(err)
}
if allowed, reason := GlobalAccessController.CheckDockerAccess("nginx"); !allowed {
t.Fatalf("nginx denied: %s", reason)
}
if allowed, _ := GlobalAccessController.CheckDockerAccess("good/bad:latest"); allowed {
t.Fatal("blacklisted image allowed")
}
if allowed, _ := GlobalAccessController.CheckDockerAccess("other/app"); allowed {
t.Fatal("image outside whitelist allowed")
}
}
func TestGitHubAccessLists(t *testing.T) {
path := filepath.Join(t.TempDir(), "config.toml")
data := []byte(`
[access]
whiteList = ["allowed/*"]
blackList = ["allowed/blocked"]
`)
if err := os.WriteFile(path, data, 0644); err != nil {
t.Fatal(err)
}
t.Setenv("CONFIG_PATH", path)
if err := config.LoadConfig(); err != nil {
t.Fatal(err)
}
if allowed, reason := GlobalAccessController.CheckGitHubAccess([]string{"allowed", "repo"}); !allowed {
t.Fatalf("allowed/repo denied: %s", reason)
}
if allowed, _ := GlobalAccessController.CheckGitHubAccess([]string{"allowed", "blocked"}); allowed {
t.Fatal("blacklisted repo allowed")
}
if allowed, _ := GlobalAccessController.CheckGitHubAccess([]string{"other", "repo"}); allowed {
t.Fatal("repo outside whitelist allowed")
}
}
+49
View File
@@ -0,0 +1,49 @@
package utils
import (
"testing"
"time"
)
func TestUniversalCacheSetGetAndExpire(t *testing.T) {
cache := &UniversalCache{}
cache.Set("k", []byte("v"), "text/plain", map[string]string{"X-Test": "1"}, time.Minute)
if got := cache.Get("k"); got == nil || string(got.Data) != "v" || got.Headers["X-Test"] != "1" {
t.Fatalf("cache hit mismatch: %#v", got)
}
cache.Set("expired", []byte("v"), "", nil, -time.Second)
if got := cache.Get("expired"); got != nil {
t.Fatalf("expired item returned: %#v", got)
}
}
func TestTokenCacheHelpers(t *testing.T) {
cache := &UniversalCache{}
cache.SetToken("token", `{"token":"abc"}`, time.Minute)
if got := cache.GetToken("token"); got != `{"token":"abc"}` {
t.Fatalf("GetToken = %q", got)
}
}
func TestExtractTTLFromResponse(t *testing.T) {
ttl := ExtractTTLFromResponse([]byte(`{"expires_in":3600}`))
if ttl != 55*time.Minute {
t.Fatalf("TTL = %s, want 55m", ttl)
}
if ttl := ExtractTTLFromResponse([]byte(`{}`)); ttl != 30*time.Minute {
t.Fatalf("default TTL = %s", ttl)
}
}
func TestBuildCacheKeyStable(t *testing.T) {
a := BuildCacheKey("p", "query")
b := BuildCacheKey("p", "query")
c := BuildCacheKey("p", "other")
if a != b || a == c {
t.Fatalf("unexpected keys: %q %q %q", a, b, c)
}
}
+69
View File
@@ -0,0 +1,69 @@
package utils
import (
"compress/gzip"
"io"
"strings"
"testing"
)
func TestProcessSmartRewritesGitHubURLs(t *testing.T) {
input := `curl -L https://github.com/user/repo/releases/download/v1/file.sh`
reader, size, err := ProcessSmart(strings.NewReader(input), false, "proxy.example.com")
if err != nil {
t.Fatal(err)
}
buf := new(strings.Builder)
if _, err := io.Copy(buf, reader); err != nil {
t.Fatal(err)
}
want := "https://proxy.example.com/https://github.com/user/repo/releases/download/v1/file.sh"
if !strings.Contains(buf.String(), want) {
t.Fatalf("processed script = %q, want contains %q", buf.String(), want)
}
if size != int64(len(buf.String())) {
t.Fatalf("size = %d, want %d", size, len(buf.String()))
}
}
func TestProcessSmartKeepsNonGitHubContent(t *testing.T) {
input := "echo hello"
reader, _, err := ProcessSmart(strings.NewReader(input), false, "proxy.example.com")
if err != nil {
t.Fatal(err)
}
buf := new(strings.Builder)
if _, err := io.Copy(buf, reader); err != nil {
t.Fatal(err)
}
if buf.String() != input {
t.Fatalf("content changed: %q", buf.String())
}
}
func TestReadShellContentGzip(t *testing.T) {
var compressed strings.Builder
gz := gzip.NewWriter(&compressed)
if _, err := gz.Write([]byte("echo https://github.com/u/r")); err != nil {
t.Fatal(err)
}
if err := gz.Close(); err != nil {
t.Fatal(err)
}
reader, _, err := ProcessSmart(strings.NewReader(compressed.String()), true, "proxy.example.com")
if err != nil {
t.Fatal(err)
}
buf := new(strings.Builder)
if _, err := io.Copy(buf, reader); err != nil {
t.Fatal(err)
}
if !strings.Contains(buf.String(), "https://proxy.example.com/https://github.com/u/r") {
t.Fatalf("gzip content not rewritten: %q", buf.String())
}
}
+21
View File
@@ -0,0 +1,21 @@
package utils
import "testing"
func TestExtractIPFromAddress(t *testing.T) {
if got := extractIPFromAddress("127.0.0.1:5000"); got != "127.0.0.1" {
t.Fatalf("extract IPv4 = %q", got)
}
if got := extractIPFromAddress("[2001:db8::1]:5000"); got != "2001:db8::1" {
t.Fatalf("extract IPv6 = %q", got)
}
}
func TestNormalizeIPv6ForRateLimit(t *testing.T) {
if got := normalizeIPForRateLimit("192.168.1.2"); got != "192.168.1.2" {
t.Fatalf("IPv4 normalized = %q", got)
}
if got := normalizeIPForRateLimit("2001:db8::1"); got != "2001:db8::/64" {
t.Fatalf("IPv6 normalized = %q", got)
}
}