Files
maker/dexhttp_test.go

106 lines
3.4 KiB
Go

package maker
import (
"context"
"io"
"net/http"
"net/http/httptest"
"testing"
)
// TestHTTPDEXClientRoutesAndBody proves the native HTTP transport maps
// CallRaw(method, payload) to a POST of the verbatim payload at
// <base>/dex/<method> and returns the raw response body unchanged — the exact
// route shape luxd mounts for the in-luxd D-Chain VM (dex/pkg/dchain/ingest.go:
// /v1/chain/<chainID>/dex/<method>).
func TestHTTPDEXClientRoutesAndBody(t *testing.T) {
const method = "clob_submit"
wantPath := "/v1/chain/D/dex/" + method
reqBody := []byte{0xDE, 0xAD, 0xBE, 0xEF}
respBody := []byte{0x00, 0x00, 0x00, 0x00} // a zero-fills frame
var gotPath, gotMethod, gotCT string
var gotBody []byte
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
gotPath = r.URL.Path
gotMethod = r.Method
gotCT = r.Header.Get("Content-Type")
gotBody, _ = io.ReadAll(r.Body)
w.Header().Set("Content-Type", "application/octet-stream")
w.WriteHeader(http.StatusOK)
_, _ = w.Write(respBody)
}))
defer srv.Close()
c := newHTTPDEXClient(srv.URL + "/v1/chain/D")
got, err := c.CallRaw(context.Background(), method, reqBody)
if err != nil {
t.Fatalf("CallRaw: %v", err)
}
if gotMethod != http.MethodPost {
t.Errorf("method = %q, want POST", gotMethod)
}
if gotPath != wantPath {
t.Errorf("path = %q, want %q", gotPath, wantPath)
}
if gotCT != "application/octet-stream" {
t.Errorf("content-type = %q, want application/octet-stream", gotCT)
}
if string(gotBody) != string(reqBody) {
t.Errorf("request body = %x, want %x", gotBody, reqBody)
}
if string(got) != string(respBody) {
t.Errorf("response body = %x, want %x", got, respBody)
}
}
// TestHTTPDEXClientTrimsTrailingSlash proves a base with a trailing slash still
// yields exactly one separator before /dex (no double slash that would 404).
func TestHTTPDEXClientTrimsTrailingSlash(t *testing.T) {
var gotPath string
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
gotPath = r.URL.Path
w.WriteHeader(http.StatusOK)
}))
defer srv.Close()
c := newHTTPDEXClient(srv.URL + "/v1/chain/D/")
if _, err := c.CallRaw(context.Background(), "clob_place", []byte{1}); err != nil {
t.Fatalf("CallRaw: %v", err)
}
if want := "/v1/chain/D/dex/clob_place"; gotPath != want {
t.Errorf("path = %q, want %q", gotPath, want)
}
}
// TestHTTPDEXClientNon200IsError proves a non-200 status is surfaced as an error
// carrying the code and body — the pre-fix node 404 (route not served) and the
// VM 502 (op could not be sequenced) are never silently swallowed into a
// success. A 404 in particular is the signal that the fix is NOT loaded.
func TestHTTPDEXClientNon200IsError(t *testing.T) {
for _, tc := range []struct {
name string
code int
body string
}{
{"not-found", http.StatusNotFound, "404 page not found"},
{"bad-gateway", http.StatusBadGateway, "clob_submit: short payload: 3"},
{"method-not-allowed", http.StatusMethodNotAllowed, "method not allowed"},
} {
t.Run(tc.name, func(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(tc.code)
_, _ = io.WriteString(w, tc.body)
}))
defer srv.Close()
c := newHTTPDEXClient(srv.URL + "/v1/chain/D")
_, err := c.CallRaw(context.Background(), "clob_submit", []byte{1, 2, 3})
if err == nil {
t.Fatalf("expected error for status %d, got nil", tc.code)
}
})
}
}