mirror of
https://github.com/git-pkgs/proxy.git
synced 2026-11-09 15:49:16 -05:00
proxy list and proxy delete sat next to serve, stats and mirror and read as cache operations. The commands are now proxy hosted push, proxy hosted list and proxy hosted delete, before a release makes the names hard to change. proxy hosted without a known subcommand prints the three. Refs #133
167 lines
6.7 KiB
Go
167 lines
6.7 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
type recordedRequest struct {
|
|
method, path, query, authorization, body string
|
|
}
|
|
|
|
func hostedTestServer(t *testing.T, status int, response string) (*httptest.Server, *recordedRequest) {
|
|
t.Helper()
|
|
recorded := &recordedRequest{}
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
body, _ := io.ReadAll(r.Body)
|
|
*recorded = recordedRequest{
|
|
method: r.Method,
|
|
path: r.URL.EscapedPath(),
|
|
query: r.URL.RawQuery,
|
|
authorization: r.Header.Get("Authorization"),
|
|
body: string(body),
|
|
}
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(status)
|
|
_, _ = io.WriteString(w, response)
|
|
}))
|
|
t.Cleanup(srv.Close)
|
|
return srv, recorded
|
|
}
|
|
|
|
func hostedEnv(vars map[string]string) func(string) string {
|
|
return func(key string) string { return vars[key] }
|
|
}
|
|
|
|
func writeArchive(t *testing.T, name, content string) string {
|
|
t.Helper()
|
|
path := filepath.Join(t.TempDir(), name)
|
|
if err := os.WriteFile(path, []byte(content), 0o600); err != nil {
|
|
t.Fatalf("writing archive: %v", err)
|
|
}
|
|
return path
|
|
}
|
|
|
|
func TestRunPush(t *testing.T) {
|
|
srv, recorded := hostedTestServer(t, http.StatusCreated,
|
|
`{"ecosystem":"npm","name":"@types/node","version":"20.1.0","filename":"node-20.1.0.tgz","sha256":"abc123","size":7}`)
|
|
archive := writeArchive(t, "node-20.1.0.tgz", "tarball")
|
|
var stdout bytes.Buffer
|
|
|
|
err := runPush([]string{"-url", srv.URL, "npm", "@types/node", "20.1.0", archive},
|
|
hostedEnv(map[string]string{"PROXY_HOSTED_TOKEN": "tok"}), &stdout, srv.Client())
|
|
if err != nil {
|
|
t.Fatalf("runPush: %v", err)
|
|
}
|
|
if recorded.method != http.MethodPut || recorded.path != "/api/hosted/npm/@types/node/20.1.0" {
|
|
t.Errorf("request = %s %s", recorded.method, recorded.path)
|
|
}
|
|
if recorded.authorization != "Bearer tok" || recorded.body != "tarball" || recorded.query != "" {
|
|
t.Errorf("authorization/body/query = %q/%q/%q", recorded.authorization, recorded.body, recorded.query)
|
|
}
|
|
if out := stdout.String(); !strings.Contains(out, "node-20.1.0.tgz") || !strings.Contains(out, "abc123") {
|
|
t.Errorf("output = %q, want filename and sha256", out)
|
|
}
|
|
}
|
|
|
|
func TestRunPushErrors(t *testing.T) {
|
|
srv, _ := hostedTestServer(t, http.StatusBadRequest, `{"code":"BAD_REQUEST","message":"pushing packages is not supported for this ecosystem: cargo"}`)
|
|
archive := writeArchive(t, "serde-1.0.200.crate", "crate")
|
|
|
|
err := runPush([]string{"-url", srv.URL, "cargo", "serde", "1.0.200", archive}, hostedEnv(nil), io.Discard, srv.Client())
|
|
if err == nil || !strings.Contains(err.Error(), "PROXY_HOSTED_TOKEN") {
|
|
t.Errorf("push without token error = %v, want a PROXY_HOSTED_TOKEN hint", err)
|
|
}
|
|
|
|
err = runPush([]string{"-url", srv.URL, "cargo", "serde", "1.0.200", archive},
|
|
hostedEnv(map[string]string{"PROXY_HOSTED_TOKEN": "tok"}), io.Discard, srv.Client())
|
|
if err == nil || !strings.Contains(err.Error(), "not supported for this ecosystem") {
|
|
t.Errorf("rejected push error = %v, want the server's message", err)
|
|
}
|
|
|
|
err = runPush([]string{"-url", srv.URL, "npm", "request"}, hostedEnv(map[string]string{"PROXY_HOSTED_TOKEN": "tok"}), io.Discard, srv.Client())
|
|
if err == nil || !strings.Contains(err.Error(), "usage") {
|
|
t.Errorf("push with missing arguments error = %v, want usage", err)
|
|
}
|
|
}
|
|
|
|
func TestRunPushUsesProxyURLFromEnv(t *testing.T) {
|
|
srv, recorded := hostedTestServer(t, http.StatusCreated, `{}`)
|
|
archive := writeArchive(t, "request-2.88.3.tgz", "tarball")
|
|
|
|
err := runPush([]string{"npm", "request", "2.88.3", archive},
|
|
hostedEnv(map[string]string{"PROXY_HOSTED_TOKEN": "tok", "PROXY_URL": srv.URL}), io.Discard, srv.Client())
|
|
if err != nil {
|
|
t.Fatalf("runPush: %v", err)
|
|
}
|
|
if recorded.path != "/api/hosted/npm/request/2.88.3" {
|
|
t.Errorf("path = %q", recorded.path)
|
|
}
|
|
}
|
|
|
|
func TestRunList(t *testing.T) {
|
|
srv, recorded := hostedTestServer(t, http.StatusOK,
|
|
`{"ecosystem":"npm","name":"request","artifacts":[{"version":"2.88.3","filename":"request-2.88.3.tgz","sha256":"abc123","size":7,"pushed_at":"2026-10-13T10:00:00Z"}]}`)
|
|
var stdout bytes.Buffer
|
|
|
|
if err := runList([]string{"-url", srv.URL, "npm", "request"}, hostedEnv(nil), &stdout, srv.Client()); err != nil {
|
|
t.Fatalf("runList: %v", err)
|
|
}
|
|
if recorded.method != http.MethodGet || recorded.path != "/api/hosted/npm/request" || recorded.authorization != "" {
|
|
t.Errorf("request = %s %s (authorization %q)", recorded.method, recorded.path, recorded.authorization)
|
|
}
|
|
if out := stdout.String(); !strings.Contains(out, "2.88.3") || !strings.Contains(out, "request-2.88.3.tgz") {
|
|
t.Errorf("output = %q", out)
|
|
}
|
|
}
|
|
|
|
func TestRunDelete(t *testing.T) {
|
|
srv, recorded := hostedTestServer(t, http.StatusNoContent, "")
|
|
|
|
err := runDelete([]string{"-url", srv.URL, "npm", "request", "2.88.3"},
|
|
hostedEnv(map[string]string{"PROXY_HOSTED_TOKEN": "tok"}), io.Discard, srv.Client())
|
|
if err != nil {
|
|
t.Fatalf("runDelete: %v", err)
|
|
}
|
|
if recorded.method != http.MethodDelete || recorded.path != "/api/hosted/npm/request/2.88.3" || recorded.authorization != "Bearer tok" {
|
|
t.Errorf("request = %s %s (authorization %q)", recorded.method, recorded.path, recorded.authorization)
|
|
}
|
|
|
|
missing, _ := hostedTestServer(t, http.StatusNotFound, `{"code":"NOT_FOUND","message":"no pushed artifacts for this version"}`)
|
|
err = runDelete([]string{"-url", missing.URL, "npm", "request", "2.88.3"},
|
|
hostedEnv(map[string]string{"PROXY_HOSTED_TOKEN": "tok"}), io.Discard, missing.Client())
|
|
if err == nil || !strings.Contains(err.Error(), "no pushed artifacts") {
|
|
t.Errorf("delete of a missing version error = %v", err)
|
|
}
|
|
}
|
|
|
|
func TestRunHostedDispatchesSubcommands(t *testing.T) {
|
|
srv, recorded := hostedTestServer(t, http.StatusOK, `{"ecosystem":"npm","name":"request","artifacts":[]}`)
|
|
|
|
if err := runHosted([]string{"list", "-url", srv.URL, "npm", "request"}, hostedEnv(nil), io.Discard, srv.Client()); err != nil {
|
|
t.Fatalf("runHosted list: %v", err)
|
|
}
|
|
if recorded.method != http.MethodGet || recorded.path != "/api/hosted/npm/request" {
|
|
t.Errorf("request = %s %s", recorded.method, recorded.path)
|
|
}
|
|
|
|
for _, args := range [][]string{nil, {"bogus"}} {
|
|
err := runHosted(args, hostedEnv(nil), io.Discard, srv.Client())
|
|
if err == nil || !strings.Contains(err.Error(), "usage: proxy hosted <push|list|delete>") {
|
|
t.Errorf("runHosted(%q) error = %v, want the hosted usage", args, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestHostedSubcommandUsageNamesTheHostedCommand(t *testing.T) {
|
|
err := runPush([]string{"npm"}, hostedEnv(map[string]string{"PROXY_HOSTED_TOKEN": "tok"}), io.Discard, http.DefaultClient)
|
|
if err == nil || !strings.Contains(err.Error(), "usage: proxy hosted push") {
|
|
t.Errorf("push usage error = %v, want it to name proxy hosted push", err)
|
|
}
|
|
}
|