feat(14-03): tide keeps binary upstream bodies and compares every *_url upload by shape

- A response body that is not valid UTF-8 (a cover image) is written as a
  YAML !!binary scalar, never masked and replayed byte for byte
- The upload URL normalizer covers every key ending in _url (cover_url),
  not only url and thumb_url
- README and parity-testing docs updated
This commit is contained in:
Jakub Zych
2026-10-03 21:34:52 +02:00
parent 2ee97c62f6
commit 5101ecb49c
6 changed files with 115 additions and 10 deletions

View File

@@ -286,3 +286,51 @@ func TestUpstreamFakeHashesBase64Bodies(t *testing.T) {
t.Fatalf("mismatch message not clipped: %d bytes", len(err.Error()))
}
}
// TestUpstreamBinaryBodyRoundTrip pins that a response body that is not
// valid UTF-8 (an image) is written as !!binary, kept unmasked, read back
// byte for byte and replayed by the fake unchanged.
func TestUpstreamBinaryBodyRoundTrip(t *testing.T) {
store := upstreamTestStore(t)
store.Set("id:short", "7")
img := "\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01 7 {{ example-token-value \xff\xd9"
s := UpstreamSidecar{Version: 1, Exchanges: []UpstreamExchange{{
Request: UpstreamRequest{Method: "GET", URL: "https://img.example.test/cover.jpg"},
Response: UpstreamResponse{Status: 200, Headers: map[string]string{"Content-Type": "image/jpeg"}, Body: img},
}, {
Request: UpstreamRequest{Method: "GET", URL: "https://api.example.test/v1/me"},
Response: UpstreamResponse{Status: 200, Body: `{"token":"example-token-value"}`},
}}}
path := filepath.Join(t.TempDir(), "bin.upstream.yaml")
if err := WriteUpstream(path, s, store); err != nil {
t.Fatal(err)
}
raw, err := os.ReadFile(path)
if err != nil {
t.Fatal(err)
}
if !bytes.Contains(raw, []byte("body: !!binary "+base64.StdEncoding.EncodeToString([]byte(img)))) {
t.Fatalf("binary body not written as !!binary:\n%s", raw)
}
if !bytes.Contains(raw, []byte(`{{secret:example-token}}`)) {
t.Fatalf("text body not masked:\n%s", raw)
}
got, err := LoadUpstream(path)
if err != nil {
t.Fatal(err)
}
if got.Exchanges[0].Response.Body != img {
t.Fatalf("binary body changed: %q", got.Exchanges[0].Response.Body)
}
fake := NewUpstreamFake(got, store)
req, _ := http.NewRequest(http.MethodGet, "https://img.example.test/cover.jpg", nil)
res, err := fake.RoundTrip(req)
if err != nil {
t.Fatal(err)
}
var buf bytes.Buffer
_, _ = buf.ReadFrom(res.Body)
if buf.String() != img {
t.Fatalf("replayed body %q", buf.String())
}
}