ccpoad / internal /version /checker_additional_test.go
anyalerob's picture
Upload folder using huggingface_hub
2986042 verified
Raw
History Blame Contribute Delete
4.64 kB
package version
import (
"bytes"
"errors"
"io"
"net/http"
"strconv"
"sync/atomic"
"testing"
"time"
)
type roundTripFunc func(*http.Request) (*http.Response, error)
func (f roundTripFunc) RoundTrip(r *http.Request) (*http.Response, error) { return f(r) }
type signalReadCloser struct {
rc io.ReadCloser
onClose func()
}
func (s *signalReadCloser) Read(p []byte) (int, error) { return s.rc.Read(p) }
func (s *signalReadCloser) Close() error {
if s.onClose != nil {
s.onClose()
s.onClose = nil
}
return s.rc.Close()
}
func httpResp(status int, body string) *http.Response {
return &http.Response{
StatusCode: status,
Status: strconv.Itoa(status),
Header: make(http.Header),
Body: io.NopCloser(bytes.NewBufferString(body)),
}
}
func TestChecker_Check_ErrorsAndSuccess(t *testing.T) {
origVersion := Version
t.Cleanup(func() { Version = origVersion })
t.Run("client error", func(t *testing.T) {
c := &Checker{
client: &http.Client{
Transport: roundTripFunc(func(req *http.Request) (*http.Response, error) {
return nil, errors.New("boom")
}),
},
}
c.check()
if c.lastCheck != (time.Time{}) {
t.Fatalf("expected lastCheck untouched on error, got %v", c.lastCheck)
}
})
t.Run("non-200", func(t *testing.T) {
c := &Checker{
client: &http.Client{
Transport: roundTripFunc(func(req *http.Request) (*http.Response, error) {
return httpResp(http.StatusTooManyRequests, "{}"), nil
}),
},
}
c.check()
if c.latestVersion != "" || c.releaseURL != "" || c.hasUpdate {
t.Fatalf("expected no state update on non-200, got latest=%q url=%q hasUpdate=%v", c.latestVersion, c.releaseURL, c.hasUpdate)
}
})
t.Run("bad json", func(t *testing.T) {
c := &Checker{
client: &http.Client{
Transport: roundTripFunc(func(req *http.Request) (*http.Response, error) {
return httpResp(http.StatusOK, "{"), nil
}),
},
}
c.check()
if c.latestVersion != "" || c.releaseURL != "" || c.hasUpdate {
t.Fatalf("expected no state update on bad json, got latest=%q url=%q hasUpdate=%v", c.latestVersion, c.releaseURL, c.hasUpdate)
}
})
t.Run("success no update", func(t *testing.T) {
Version = "v1.2.3"
c := &Checker{
client: &http.Client{
Transport: roundTripFunc(func(req *http.Request) (*http.Response, error) {
if req.Header.Get("Accept") == "" || req.Header.Get("User-Agent") == "" {
t.Fatalf("expected headers set, got Accept=%q UA=%q", req.Header.Get("Accept"), req.Header.Get("User-Agent"))
}
return httpResp(http.StatusOK, `{"tag_name":"v1.2.3","html_url":"https://example.com/release"}`), nil
}),
},
}
c.check()
if c.latestVersion != "v1.2.3" || c.releaseURL != "https://example.com/release" {
t.Fatalf("unexpected state: latest=%q url=%q", c.latestVersion, c.releaseURL)
}
if c.hasUpdate {
t.Fatalf("expected hasUpdate=false when versions equal")
}
if c.lastCheck.IsZero() {
t.Fatalf("expected lastCheck set")
}
})
t.Run("success has update", func(t *testing.T) {
Version = "v1.0.0"
c := &Checker{
client: &http.Client{
Transport: roundTripFunc(func(req *http.Request) (*http.Response, error) {
return httpResp(http.StatusOK, `{"tag_name":"v2.0.0","html_url":"https://example.com/release2"}`), nil
}),
},
}
c.check()
if !c.hasUpdate || c.latestVersion != "v2.0.0" || c.releaseURL != "https://example.com/release2" {
t.Fatalf("unexpected state: hasUpdate=%v latest=%q url=%q", c.hasUpdate, c.latestVersion, c.releaseURL)
}
})
}
func TestStartChecker_RunsCheckOnce(t *testing.T) {
origVersion := Version
origClient := checker.client
t.Cleanup(func() {
Version = origVersion
checker.client = origClient
})
Version = "v1.0.0"
var calls int32
done := make(chan struct{})
checker.client = &http.Client{
Transport: roundTripFunc(func(req *http.Request) (*http.Response, error) {
atomic.AddInt32(&calls, 1)
resp := httpResp(http.StatusOK, `{"tag_name":"v2.0.0","html_url":"https://example.com/release"}`)
resp.Body = &signalReadCloser{
rc: resp.Body,
onClose: func() {
select {
case <-done:
default:
close(done)
}
},
}
return resp, nil
}),
}
StartChecker()
select {
case <-done:
case <-time.After(1 * time.Second):
t.Fatalf("expected StartChecker to run check at least once")
}
if atomic.LoadInt32(&calls) == 0 {
t.Fatalf("expected StartChecker to issue at least one HTTP call")
}
checker.mu.RLock()
lastCheck := checker.lastCheck
checker.mu.RUnlock()
if lastCheck.IsZero() {
t.Fatalf("expected lastCheck to be set")
}
}