85 lines
2.9 KiB
Go
85 lines
2.9 KiB
Go
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")
|
|
}
|
|
}
|
|
}
|