package version import ( "bytes" "context" "errors" "net/http" "net/http/httptest" "os" "path/filepath" "testing" "gitgud.io/mike/mpv-manager/pkg/releasemanifest" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestSelectManagerAssetPlatforms(t *testing.T) { newRelease := func() *ReleaseInfo { release := &ReleaseInfo{Version: "9.9.9"} release.Components = map[string]releasemanifest.Component{ ComponentID: { Version: "9.9.9", Assets: []releasemanifest.Asset{ {GOOS: "linux", GOARCH: "amd64", URL: "https://example.com/linux-amd64", BLAKE3: "blake3:linux-amd64"}, {GOOS: "linux", GOARCH: "arm64", URL: "https://example.com/linux-arm64", BLAKE3: "blake3:linux-arm64"}, {GOOS: "windows", GOARCH: "amd64", URL: "https://example.com/win-x86_64.exe", BLAKE3: "blake3:win-x86_64"}, {GOOS: "windows", GOARCH: "arm64", URL: "https://example.com/win-arm64.exe", BLAKE3: "blake3:win-arm64"}, {GOOS: "darwin", GOARCH: "amd64", URL: "https://example.com/macos-intel", BLAKE3: "blake3:macos-intel"}, {GOOS: "darwin", GOARCH: "arm64", URL: "https://example.com/macos-arm", BLAKE3: "blake3:macos-arm"}, }, }, } return release } tests := []struct { name string goos string goarch string wantURL string wantHash string }{ {"linux/amd64", "linux", "amd64", "https://example.com/linux-amd64", "blake3:linux-amd64"}, {"linux/arm64", "linux", "arm64", "https://example.com/linux-arm64", "blake3:linux-arm64"}, {"windows/amd64", "windows", "amd64", "https://example.com/win-x86_64.exe", "blake3:win-x86_64"}, {"windows/arm64", "windows", "arm64", "https://example.com/win-arm64.exe", "blake3:win-arm64"}, {"darwin/amd64", "darwin", "amd64", "https://example.com/macos-intel", "blake3:macos-intel"}, {"darwin/arm64", "darwin", "arm64", "https://example.com/macos-arm", "blake3:macos-arm"}, {"unsupported combo", "freebsd", "amd64", "", ""}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := &VersionCheckResult{} err := selectManagerAsset(result, newRelease(), tt.goos, tt.goarch) assert.Equal(t, tt.wantURL, result.URL) assert.Equal(t, tt.wantHash, result.BLAKE3) assert.Equal(t, tt.wantURL != "", result.UpdateAvailable) if tt.wantURL == "" { assert.Error(t, err) } else { assert.NoError(t, err) } }) } } func TestVerifyBLAKE3OpenFailure(t *testing.T) { err := VerifyBLAKE3(filepath.Join(t.TempDir(), "does-not-exist"), "blake3:whatever") require.Error(t, err) assert.Contains(t, err.Error(), "failed to open file") } // errAfterReader yields its data once and then fails, simulating a connection // that dies mid-download. type errAfterReader struct { data []byte err error } func (r *errAfterReader) Read(p []byte) (int, error) { if len(r.data) == 0 { return 0, r.err } n := copy(p, r.data) r.data = r.data[n:] return n, nil } func (r *errAfterReader) Close() error { return nil } func TestDownloadFileWithProgressMidStreamError(t *testing.T) { payload := []byte("partial content that never completes") previousClient := selfUpdateHTTPClient selfUpdateHTTPClient = &http.Client{Transport: roundTripFunc(func(*http.Request) (*http.Response, error) { return &http.Response{ StatusCode: http.StatusOK, Body: &errAfterReader{data: bytes.Clone(payload), err: errors.New("connection reset")}, ContentLength: int64(len(payload)) * 4, }, nil })} t.Cleanup(func() { selfUpdateHTTPClient = previousClient }) dest := filepath.Join(t.TempDir(), "partial.bin") err := downloadFileWithProgressContext(context.Background(), "https://example.invalid/update", dest, func(written, total int64) {}, 2) require.Error(t, err) assert.Contains(t, err.Error(), "download failed after 2 attempts") assert.NoFileExists(t, dest, "partial downloads are removed on failure") } func TestDownloadFileWithProgressUnwritableDirectory(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.Write([]byte("content")) })) defer server.Close() // A regular file as the parent path makes MkdirAll fail deterministically. parent := filepath.Join(t.TempDir(), "a-file") require.NoError(t, os.WriteFile(parent, []byte("x"), 0644)) err := downloadFileWithProgressContext(context.Background(), server.URL, filepath.Join(parent, "nested", "dest.bin"), nil, 1) require.Error(t, err) }