Replay every unanimous upstream status, not just 4xx
openvoxdb does not reserve 5xx for its own faults: the same malformed query is a 400 on /nodes and a 500 on /facts, and /metrics answers a flat 403, so a 4xx-only replay rule made pdbmux's behaviour depend on the route. The meta and metrics handlers held their own copy of the gateway error and bypassed the replay entirely. - Replay any status from 400 up that every backend agreed on, with the backend's own body and content type. - Keep 502 for backends disagreeing on the status, or a backend that answered nothing at all. - Route /pdb/meta, /metrics and the pass-through path through the same rule as the merged query handlers. - Count a unanimous 5xx as a failed round and let it fall back to a stale cache entry; only a unanimous 4xx stays exempt from both. - Answer successful queries with openvoxdb's application/json;charset=utf-8.
This commit is contained in:
+57
-2
@@ -4,6 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -85,9 +86,9 @@ func TestMetaVersion_OneBackendDown(t *testing.T) {
|
||||
|
||||
func TestMetaVersion_AllBackendsDown(t *testing.T) {
|
||||
a := newFakeBackend(t, `[]`, `[]`)
|
||||
a.fail = true
|
||||
a.dead = true
|
||||
b := newFakeBackend(t, `[]`, `[]`)
|
||||
b.fail = true
|
||||
b.dead = true
|
||||
srv := newTestServer(testConfig(a.srv.URL, b.srv.URL, mergeStatic))
|
||||
|
||||
if rec := metaGet(t, srv.Handler(), metaVersionPath); rec.Code != http.StatusBadGateway {
|
||||
@@ -95,6 +96,60 @@ func TestMetaVersion_AllBackendsDown(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// /pdb/meta had its own copy of the gateway error, so a status both backends
|
||||
// agreed on never reached the client. It answers failures the way the query
|
||||
// routes do now.
|
||||
func TestMeta_ReplaysUnanimousUpstreamStatus(t *testing.T) {
|
||||
for _, path := range []string{metaVersionPath, metaServerTimePath} {
|
||||
for _, status := range []int{http.StatusNotFound, http.StatusForbidden, http.StatusInternalServerError} {
|
||||
t.Run(path+"/"+http.StatusText(status), func(t *testing.T) {
|
||||
a := newFakeBackend(t, `[]`, `[]`)
|
||||
b := newFakeBackend(t, `[]`, `[]`)
|
||||
a.reject, a.rejectBody = status, "upstream said no"
|
||||
b.reject, b.rejectBody = status, "upstream said no"
|
||||
srv := newTestServer(testConfig(a.srv.URL, b.srv.URL, mergeStatic))
|
||||
|
||||
rec := metaGet(t, srv.Handler(), path)
|
||||
if rec.Code != status {
|
||||
t.Fatalf("status %d, want the upstream %d: %s", rec.Code, status, rec.Body.String())
|
||||
}
|
||||
if !strings.Contains(rec.Body.String(), "upstream said no") {
|
||||
t.Errorf("body = %q, want the upstream explanation", rec.Body.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMeta_DisagreeingStatusesStay502(t *testing.T) {
|
||||
a := newFakeBackend(t, `[]`, `[]`)
|
||||
b := newFakeBackend(t, `[]`, `[]`)
|
||||
a.reject, a.rejectBody = http.StatusNotFound, "gone"
|
||||
b.reject, b.rejectBody = http.StatusInternalServerError, "boom"
|
||||
srv := newTestServer(testConfig(a.srv.URL, b.srv.URL, mergeStatic))
|
||||
|
||||
if rec := metaGet(t, srv.Handler(), metaVersionPath); rec.Code != http.StatusBadGateway {
|
||||
t.Errorf("status %d, want 502 when backends disagree", rec.Code)
|
||||
}
|
||||
}
|
||||
|
||||
// A replayed body must not name a backend, on /pdb/meta as anywhere else.
|
||||
func TestMeta_ReplayedBodyIsRedacted(t *testing.T) {
|
||||
a := newFakeBackend(t, `[]`, `[]`)
|
||||
b := newFakeBackend(t, `[]`, `[]`)
|
||||
a.reject, a.rejectBody = http.StatusInternalServerError, "upstream "+a.srv.URL+" blew up"
|
||||
b.reject, b.rejectBody = http.StatusInternalServerError, "upstream "+b.srv.URL+" blew up"
|
||||
srv := newTestServer(testConfig(a.srv.URL, b.srv.URL, mergeStatic))
|
||||
|
||||
rec := metaGet(t, srv.Handler(), metaVersionPath)
|
||||
if rec.Code != http.StatusInternalServerError {
|
||||
t.Fatalf("status %d, want the upstream 500", rec.Code)
|
||||
}
|
||||
if strings.Contains(rec.Body.String(), hostOf(t, a.srv.URL)) {
|
||||
t.Errorf("replayed body names a backend: %q", rec.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMetaServerTime_FirstReachableBackend(t *testing.T) {
|
||||
a := newFakeBackend(t, `[]`, `[]`)
|
||||
a.bodies[metaServerTimePath] = `{"server_time":"2026-08-29T01:00:00.000Z"}`
|
||||
|
||||
Reference in New Issue
Block a user