Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions download/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,11 +244,19 @@ func getCliName(targetOS string) string {
return name
}

type httpClient interface {
Get(url string) (resp *http.Response, err error)
}

func fetchZip(url string, useEtag bool) (string, error) {
return fetchZipWithClient(url, useEtag, http.DefaultClient)
}

func fetchZipWithClient(url string, useEtag bool, client httpClient) (string, error) {
// It *may* be more efficient (for whom?) to issue a HEAD request first for the ETag and Content-Length.
// We can't use If-None-Match because we don't know in advance which cached file is for which spec.
// We could encode the entire spec in the cached file name but the complexity would not be worth it.
resp, err := http.Get(url)
resp, err := client.Get(url)
if err != nil {
return "", genericDownloadErr(url, err)
}
Expand All @@ -259,7 +267,7 @@ func fetchZip(url string, useEtag bool) (string, error) {
contentLength := resp.ContentLength
defer helperr.CloseQuietly(resp.Body)
var tmpZip *os.File
if !useEtag && etagHeader != "" {
if !useEtag || etagHeader == "" {
tmpZip, err = os.CreateTemp("", "getaduck")
} else {
// ETag may contain chars not allowed in filenames.
Expand All @@ -275,16 +283,19 @@ func fetchZip(url string, useEtag bool) (string, error) {
tmpZip, err = os.Create(fileName)
}
if err != nil {
return "", fmt.Errorf("failed to create temp file: %w", err)
return "", merry.Wrap(fmt.Errorf("failed to create temp file: %w", err))
}
defer helperr.CloseQuietly(tmpZip)
if resp.Body == nil {
return "", merry.Wrap(fmt.Errorf("no response body available"))
}
_, err = io.Copy(tmpZip, resp.Body)
if err != nil {
return "", genericDownloadErr(url, err)
}
err = tmpZip.Close()
if err != nil {
return "", fmt.Errorf("failed to close temp file: %w", err)
return "", merry.Wrap(fmt.Errorf("failed to close temp file: %w", err))
}

return tmpZip.Name(), nil
Expand Down
42 changes: 42 additions & 0 deletions download/download_internal_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package download

import (
"io"
"net/http"
"os"
"strings"
"testing"

"github.com/stretchr/testify/require"
)

func TestFetchZipWithClient(t *testing.T) {
t.Run("empty body", func(t *testing.T) {
_, err := fetchZipWithClient("", true, clientStub{
response: &http.Response{
StatusCode: 200,
},
})
require.Error(t, err)
})
t.Run("empty etag", func(t *testing.T) {
name, err := fetchZipWithClient("", true, clientStub{
response: &http.Response{
StatusCode: 200,
Body: io.NopCloser(strings.NewReader("")),
},
})
require.NoError(t, err)
require.NoError(t, os.Remove(name))
require.NotContains(t, name, "etag")
})
}

type clientStub struct {
response *http.Response
err error
}

func (c clientStub) Get(_ string) (resp *http.Response, err error) {
return c.response, c.err
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.24.7

require (
github.com/ansel1/merry/v2 v2.2.2
github.com/murfffi/gorich v0.2.0
github.com/murfffi/gorich v0.2.1
github.com/stretchr/testify v1.11.1
golang.org/x/mod v0.28.0
)
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-errors/errors v1.1.1 h1:ljK/pL5ltg3qoN+OtN6yCv9HWSfMwxSx90GJCZQxYNg=
github.com/go-errors/errors v1.1.1/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
github.com/murfffi/gorich v0.2.0 h1:eUQ2xzjp7czPemnc0nSEDVBLz2xyFKfQg2kSgJ9ljwk=
github.com/murfffi/gorich v0.2.0/go.mod h1:o1VsmtwZ9U/E8eyiLvhUTOdV810J8v6Y0R3pi/97TdQ=
github.com/murfffi/gorich v0.2.1 h1:YKUnllpO54KMGomcTBKb8K3zLFxFZT9soEFckf7wkSU=
github.com/murfffi/gorich v0.2.1/go.mod h1:o1VsmtwZ9U/E8eyiLvhUTOdV810J8v6Y0R3pi/97TdQ=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
Expand Down