test: circuit breaker states, bearer cache-hit, blob dedup, terraform/storage branches
This commit is contained in:
@@ -99,6 +99,13 @@ func mockUpstream(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
w.Write([]byte("protected payload"))
|
||||
case "/protected2.bin": // same challenge as /protected.bin
|
||||
if r.Header.Get("Authorization") != "Bearer minted-token" {
|
||||
w.Header().Set("Www-Authenticate", `Bearer realm="`+upstream.URL+`/token",service="reg",scope="repo:pull"`)
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
w.Write([]byte("protected payload 2"))
|
||||
case "/token":
|
||||
w.Write([]byte(`{"token":"minted-token","expires_in":300}`))
|
||||
default:
|
||||
@@ -285,6 +292,15 @@ func TestBearerTokenFlow(t *testing.T) {
|
||||
t.Error("bearer-protected content mismatch")
|
||||
}
|
||||
|
||||
// A second protected path with the same challenge reuses the cached token.
|
||||
res2, err := testEngine.Fetch(ctx, r, "protected2.bin", p)
|
||||
if err != nil {
|
||||
t.Fatalf("second bearer fetch: %v", err)
|
||||
}
|
||||
if readAll(t, res2) != "protected payload 2" {
|
||||
t.Error("second bearer content mismatch")
|
||||
}
|
||||
|
||||
// HEAD path also negotiates a bearer token (uncached).
|
||||
testCache.FlushRemote(ctx, "eng-bearer")
|
||||
testDB.DeleteArtifact(ctx, "eng-bearer", "protected.bin")
|
||||
@@ -359,6 +375,56 @@ func TestUpstreamErrorUnwrap(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestImmutableBlobDedup(t *testing.T) {
|
||||
requireStack(t)
|
||||
ctx := context.Background()
|
||||
p := prov(t, models.PackageGeneric)
|
||||
// Two remotes serving identical content: the second store hits the
|
||||
// already-exists branch (blob content is deduplicated).
|
||||
for _, name := range []string{"eng-dedup-a", "eng-dedup-b"} {
|
||||
r := seed(t, genericRemote(name))
|
||||
res, err := testEngine.Fetch(ctx, r, "blob.bin", p)
|
||||
if err != nil {
|
||||
t.Fatalf("%s fetch: %v", name, err)
|
||||
}
|
||||
if readAll(t, res) != "immutable blob" {
|
||||
t.Errorf("%s content mismatch", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCircuitBreakerStates(t *testing.T) {
|
||||
requireStack(t)
|
||||
ctx := context.Background()
|
||||
cb := NewCircuitBreaker(testCache)
|
||||
const key = "cb-states"
|
||||
testCache.ResetCircuit(ctx, key)
|
||||
|
||||
if cb.IsOpen(ctx, key) {
|
||||
t.Error("fresh breaker should be closed")
|
||||
}
|
||||
if cb.Health(ctx, key).Status != "healthy" {
|
||||
t.Error("fresh breaker should be healthy")
|
||||
}
|
||||
cb.RecordFailure(ctx, key)
|
||||
if s := cb.Health(ctx, key).Status; s != "degraded" {
|
||||
t.Errorf("one failure should be degraded, got %q", s)
|
||||
}
|
||||
for i := 0; i < 6; i++ {
|
||||
cb.RecordFailure(ctx, key)
|
||||
}
|
||||
if !cb.IsOpen(ctx, key) {
|
||||
t.Error("breaker should be open after threshold failures")
|
||||
}
|
||||
if s := cb.Health(ctx, key).Status; s != "down" {
|
||||
t.Errorf("open breaker should be down, got %q", s)
|
||||
}
|
||||
cb.RecordSuccess(ctx, key)
|
||||
if cb.IsOpen(ctx, key) {
|
||||
t.Error("breaker should close after success")
|
||||
}
|
||||
}
|
||||
|
||||
func asProxyError(err error, target **ProxyError) bool {
|
||||
pe, ok := err.(*ProxyError)
|
||||
if ok {
|
||||
|
||||
@@ -12,7 +12,10 @@ import (
|
||||
"git.unkin.net/unkin/artifactapi/internal/testsupport"
|
||||
)
|
||||
|
||||
var testS3 *S3
|
||||
var (
|
||||
testS3 *S3
|
||||
testEndpoint string
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
ctx := context.Background()
|
||||
@@ -32,6 +35,7 @@ func TestMain(m *testing.M) {
|
||||
panic(err)
|
||||
}
|
||||
testS3 = s3
|
||||
testEndpoint = conn.Endpoint
|
||||
code := m.Run()
|
||||
terminate()
|
||||
if code != 0 {
|
||||
@@ -95,6 +99,15 @@ func TestS3RoundTrip(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewS3ExistingBucket(t *testing.T) {
|
||||
requireS3(t)
|
||||
// The bucket already exists from TestMain, so ensureBucket takes the
|
||||
// "already present" path.
|
||||
if _, err := NewS3(testEndpoint, "minioadmin", "minioadmin", "test-bucket", false, ""); err != nil {
|
||||
t.Fatalf("second NewS3: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestS3DownloadMissing(t *testing.T) {
|
||||
requireS3(t)
|
||||
if _, _, err := testS3.Download(context.Background(), "does/not/exist"); err == nil {
|
||||
|
||||
Reference in New Issue
Block a user