Initialize Clash Web source and deployment documentation

This commit is contained in:
lhc committed 2026-10-05 17:32:00 +08:00
commit 8e0fa00a73
66 files changed
+8532

No files matched your search

+84
View File
@@ -0,0 +1,84 @@
package app
import (
"context"
"io"
"net/http"
"strings"
"sync/atomic"
"testing"
)
type updateTransport func(*http.Request) (*http.Response, error)
func (transport updateTransport) RoundTrip(request *http.Request) (*http.Response, error) {
return transport(request)
}
func TestStableVersionComparison(t *testing.T) {
for _, test := range []struct {
current, latest string
known, newer bool
}{
{"v1.19.9", "v1.19.32", true, true},
{"1.19.32", "v1.19.32", true, false},
{"v2.0.0", "v1.99.99", true, false},
{"v1.19.32", "v1.20.0", true, true},
{"", "v1.19.32", false, false},
{"Meta-alpha", "v1.19.32", false, false},
{"v1.19.32", "v1.20.0-beta", false, false},
} {
result := newerStableVersion(test.current, test.latest)
if (result != nil) != test.known || result != nil && *result != test.newer {
t.Fatalf("%s -> %s: got %v", test.current, test.latest, result)
}
}
}
func TestUpdateCheckAuthCachingAndFailure(t *testing.T) {
a := newTestApp(t)
var calls atomic.Int32
a.download.Transport = updateTransport(func(r *http.Request) (*http.Response, error) {
calls.Add(1)
if r.URL.String() != coreReleaseEndpoint {
t.Fatal("unexpected update source", r.URL)
}
return &http.Response{StatusCode: 200, Body: io.NopCloser(strings.NewReader(`{"tag_name":"v1.19.33","published_at":"2026-10-03T00:00:00Z"}`)), Header: http.Header{}}, nil
})
if w := request(t, a, "GET", "/api/v1/system/updates", nil, nil, ""); w.Code != 401 || calls.Load() != 0 {
t.Fatal("unauthenticated update check must not fetch metadata")
}
cookie, _ := loginTest(t, a)
for range 2 {
w := request(t, a, "GET", "/api/v1/system/updates", nil, cookie, "")
if w.Code != 200 || !strings.Contains(w.Body.String(), `"updateAvailable":null`) || !strings.Contains(w.Body.String(), `"latestVersion":"v1.19.33"`) {
t.Fatal(w.Code, w.Body)
}
}
if calls.Load() != 1 {
t.Fatal("repeated checks must use cached release metadata")
}
a.updateCache = nil
a.download.Transport = updateTransport(func(*http.Request) (*http.Response, error) {
return &http.Response{StatusCode: 429, Body: io.NopCloser(strings.NewReader("rate limited")), Header: http.Header{}}, nil
})
if w := request(t, a, "GET", "/api/v1/system/updates", nil, cookie, ""); w.Code != 502 {
t.Fatal(w.Code, w.Body)
}
}
func TestUpdateCheckRejectsInvalidRelease(t *testing.T) {
for _, body := range []string{
`{"tag_name":"v1.20.0-beta"}`,
`{"tag_name":"v1.20.0","draft":true}`,
`{"tag_name":"v1.20.0","prerelease":true}`,
`{broken`, strings.Repeat("x", (2<<20)+1),
} {
client := &http.Client{Transport: updateTransport(func(*http.Request) (*http.Response, error) {
return &http.Response{StatusCode: 200, Body: io.NopCloser(strings.NewReader(body)), Header: http.Header{}}, nil
})}
if _, err := fetchCoreRelease(context.Background(), client); err == nil {
t.Fatal("invalid stable release metadata accepted")
}
}
}