discovery/internal/proxy: implement GET zip for proxy client

GetZip is implemented, which makes a request to
$GOPROXY/<module>/@v/<version>.zip and transforms that data into a
*zip.Reader

This will be used by the discovery fetch service to download modules
from the proxy.

Change-Id: I5aacbbc12fd01f77a22a415206e64698d8849d40
Reviewed-on: https://team-review.git.corp.google.com/c/417749
Reviewed-by: Andrew Bonventre <andybons@google.com>
This commit is contained in:
Julie Qiu 2019-02-18 09:43:57 -05:00
Родитель a6f7eb7c14
Коммит 3db52fc59f
3 изменённых файлов: 88 добавлений и 2 удалений

Просмотреть файл

@ -5,8 +5,11 @@
package proxy package proxy
import ( import (
"archive/zip"
"bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil"
"net/http" "net/http"
"strings" "strings"
"time" "time"
@ -36,12 +39,13 @@ func New(rawurl string) *Client {
return &Client{url: cleanURL(rawurl)} return &Client{url: cleanURL(rawurl)}
} }
// infoURL constructs a url for a GET request to $GOPROXY/<module>/@v/list. // infoURL constructs a url for a request to
// $GOPROXY/<module>/@v/list.
func (c *Client) infoURL(name, version string) string { func (c *Client) infoURL(name, version string) string {
return fmt.Sprintf("%s/%s/@v/%s.info", c.url, name, version) return fmt.Sprintf("%s/%s/@v/%s.info", c.url, name, version)
} }
// GetInfo makes a GET request to $GOPROXY/<module>/@v/<version>.info and // GetInfo makes a request to $GOPROXY/<module>/@v/<version>.info and
// transforms that data into a *VersionInfo. // transforms that data into a *VersionInfo.
func (c *Client) GetInfo(name, version string) (*VersionInfo, error) { func (c *Client) GetInfo(name, version string) (*VersionInfo, error) {
r, err := http.Get(c.infoURL(name, version)) r, err := http.Get(c.infoURL(name, version))
@ -56,3 +60,38 @@ func (c *Client) GetInfo(name, version string) (*VersionInfo, error) {
} }
return &v, nil return &v, nil
} }
// zipURL constructs a url for a request to $GOPROXY/<module>/@v/<version>.zip.
func (c *Client) zipURL(name, version string) string {
return fmt.Sprintf("%s/%s/@v/%s.zip", c.url, name, version)
}
// GetZip makes a request to $GOPROXY/<module>/@v/<version>.zip and transforms
// that data into a *zip.Reader.
func (c *Client) GetZip(name, version string) (*zip.Reader, error) {
u := c.zipURL(name, version)
r, err := http.Get(u)
if err != nil {
return nil, fmt.Errorf("http.Get(%q): %v",
c.zipURL(name, version), err)
}
defer r.Body.Close()
if r.StatusCode < 200 || r.StatusCode >= 300 {
return nil, fmt.Errorf("http.Get(%q) returned response: %d (%q)",
c.zipURL(name, version), r.StatusCode, r.Status)
}
body, err := ioutil.ReadAll(r.Body)
if err != nil {
return nil, fmt.Errorf("http.Get(%q): %v",
c.zipURL(name, version), err)
}
zipReader, err := zip.NewReader(bytes.NewReader(body), int64(len(body)))
if err != nil {
return nil, fmt.Errorf("http.Get(%q): %v",
c.zipURL(name, version), err)
}
return zipReader, nil
}

Просмотреть файл

@ -5,6 +5,7 @@
package proxy package proxy
import ( import (
"fmt"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"testing" "testing"
@ -73,3 +74,49 @@ func TestGetInfoVersionDoesNotExist(t *testing.T) {
t.Errorf("GetInfo(%q, %q) = %v, want %v", name, version, info, nil) t.Errorf("GetInfo(%q, %q) = %v, want %v", name, version, info, nil)
} }
} }
func TestGetZip(t *testing.T) {
teardownTestCase, testCase := setupTestCase(t)
defer teardownTestCase(t)
name := "my/module"
version := "v1.0.0"
zipReader, err := testCase.client.GetZip(name, version)
if err != nil {
t.Errorf("GetZip(%q, %q) error: %v", name, version, err)
}
expectedFiles := map[string]bool{
"my/": true,
"my/module@v1.0.0/": true,
"my/module@v1.0.0/LICENSE": true,
"my/module@v1.0.0/README.md": true,
"my/module@v1.0.0/go.mod": true,
}
if len(zipReader.File) != len(expectedFiles) {
t.Errorf("GetZip(%q, %q) returned number of files: got %d, want %d",
name, version, len(zipReader.File), len(expectedFiles))
}
for _, zipFile := range zipReader.File {
if !expectedFiles[zipFile.Name] {
t.Errorf("GetZip(%q, %q) returned unexpected file: %q", name,
version, zipFile.Name)
}
delete(expectedFiles, zipFile.Name)
}
}
func TestGetZipNonExist(t *testing.T) {
teardownTestCase, testCase := setupTestCase(t)
defer teardownTestCase(t)
name := "my/nonexistmodule"
version := "v1.0.0"
expectedErr := fmt.Sprintf("http.Get(%q) returned response: %d (%q)",
testCase.client.zipURL(name, version), 404, "404 Not Found")
if _, err := testCase.client.GetZip(name, version); err.Error() != expectedErr {
t.Errorf("GetZip(%q, %q) returned error %v, want %v", name, version, err, expectedErr)
}
}

Двоичные данные
internal/proxy/testdata/modproxy/proxy/my/module/@v/v1.0.0.zip поставляемый

Двоичный файл не отображается.