Files
zeekayandHanzo Dev 0ac784c33a codec, quantumvm: a lower-case name on the wire reaches an exported Go method
quantumvm registered node's JSON-RPC codec — the one that raises the initial
of the function named after the dot. That codec is now internal/codec, so the
spelling quantumvm serves, quantumvm.getBlock for Service.GetBlock, is decided
in this module.

The spelling is unchanged: an initial that is already upper-case is refused,
and an argument that will not read reports one message. identityvm, keyvm and
bridgevm register gorilla's plain codec and keep it.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-30 14:54:14 -07:00

112 lines
3.6 KiB
Go

// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package codec
import (
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/gorilla/rpc/v2"
"github.com/stretchr/testify/require"
)
// call builds the JSON-RPC request a client would send for the named method.
func call(t *testing.T, method, params string) *http.Request {
t.Helper()
body := `{"jsonrpc":"2.0","id":1,"method":"` + method + `","params":` + params + `}`
r := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(body))
r.Header.Set("Content-Type", "application/json")
return r
}
// TestMethod pins the spelling a client may use. Every name here is one
// quantumvm serves; a change to this table is a change to the wire.
func TestMethod(t *testing.T) {
for _, test := range []struct {
wire, method string
}{
{"quantumvm.getBlock", "quantumvm.GetBlock"},
{"quantumvm.generateCoronaKey", "quantumvm.GenerateCoronaKey"},
{"quantumvm.verifyQuantumSignature", "quantumvm.VerifyQuantumSignature"},
{"quantumvm.getPendingTransactions", "quantumvm.GetPendingTransactions"},
{"quantumvm.getHealth", "quantumvm.GetHealth"},
{"quantumvm.getConfig", "quantumvm.GetConfig"},
} {
t.Run(test.wire, func(t *testing.T) {
method, err := New().NewRequest(call(t, test.wire, "[{}]")).Method()
require.NoError(t, err)
require.Equal(t, test.method, method)
})
}
}
// TestMethodRaised refuses the spelling of the Go method itself, so a service
// answers to one name and not two.
func TestMethodRaised(t *testing.T) {
method, err := New().NewRequest(call(t, "quantumvm.GetBlock", "[{}]")).Method()
require.ErrorIs(t, err, errUppercaseMethod)
require.EqualError(t, err, "method must start with a non-uppercase letter")
require.Equal(t, "quantumvm.GetBlock", method)
}
// TestMethodWhole passes a name carrying no dot through untouched — the server
// rejects it, and the codec does not invent a class for it.
func TestMethodWhole(t *testing.T) {
method, err := New().NewRequest(call(t, "getBlock", "[{}]")).Method()
require.NoError(t, err)
require.Equal(t, "getBlock", method)
}
// TestReadRequest reports one message for arguments of the wrong shape.
func TestReadRequest(t *testing.T) {
request := New().NewRequest(call(t, "quantumvm.getBlock", `["not-an-object"]`))
_, err := request.Method()
require.NoError(t, err)
require.ErrorIs(t, request.ReadRequest(&Args{}), errInvalidArg)
}
type Args struct {
Height uint64 `json:"height"`
}
type Reply struct {
Height uint64 `json:"height"`
}
// service stands in for quantumvm's: an exported Go method, recording that it
// ran.
type service struct{ ran string }
func (s *service) GetBlock(_ *http.Request, a *Args, r *Reply) error {
s.ran = "GetBlock"
r.Height = a.Height
return nil
}
// TestServe drives the whole path a client takes: a lower-case name on the
// wire reaches the exported Go method and its answer comes back.
func TestServe(t *testing.T) {
server := rpc.NewServer()
server.RegisterCodec(New(), "application/json")
served := &service{}
require.NoError(t, server.RegisterService(served, "quantumvm"))
recorder := httptest.NewRecorder()
server.ServeHTTP(recorder, call(t, "quantumvm.getBlock", `[{"height":7}]`))
require.Equal(t, http.StatusOK, recorder.Code)
require.Equal(t, "GetBlock", served.ran)
var answer struct {
Result Reply `json:"result"`
Error *json.RawMessage `json:"error"`
}
require.NoError(t, json.Unmarshal(recorder.Body.Bytes(), &answer))
require.Nil(t, answer.Error)
require.Equal(t, uint64(7), answer.Result.Height)
}