zsvo/pkg/debian/source_test.go

199 lines
5.3 KiB
Go

package debian
import (
"bytes"
"compress/gzip"
"fmt"
"io"
"net/http"
"strings"
"testing"
)
type roundTripFunc func(*http.Request) (*http.Response, error)
func (f roundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) {
return f(req)
}
func TestResolveSourceHTTPFallbackToGzip(t *testing.T) {
t.Parallel()
sources := strings.TrimSpace(`
Package: neofetch
Binary: neofetch
Version: 7.1.0-4
Directory: pool/main/n/neofetch
Checksums-Sha256:
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 1978 neofetch_7.1.0-4.dsc
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 73791 neofetch_7.1.0.orig.tar.gz
`) + "\n"
var gz bytes.Buffer
zw := gzip.NewWriter(&gz)
if _, err := zw.Write([]byte(sources)); err != nil {
t.Fatalf("failed to write gzip sources: %v", err)
}
if err := zw.Close(); err != nil {
t.Fatalf("failed to close gzip writer: %v", err)
}
client := &http.Client{
Transport: roundTripFunc(func(req *http.Request) (*http.Response, error) {
switch req.URL.Path {
case "/debian/dists/stable/main/source/Sources.xz":
return httpResponse(req, http.StatusNotFound, []byte("not found")), nil
case "/debian/dists/stable/main/source/Sources.gz":
return httpResponse(req, http.StatusOK, gz.Bytes()), nil
default:
return httpResponse(req, http.StatusNotFound, []byte("missing")), nil
}
}),
}
r := NewResolver(
WithHTTPClient(client),
WithMirrors([]string{"https://mirror.example/debian"}),
WithSuites([]string{"stable"}),
WithComponents([]string{"main"}),
)
info, err := r.ResolveSource("neofetch")
if err != nil {
t.Fatalf("ResolveSource() error = %v", err)
}
if info.SourcePackage != "neofetch" {
t.Fatalf("unexpected source package: %s", info.SourcePackage)
}
if info.DebianVersion != "7.1.0-4" {
t.Fatalf("unexpected debian version: %s", info.DebianVersion)
}
if info.UpstreamVersion != "7.1.0" {
t.Fatalf("unexpected upstream version: %s", info.UpstreamVersion)
}
wantURL := "https://mirror.example/debian/pool/main/n/neofetch/neofetch_7.1.0-4.dsc"
if info.DSCURL != wantURL {
t.Fatalf("unexpected dsc url:\nwant: %s\ngot: %s", wantURL, info.DSCURL)
}
}
func TestResolveSourceByBinaryName(t *testing.T) {
t.Parallel()
sources := strings.TrimSpace(`
Package: pkgconf
Binary: pkgconf, pkg-config
Version: 2.0.3-1
Directory: pool/main/p/pkgconf
Checksums-Sha256:
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc 1800 pkgconf_2.0.3-1.dsc
`) + "\n"
client := &http.Client{
Transport: roundTripFunc(func(req *http.Request) (*http.Response, error) {
if strings.HasSuffix(req.URL.Path, "/Sources") {
return httpResponse(req, http.StatusOK, []byte(sources)), nil
}
return httpResponse(req, http.StatusNotFound, []byte("missing")), nil
}),
}
r := NewResolver(
WithHTTPClient(client),
WithMirrors([]string{"https://mirror.example/debian"}),
WithSuites([]string{"stable"}),
WithComponents([]string{"main"}),
)
info, err := r.ResolveSource("pkg-config")
if err != nil {
t.Fatalf("ResolveSource() error = %v", err)
}
if info.SourcePackage != "pkgconf" {
t.Fatalf("unexpected source package: %s", info.SourcePackage)
}
wantURL := "https://mirror.example/debian/pool/main/p/pkgconf/pkgconf_2.0.3-1.dsc"
if info.DSCURL != wantURL {
t.Fatalf("unexpected dsc url:\nwant: %s\ngot: %s", wantURL, info.DSCURL)
}
}
func TestResolveSourceHTTPNotFound(t *testing.T) {
t.Parallel()
client := &http.Client{
Transport: roundTripFunc(func(req *http.Request) (*http.Response, error) {
return httpResponse(req, http.StatusNotFound, []byte("not found")), nil
}),
}
r := NewResolver(
WithHTTPClient(client),
WithMirrors([]string{"https://mirror.example/debian"}),
WithSuites([]string{"stable"}),
WithComponents([]string{"main"}),
)
_, err := r.ResolveSource("no-such-package")
if err == nil {
t.Fatalf("expected not found error")
}
if !strings.Contains(err.Error(), "not found") {
t.Fatalf("unexpected error: %v", err)
}
}
func TestParseSourcesParagraph(t *testing.T) {
t.Parallel()
paragraph := []string{
"Package: foo",
"Version: 1:2.3.4-5",
"Directory: pool/main/f/foo",
"Checksums-Sha256:",
" aaaa 10 foo_1:2.3.4-5.dsc",
" bbbb 20 foo_2.3.4.orig.tar.gz",
}
rec, err := parseSourcesParagraph(paragraph)
if err != nil {
t.Fatalf("parseSourcesParagraph() error = %v", err)
}
if rec.Package != "foo" || rec.Version != "1:2.3.4-5" {
t.Fatalf("unexpected record identity: %s %s", rec.Package, rec.Version)
}
if rec.Directory != "pool/main/f/foo" {
t.Fatalf("unexpected directory: %s", rec.Directory)
}
if rec.DSCName != "foo_1:2.3.4-5.dsc" {
t.Fatalf("unexpected dsc name: %s", rec.DSCName)
}
if rec.DSCSHA256 != "aaaa" {
t.Fatalf("unexpected dsc hash: %s", rec.DSCSHA256)
}
if got := normalizeUpstreamVersion(rec.Version); got != "2.3.4" {
t.Fatalf("unexpected normalized version: %s", got)
}
}
func TestResolveSourceInvalidPackageName(t *testing.T) {
t.Parallel()
r := NewResolver()
_, err := r.ResolveSource("bad/name")
if err == nil {
t.Fatalf("expected package name validation error")
}
}
func httpResponse(req *http.Request, status int, body []byte) *http.Response {
return &http.Response{
StatusCode: status,
Body: io.NopCloser(bytes.NewReader(body)),
Header: make(http.Header),
Request: req,
Status: fmt.Sprintf("%d %s", status, http.StatusText(status)),
}
}