cli/cmd/updater/updater_test.go

262 lines
7.7 KiB
Go
Raw Normal View History

package updater
import (
"context"
"fmt"
"log"
"net/http"
"net/http/httptest"
"runtime"
)
// mockGithubClient is a mock implementation of the GithubClient interface for testing.
type mockGithubClient struct {
getLatestRelease func(ctx context.Context, owner, repo, channel string) (*Release, error)
getReleaseByPR func(ctx context.Context, owner, repo string, prNumber int) (*Release, error)
getPublicRepos func(ctx context.Context, userOrOrg string) ([]string, error)
getLatestReleaseCount int
getReleaseByPRCount int
getPublicReposCount int
}
func (m *mockGithubClient) GetLatestRelease(ctx context.Context, owner, repo, channel string) (*Release, error) {
m.getLatestReleaseCount++
return m.getLatestRelease(ctx, owner, repo, channel)
}
func (m *mockGithubClient) GetReleaseByPullRequest(ctx context.Context, owner, repo string, prNumber int) (*Release, error) {
m.getReleaseByPRCount++
return m.getReleaseByPR(ctx, owner, repo, prNumber)
}
func (m *mockGithubClient) GetPublicRepos(ctx context.Context, userOrOrg string) ([]string, error) {
m.getPublicReposCount++
if m.getPublicRepos != nil {
return m.getPublicRepos(ctx, userOrOrg)
}
return nil, fmt.Errorf("GetPublicRepos not implemented")
}
func ExampleCheckForNewerVersion() {
originalNewGithubClient := NewGithubClient
defer func() { NewGithubClient = originalNewGithubClient }()
NewGithubClient = func() GithubClient {
return &mockGithubClient{
getLatestRelease: func(ctx context.Context, owner, repo, channel string) (*Release, error) {
return &Release{TagName: "v1.1.0"}, nil
},
}
}
Version = "1.0.0"
release, available, err := CheckForNewerVersion("owner", "repo", "stable", true)
if err != nil {
log.Fatalf("CheckForNewerVersion failed: %v", err)
}
if available {
fmt.Printf("Newer version available: %s", release.TagName)
} else {
fmt.Println("No newer version available.")
}
// Output: Newer version available: v1.1.0
}
func ExampleCheckForUpdates() {
// Mock the functions to prevent actual updates and network calls
originalDoUpdate := DoUpdate
originalNewGithubClient := NewGithubClient
defer func() {
DoUpdate = originalDoUpdate
NewGithubClient = originalNewGithubClient
}()
NewGithubClient = func() GithubClient {
return &mockGithubClient{
getLatestRelease: func(ctx context.Context, owner, repo, channel string) (*Release, error) {
return &Release{
TagName: "v1.1.0",
Assets: []ReleaseAsset{{Name: fmt.Sprintf("test-asset-%s-%s", runtime.GOOS, runtime.GOARCH), DownloadURL: "http://example.com/asset"}},
}, nil
},
}
}
DoUpdate = func(url string) error {
fmt.Printf("Update would be applied from: %s", url)
return nil
}
Version = "1.0.0"
err := CheckForUpdates("owner", "repo", "stable", true, "")
if err != nil {
log.Fatalf("CheckForUpdates failed: %v", err)
}
// Output:
// Newer version v1.1.0 found (current: v1.0.0). Applying update...
// Update would be applied from: http://example.com/asset
}
func ExampleCheckOnly() {
originalNewGithubClient := NewGithubClient
defer func() { NewGithubClient = originalNewGithubClient }()
NewGithubClient = func() GithubClient {
return &mockGithubClient{
getLatestRelease: func(ctx context.Context, owner, repo, channel string) (*Release, error) {
return &Release{TagName: "v1.1.0"}, nil
},
}
}
Version = "1.0.0"
err := CheckOnly("owner", "repo", "stable", true, "")
if err != nil {
log.Fatalf("CheckOnly failed: %v", err)
}
// Output: New release found: v1.1.0 (current version: v1.0.0)
}
func ExampleCheckForUpdatesByTag() {
// Mock the functions to prevent actual updates and network calls
originalDoUpdate := DoUpdate
originalNewGithubClient := NewGithubClient
defer func() {
DoUpdate = originalDoUpdate
NewGithubClient = originalNewGithubClient
}()
NewGithubClient = func() GithubClient {
return &mockGithubClient{
getLatestRelease: func(ctx context.Context, owner, repo, channel string) (*Release, error) {
if channel == "stable" {
return &Release{
TagName: "v1.1.0",
Assets: []ReleaseAsset{{Name: fmt.Sprintf("test-asset-%s-%s", runtime.GOOS, runtime.GOARCH), DownloadURL: "http://example.com/asset"}},
}, nil
}
return nil, nil
},
}
}
DoUpdate = func(url string) error {
fmt.Printf("Update would be applied from: %s", url)
return nil
}
Version = "1.0.0" // A version that resolves to the "stable" channel
err := CheckForUpdatesByTag("owner", "repo")
if err != nil {
log.Fatalf("CheckForUpdatesByTag failed: %v", err)
}
// Output:
// Newer version v1.1.0 found (current: v1.0.0). Applying update...
// Update would be applied from: http://example.com/asset
}
func ExampleCheckOnlyByTag() {
originalNewGithubClient := NewGithubClient
defer func() { NewGithubClient = originalNewGithubClient }()
NewGithubClient = func() GithubClient {
return &mockGithubClient{
getLatestRelease: func(ctx context.Context, owner, repo, channel string) (*Release, error) {
if channel == "stable" {
return &Release{TagName: "v1.1.0"}, nil
}
return nil, nil
},
}
}
Version = "1.0.0" // A version that resolves to the "stable" channel
err := CheckOnlyByTag("owner", "repo")
if err != nil {
log.Fatalf("CheckOnlyByTag failed: %v", err)
}
// Output: New release found: v1.1.0 (current version: v1.0.0)
}
func ExampleCheckForUpdatesByPullRequest() {
// Mock the functions to prevent actual updates and network calls
originalDoUpdate := DoUpdate
originalNewGithubClient := NewGithubClient
defer func() {
DoUpdate = originalDoUpdate
NewGithubClient = originalNewGithubClient
}()
NewGithubClient = func() GithubClient {
return &mockGithubClient{
getReleaseByPR: func(ctx context.Context, owner, repo string, prNumber int) (*Release, error) {
if prNumber == 123 {
return &Release{
TagName: "v1.1.0-alpha.pr.123",
Assets: []ReleaseAsset{{Name: fmt.Sprintf("test-asset-%s-%s", runtime.GOOS, runtime.GOARCH), DownloadURL: "http://example.com/asset-pr"}},
}, nil
}
return nil, nil
},
}
}
DoUpdate = func(url string) error {
fmt.Printf("Update would be applied from: %s", url)
return nil
}
err := CheckForUpdatesByPullRequest("owner", "repo", 123, "")
if err != nil {
log.Fatalf("CheckForUpdatesByPullRequest failed: %v", err)
}
// Output:
// Release v1.1.0-alpha.pr.123 found for PR #123. Applying update...
// Update would be applied from: http://example.com/asset-pr
}
func ExampleCheckForUpdatesHTTP() {
// Create a mock HTTP server
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/latest.json" {
feat: infrastructure packages and lint cleanup (#281) * ci: consolidate duplicate workflows and merge CodeQL configs Remove 17 duplicate workflow files that were split copies of the combined originals. Each family (CI, CodeQL, Coverage, PR Build, Alpha Release) had the same job duplicated across separate push/pull_request/schedule/manual trigger files. Merge codeql.yml and codescan.yml into a single codeql.yml with a language matrix covering go, javascript-typescript, python, and actions — matching the previous default setup coverage. Remaining workflows (one per family): - ci.yml (push + PR + manual) - codeql.yml (push + PR + schedule, all languages) - coverage.yml (push + PR + manual) - alpha-release.yml (push + manual) - pr-build.yml (PR + manual) - release.yml (tag push) - agent-verify.yml, auto-label.yml, auto-project.yml Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: add collect, config, crypt, plugin packages and fix all lint issues Add four new infrastructure packages with CLI commands: - pkg/config: layered configuration (defaults → file → env → flags) - pkg/crypt: crypto primitives (Argon2id, AES-GCM, ChaCha20, HMAC, checksums) - pkg/plugin: plugin system with GitHub-based install/update/remove - pkg/collect: collection subsystem (GitHub, BitcoinTalk, market, papers, excavate) Fix all golangci-lint issues across the entire codebase (~100 errcheck, staticcheck SA1012/SA1019/ST1005, unused, ineffassign fixes) so that `core go qa` passes with 0 issues. Closes #167, #168, #170, #250, #251, #252, #253, #254, #255, #256 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 11:34:43 +00:00
_, _ = fmt.Fprintln(w, `{"version": "1.1.0", "url": "http://example.com/update"}`)
}
}))
defer server.Close()
// Mock the doUpdateFunc to prevent actual updates
originalDoUpdate := DoUpdate
defer func() { DoUpdate = originalDoUpdate }()
DoUpdate = func(url string) error {
fmt.Printf("Update would be applied from: %s", url)
return nil
}
Version = "1.0.0"
err := CheckForUpdatesHTTP(server.URL)
if err != nil {
log.Fatalf("CheckForUpdatesHTTP failed: %v", err)
}
// Output:
// Newer version 1.1.0 found (current: 1.0.0). Applying update...
// Update would be applied from: http://example.com/update
}
func ExampleCheckOnlyHTTP() {
// Create a mock HTTP server
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/latest.json" {
feat: infrastructure packages and lint cleanup (#281) * ci: consolidate duplicate workflows and merge CodeQL configs Remove 17 duplicate workflow files that were split copies of the combined originals. Each family (CI, CodeQL, Coverage, PR Build, Alpha Release) had the same job duplicated across separate push/pull_request/schedule/manual trigger files. Merge codeql.yml and codescan.yml into a single codeql.yml with a language matrix covering go, javascript-typescript, python, and actions — matching the previous default setup coverage. Remaining workflows (one per family): - ci.yml (push + PR + manual) - codeql.yml (push + PR + schedule, all languages) - coverage.yml (push + PR + manual) - alpha-release.yml (push + manual) - pr-build.yml (PR + manual) - release.yml (tag push) - agent-verify.yml, auto-label.yml, auto-project.yml Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: add collect, config, crypt, plugin packages and fix all lint issues Add four new infrastructure packages with CLI commands: - pkg/config: layered configuration (defaults → file → env → flags) - pkg/crypt: crypto primitives (Argon2id, AES-GCM, ChaCha20, HMAC, checksums) - pkg/plugin: plugin system with GitHub-based install/update/remove - pkg/collect: collection subsystem (GitHub, BitcoinTalk, market, papers, excavate) Fix all golangci-lint issues across the entire codebase (~100 errcheck, staticcheck SA1012/SA1019/ST1005, unused, ineffassign fixes) so that `core go qa` passes with 0 issues. Closes #167, #168, #170, #250, #251, #252, #253, #254, #255, #256 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 11:34:43 +00:00
_, _ = fmt.Fprintln(w, `{"version": "1.1.0", "url": "http://example.com/update"}`)
}
}))
defer server.Close()
Version = "1.0.0"
err := CheckOnlyHTTP(server.URL)
if err != nil {
log.Fatalf("CheckOnlyHTTP failed: %v", err)
}
// Output: New release found: 1.1.0 (current version: 1.0.0)
}