mirror of
https://github.com/sky22333/hubproxy.git
synced 2026-09-30 20:26:38 +08:00
更新构建配置并补充测试
This commit is contained in:
@@ -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")
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user