147 lines
4 KiB
Go
147 lines
4 KiB
Go
package fetcher
|
|
|
|
import (
|
|
"archive/tar"
|
|
"bytes"
|
|
"compress/gzip"
|
|
"crypto/sha256"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
func TestDownloadAndExtractDebianDSCUsesOnlyOrig(t *testing.T) {
|
|
origArchive := buildTarGz(t, map[string]string{
|
|
"demo-1.0/README": "hello upstream\n",
|
|
})
|
|
debianPatch := []byte("pretend debian patch content")
|
|
|
|
origHash := hashHex(origArchive)
|
|
debianHash := hashHex(debianPatch)
|
|
|
|
dsc := fmt.Sprintf(`Format: 3.0 (quilt)
|
|
Source: demo
|
|
Checksums-Sha256:
|
|
%s %d demo_1.0.orig.tar.gz
|
|
%s %d demo_1.0-1.debian.tar.xz
|
|
`, origHash, len(origArchive), debianHash, len(debianPatch))
|
|
|
|
hits := map[string]int{}
|
|
withHTTPTransport(t, roundTripFunc(func(req *http.Request) (*http.Response, error) {
|
|
hits[req.URL.Path]++
|
|
switch req.URL.Path {
|
|
case "/pool/main/d/demo/demo_1.0-1.dsc":
|
|
return httpResponse(req, http.StatusOK, []byte(dsc)), nil
|
|
case "/pool/main/d/demo/demo_1.0.orig.tar.gz":
|
|
return httpResponse(req, http.StatusOK, origArchive), nil
|
|
case "/pool/main/d/demo/demo_1.0-1.debian.tar.xz":
|
|
return httpResponse(req, http.StatusOK, debianPatch), nil
|
|
default:
|
|
return httpResponse(req, http.StatusNotFound, []byte("not found")), nil
|
|
}
|
|
}))
|
|
|
|
workDir := t.TempDir()
|
|
f := NewFetcher(filepath.Join(workDir, "cache"))
|
|
destDir := filepath.Join(workDir, "src")
|
|
|
|
err := f.DownloadAndExtract("https://deb.example/pool/main/d/demo/demo_1.0-1.dsc", "", destDir)
|
|
if err != nil {
|
|
t.Fatalf("DownloadAndExtract() error = %v", err)
|
|
}
|
|
|
|
readmePath := filepath.Join(destDir, "demo-1.0", "README")
|
|
content, err := os.ReadFile(readmePath)
|
|
if err != nil {
|
|
t.Fatalf("failed to read extracted file %s: %v", readmePath, err)
|
|
}
|
|
if string(content) != "hello upstream\n" {
|
|
t.Fatalf("unexpected extracted file content: %q", string(content))
|
|
}
|
|
|
|
debianHits := hits["/pool/main/d/demo/demo_1.0-1.debian.tar.xz"]
|
|
origHits := hits["/pool/main/d/demo/demo_1.0.orig.tar.gz"]
|
|
dscHits := hits["/pool/main/d/demo/demo_1.0-1.dsc"]
|
|
|
|
if dscHits == 0 || origHits == 0 {
|
|
t.Fatalf("expected dsc and orig to be downloaded, got dsc=%d orig=%d", dscHits, origHits)
|
|
}
|
|
if debianHits != 0 {
|
|
t.Fatalf("expected debian patch archive to be ignored, got %d requests", debianHits)
|
|
}
|
|
}
|
|
|
|
func TestDownloadAndExtractDebianDSCChecksumMismatch(t *testing.T) {
|
|
withHTTPTransport(t, roundTripFunc(func(req *http.Request) (*http.Response, error) {
|
|
return httpResponse(req, http.StatusOK, []byte("Format: 3.0 (quilt)\nSource: demo\n")), nil
|
|
}))
|
|
|
|
f := NewFetcher(filepath.Join(t.TempDir(), "cache"))
|
|
err := f.DownloadAndExtract("https://deb.example/demo_1.0-1.dsc", "deadbeef", t.TempDir())
|
|
if err == nil {
|
|
t.Fatalf("expected checksum mismatch error")
|
|
}
|
|
}
|
|
|
|
type roundTripFunc func(*http.Request) (*http.Response, error)
|
|
|
|
func (f roundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
return f(req)
|
|
}
|
|
|
|
func withHTTPTransport(t *testing.T, transport http.RoundTripper) {
|
|
t.Helper()
|
|
orig := http.DefaultTransport
|
|
http.DefaultTransport = transport
|
|
t.Cleanup(func() {
|
|
http.DefaultTransport = orig
|
|
})
|
|
}
|
|
|
|
func httpResponse(req *http.Request, code int, body []byte) *http.Response {
|
|
return &http.Response{
|
|
StatusCode: code,
|
|
Body: io.NopCloser(bytes.NewReader(body)),
|
|
Header: make(http.Header),
|
|
Request: req,
|
|
}
|
|
}
|
|
|
|
func buildTarGz(t *testing.T, files map[string]string) []byte {
|
|
t.Helper()
|
|
|
|
var buf bytes.Buffer
|
|
gz := gzip.NewWriter(&buf)
|
|
tw := tar.NewWriter(gz)
|
|
|
|
for name, content := range files {
|
|
hdr := &tar.Header{
|
|
Name: name,
|
|
Mode: 0o644,
|
|
Size: int64(len(content)),
|
|
}
|
|
if err := tw.WriteHeader(hdr); err != nil {
|
|
t.Fatalf("failed to write tar header: %v", err)
|
|
}
|
|
if _, err := tw.Write([]byte(content)); err != nil {
|
|
t.Fatalf("failed to write tar body: %v", err)
|
|
}
|
|
}
|
|
|
|
if err := tw.Close(); err != nil {
|
|
t.Fatalf("failed to close tar writer: %v", err)
|
|
}
|
|
if err := gz.Close(); err != nil {
|
|
t.Fatalf("failed to close gzip writer: %v", err)
|
|
}
|
|
|
|
return buf.Bytes()
|
|
}
|
|
|
|
func hashHex(data []byte) string {
|
|
sum := sha256.Sum256(data)
|
|
return fmt.Sprintf("%x", sum)
|
|
}
|