1
0
Fork 1
mirror of https://github.com/git-pkgs/proxy.git synced 2026-06-02 16:48:16 -04:00
pkg-proxy/internal/handler/gradle_test.go

285 lines
8.1 KiB
Go
Raw Permalink Normal View History

package handler
import (
"io"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/git-pkgs/proxy/internal/metrics"
"github.com/prometheus/client_golang/prometheus/testutil"
)
func TestGradleBuildCacheHandler_PutGetHead(t *testing.T) {
proxy, _, _, _ := setupTestProxy(t)
h := NewGradleBuildCacheHandler(proxy)
srv := httptest.NewServer(h.Routes())
defer srv.Close()
key := "a1b2c3d4e5f6"
payload := "cache entry content"
putReq, err := http.NewRequest(http.MethodPut, srv.URL+"/"+key, strings.NewReader(payload))
if err != nil {
t.Fatalf("failed to create PUT request: %v", err)
}
putResp, err := http.DefaultClient.Do(putReq)
if err != nil {
t.Fatalf("PUT request failed: %v", err)
}
_ = putResp.Body.Close()
if putResp.StatusCode != http.StatusCreated {
t.Fatalf("PUT status = %d, want %d", putResp.StatusCode, http.StatusCreated)
}
getResp, err := http.Get(srv.URL + "/" + key)
if err != nil {
t.Fatalf("GET request failed: %v", err)
}
defer func() { _ = getResp.Body.Close() }()
if getResp.StatusCode != http.StatusOK {
t.Fatalf("GET status = %d, want %d", getResp.StatusCode, http.StatusOK)
}
if getResp.Header.Get("Content-Type") != gradleBuildCacheContentType {
t.Fatalf("GET Content-Type = %q, want %q", getResp.Header.Get("Content-Type"), gradleBuildCacheContentType)
}
body, _ := io.ReadAll(getResp.Body)
if string(body) != payload {
t.Fatalf("GET body = %q, want %q", body, payload)
}
headReq, err := http.NewRequest(http.MethodHead, srv.URL+"/"+key, nil)
if err != nil {
t.Fatalf("failed to create HEAD request: %v", err)
}
headResp, err := http.DefaultClient.Do(headReq)
if err != nil {
t.Fatalf("HEAD request failed: %v", err)
}
defer func() { _ = headResp.Body.Close() }()
if headResp.StatusCode != http.StatusOK {
t.Fatalf("HEAD status = %d, want %d", headResp.StatusCode, http.StatusOK)
}
body, _ = io.ReadAll(headResp.Body)
if len(body) != 0 {
t.Fatalf("HEAD body length = %d, want 0", len(body))
}
}
func TestGradleBuildCacheHandler_RootKeyPath(t *testing.T) {
proxy, _, _, _ := setupTestProxy(t)
h := NewGradleBuildCacheHandler(proxy)
srv := httptest.NewServer(h.Routes())
defer srv.Close()
key := "rootpathkey"
putReq, err := http.NewRequest(http.MethodPut, srv.URL+"/"+key, strings.NewReader("root"))
if err != nil {
t.Fatalf("failed to create PUT request: %v", err)
}
putResp, err := http.DefaultClient.Do(putReq)
if err != nil {
t.Fatalf("PUT request failed: %v", err)
}
_ = putResp.Body.Close()
if putResp.StatusCode != http.StatusCreated {
t.Fatalf("PUT status = %d, want %d", putResp.StatusCode, http.StatusCreated)
}
getResp, err := http.Get(srv.URL + "/" + key)
if err != nil {
t.Fatalf("GET request failed: %v", err)
}
defer func() { _ = getResp.Body.Close() }()
if getResp.StatusCode != http.StatusOK {
t.Fatalf("GET status = %d, want %d", getResp.StatusCode, http.StatusOK)
}
}
func TestGradleBuildCacheHandler_GetMiss(t *testing.T) {
proxy, _, _, _ := setupTestProxy(t)
h := NewGradleBuildCacheHandler(proxy)
srv := httptest.NewServer(h.Routes())
defer srv.Close()
resp, err := http.Get(srv.URL + "/missing-key")
if err != nil {
t.Fatalf("GET request failed: %v", err)
}
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusNotFound {
t.Fatalf("status = %d, want %d", resp.StatusCode, http.StatusNotFound)
}
}
func TestGradleBuildCacheHandler_MethodNotAllowed(t *testing.T) {
proxy, _, _, _ := setupTestProxy(t)
h := NewGradleBuildCacheHandler(proxy)
req := httptest.NewRequest(http.MethodPost, "/key", nil)
w := httptest.NewRecorder()
h.Routes().ServeHTTP(w, req)
if w.Code != http.StatusMethodNotAllowed {
t.Fatalf("status = %d, want %d", w.Code, http.StatusMethodNotAllowed)
}
}
func TestGradleBuildCacheHandler_PathTraversalRejected(t *testing.T) {
proxy, _, _, _ := setupTestProxy(t)
h := NewGradleBuildCacheHandler(proxy)
req := httptest.NewRequest(http.MethodGet, "/../secret", nil)
w := httptest.NewRecorder()
h.Routes().ServeHTTP(w, req)
if w.Code != http.StatusBadRequest {
t.Fatalf("status = %d, want %d", w.Code, http.StatusBadRequest)
}
}
func TestGradleBuildCacheHandler_CachePrefixRejected(t *testing.T) {
proxy, _, _, _ := setupTestProxy(t)
h := NewGradleBuildCacheHandler(proxy)
req := httptest.NewRequest(http.MethodGet, "/cache/key", nil)
w := httptest.NewRecorder()
h.Routes().ServeHTTP(w, req)
if w.Code != http.StatusNotFound {
t.Fatalf("status = %d, want %d", w.Code, http.StatusNotFound)
}
}
func TestGradleBuildCacheHandler_PutOverwriteReturnsCreated(t *testing.T) {
proxy, _, _, _ := setupTestProxy(t)
h := NewGradleBuildCacheHandler(proxy)
srv := httptest.NewServer(h.Routes())
defer srv.Close()
key := "overwrite-key"
for i, payload := range []string{"first", "second"} {
req, err := http.NewRequest(http.MethodPut, srv.URL+"/"+key, strings.NewReader(payload))
if err != nil {
t.Fatalf("failed to create PUT request: %v", err)
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
t.Fatalf("PUT request failed: %v", err)
}
_ = resp.Body.Close()
want := http.StatusCreated
if resp.StatusCode != want {
t.Fatalf("PUT #%d status = %d, want %d", i+1, resp.StatusCode, want)
}
}
}
func TestGradleBuildCacheHandler_PutReadOnly(t *testing.T) {
proxy, _, _, _ := setupTestProxy(t)
proxy.GradleReadOnly = true
h := NewGradleBuildCacheHandler(proxy)
srv := httptest.NewServer(h.Routes())
defer srv.Close()
req, err := http.NewRequest(http.MethodPut, srv.URL+"/readonly-key", strings.NewReader("payload"))
if err != nil {
t.Fatalf("failed to create PUT request: %v", err)
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
t.Fatalf("PUT request failed: %v", err)
}
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusMethodNotAllowed {
t.Fatalf("PUT status = %d, want %d", resp.StatusCode, http.StatusMethodNotAllowed)
}
}
func TestGradleBuildCacheHandler_PutTooLarge(t *testing.T) {
proxy, _, _, _ := setupTestProxy(t)
proxy.GradleMaxUploadSize = 4
h := NewGradleBuildCacheHandler(proxy)
srv := httptest.NewServer(h.Routes())
defer srv.Close()
req, err := http.NewRequest(http.MethodPut, srv.URL+"/oversized-key", strings.NewReader("12345"))
if err != nil {
t.Fatalf("failed to create PUT request: %v", err)
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
t.Fatalf("PUT request failed: %v", err)
}
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusRequestEntityTooLarge {
t.Fatalf("PUT status = %d, want %d", resp.StatusCode, http.StatusRequestEntityTooLarge)
}
}
func TestGradleBuildCacheHandler_RecordsMetrics(t *testing.T) {
proxy, _, _, _ := setupTestProxy(t)
h := NewGradleBuildCacheHandler(proxy)
srv := httptest.NewServer(h.Routes())
defer srv.Close()
hitsBefore := testutil.ToFloat64(metrics.CacheHits.WithLabelValues("gradle"))
missesBefore := testutil.ToFloat64(metrics.CacheMisses.WithLabelValues("gradle"))
key := "metrics-key"
putReq, err := http.NewRequest(http.MethodPut, srv.URL+"/"+key, strings.NewReader("payload"))
if err != nil {
t.Fatalf("failed to create PUT request: %v", err)
}
putResp, err := http.DefaultClient.Do(putReq)
if err != nil {
t.Fatalf("PUT request failed: %v", err)
}
_ = putResp.Body.Close()
getResp, err := http.Get(srv.URL + "/" + key)
if err != nil {
t.Fatalf("GET request failed: %v", err)
}
_ = getResp.Body.Close()
headReq, err := http.NewRequest(http.MethodHead, srv.URL+"/"+key, nil)
if err != nil {
t.Fatalf("failed to create HEAD request: %v", err)
}
headResp, err := http.DefaultClient.Do(headReq)
if err != nil {
t.Fatalf("HEAD request failed: %v", err)
}
_ = headResp.Body.Close()
missResp, err := http.Get(srv.URL + "/missing-key")
if err != nil {
t.Fatalf("GET miss request failed: %v", err)
}
_ = missResp.Body.Close()
hitsAfter := testutil.ToFloat64(metrics.CacheHits.WithLabelValues("gradle"))
missesAfter := testutil.ToFloat64(metrics.CacheMisses.WithLabelValues("gradle"))
if diff := hitsAfter - hitsBefore; diff != 2 {
t.Fatalf("cache hits delta = %.0f, want 2", diff)
}
if diff := missesAfter - missesBefore; diff != 1 {
t.Fatalf("cache misses delta = %.0f, want 1", diff)
}
}