| package updatecheck |
|
|
| import ( |
| "context" |
| "errors" |
| "io" |
| "net/http" |
| "strings" |
| "testing" |
| "time" |
| ) |
|
|
| type roundTripFunc func(*http.Request) (*http.Response, error) |
|
|
| func (function roundTripFunc) RoundTrip(request *http.Request) (*http.Response, error) { |
| return function(request) |
| } |
|
|
| func TestCheckFindsLatestRelease(t *testing.T) { |
| client := &http.Client{Transport: roundTripFunc(func(request *http.Request) (*http.Response, error) { |
| if request.URL.String() != latestReleaseAPI || request.Header.Get("User-Agent") != "grok2api/v3.0.0" { |
| t.Fatalf("request = %#v", request) |
| } |
| return &http.Response{StatusCode: http.StatusOK, Body: io.NopCloser(strings.NewReader(`{"tag_name":"v3.0.1","body":"Release notes"}`)), Header: make(http.Header)}, nil |
| })} |
| service := NewService("v3.0.0", client) |
| now := time.Date(2026, 7, 16, 12, 0, 0, 0, time.UTC) |
| service.now = func() time.Time { return now } |
| snapshot := service.Check(context.Background()) |
| if snapshot.Status != StatusUpdateAvailable || !snapshot.UpdateAvailable || snapshot.LatestVersion != "v3.0.1" || snapshot.CheckedAt == nil || !snapshot.CheckedAt.Equal(now) { |
| t.Fatalf("snapshot = %#v", snapshot) |
| } |
| if snapshot.ReleaseURL != "https://github.com/chenyme/grok2api/releases/tag/v3.0.1" || snapshot.ReleaseNotes != "Release notes" { |
| t.Fatalf("release = %#v", snapshot) |
| } |
| } |
|
|
| func TestCheckFailureKeepsLastSuccessfulRelease(t *testing.T) { |
| fail := false |
| client := &http.Client{Transport: roundTripFunc(func(*http.Request) (*http.Response, error) { |
| if fail { |
| return nil, errors.New("network down") |
| } |
| return &http.Response{StatusCode: http.StatusOK, Body: io.NopCloser(strings.NewReader(`{"tag_name":"v3.0.0","body":"Stable"}`)), Header: make(http.Header)}, nil |
| })} |
| service := NewService("v3.0.0", client) |
| first := service.Check(context.Background()) |
| fail = true |
| second := service.Check(context.Background()) |
| if first.Status != StatusUpToDate || second.Status != StatusCheckFailed || second.LatestVersion != "v3.0.0" || second.CheckedAt == nil || second.Error == "" { |
| t.Fatalf("first=%#v second=%#v", first, second) |
| } |
| } |
|
|
| func TestSemanticVersionComparison(t *testing.T) { |
| stable, ok := parseSemanticVersion("v3.0.1") |
| if !ok { |
| t.Fatal("stable version was rejected") |
| } |
| older, _ := parseSemanticVersion("3.0.0") |
| prerelease, _ := parseSemanticVersion("v3.0.1-rc.1") |
| if compareSemanticVersion(stable, older) <= 0 || compareSemanticVersion(prerelease, stable) >= 0 { |
| t.Fatal("semantic version ordering is invalid") |
| } |
| if _, ok := parseSemanticVersion("dev"); ok { |
| t.Fatal("development version was accepted as semver") |
| } |
| base, _ := parseSemanticVersion("v3.0.8") |
| hotfix1, _ := parseSemanticVersion("v3.0.8-hotfix.1") |
| hotfix2, _ := parseSemanticVersion("v3.0.8-hotfix.2") |
| sameBasePrerelease, _ := parseSemanticVersion("v3.0.8-rc.1") |
| next, _ := parseSemanticVersion("v3.0.9") |
| if compareSemanticVersion(hotfix1, base) <= 0 || compareSemanticVersion(hotfix2, hotfix1) <= 0 || compareSemanticVersion(next, hotfix2) <= 0 { |
| t.Fatal("project hotfix ordering is invalid") |
| } |
| if compareSemanticVersion(hotfix1, sameBasePrerelease) <= 0 { |
| t.Fatal("project hotfix should follow ordinary prereleases") |
| } |
| } |
|
|
| func TestCheckFindsHotfixAfterStableRelease(t *testing.T) { |
| client := &http.Client{Transport: roundTripFunc(func(*http.Request) (*http.Response, error) { |
| return &http.Response{StatusCode: http.StatusOK, Body: io.NopCloser(strings.NewReader(`{"tag_name":"v3.0.8-hotfix.1"}`)), Header: make(http.Header)}, nil |
| })} |
| service := NewService("v3.0.8", client) |
| snapshot := service.Check(context.Background()) |
| if snapshot.Status != StatusUpdateAvailable || !snapshot.UpdateAvailable { |
| t.Fatalf("snapshot = %#v", snapshot) |
| } |
| } |
|
|