Commit d064eb8e authored by Matthew Slipper's avatar Matthew Slipper Committed by GitHub

Merge pull request #2065 from mslipper/feat/caching-itests

go/proxyd: Add additional itests for cache, changeset
parents f4903adb bb0285bc
---
'@eth-optimism/proxyd': minor
---
Add caching for block-dependent RPCs
...@@ -6,6 +6,8 @@ on: ...@@ -6,6 +6,8 @@ on:
- 'master' - 'master'
- 'develop' - 'develop'
pull_request: pull_request:
paths:
- 'go/proxyd/**'
workflow_dispatch: workflow_dispatch:
defaults: defaults:
...@@ -13,7 +15,9 @@ defaults: ...@@ -13,7 +15,9 @@ defaults:
working-directory: ./go/proxyd working-directory: ./go/proxyd
jobs: jobs:
test: tests:
runs-on: ubuntu-latest
steps: steps:
- name: Install Go - name: Install Go
uses: actions/setup-go@v2 uses: actions/setup-go@v2
......
...@@ -16,12 +16,14 @@ func TestCaching(t *testing.T) { ...@@ -16,12 +16,14 @@ func TestCaching(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
defer redis.Close() defer redis.Close()
backend := NewMockBackend(RPCResponseHandler(map[string]string{ hdlr := NewRPCResponseHandler(map[string]string{
"eth_chainId": "0x420", "eth_chainId": "0x420",
"net_version": "0x1234", "net_version": "0x1234",
"eth_blockNumber": "0x64", "eth_blockNumber": "0x64",
"eth_getBlockByNumber": "dummy_block", "eth_getBlockByNumber": "dummy_block",
})) "eth_call": "dummy_call",
})
backend := NewMockBackend(hdlr)
defer backend.Close() defer backend.Close()
require.NoError(t, os.Setenv("GOOD_BACKEND_RPC_URL", backend.URL())) require.NoError(t, os.Setenv("GOOD_BACKEND_RPC_URL", backend.URL()))
...@@ -36,19 +38,22 @@ func TestCaching(t *testing.T) { ...@@ -36,19 +38,22 @@ func TestCaching(t *testing.T) {
time.Sleep(1500 * time.Millisecond) time.Sleep(1500 * time.Millisecond)
tests := []struct { tests := []struct {
method string method string
params []interface{} params []interface{}
response string response string
backendCalls int
}{ }{
{ {
"eth_chainId", "eth_chainId",
nil, nil,
"{\"jsonrpc\": \"2.0\", \"result\": \"0x420\", \"id\": 999}", "{\"jsonrpc\": \"2.0\", \"result\": \"0x420\", \"id\": 999}",
1,
}, },
{ {
"net_version", "net_version",
nil, nil,
"{\"jsonrpc\": \"2.0\", \"result\": \"0x1234\", \"id\": 999}", "{\"jsonrpc\": \"2.0\", \"result\": \"0x1234\", \"id\": 999}",
1,
}, },
{ {
"eth_getBlockByNumber", "eth_getBlockByNumber",
...@@ -57,23 +62,79 @@ func TestCaching(t *testing.T) { ...@@ -57,23 +62,79 @@ func TestCaching(t *testing.T) {
true, true,
}, },
"{\"jsonrpc\": \"2.0\", \"result\": \"dummy_block\", \"id\": 999}", "{\"jsonrpc\": \"2.0\", \"result\": \"dummy_block\", \"id\": 999}",
1,
},
{
"eth_call",
[]interface{}{
struct {
To string `json:"to"`
}{
"0x1234",
},
"0x60",
},
"{\"id\":999,\"jsonrpc\":\"2.0\",\"result\":\"dummy_call\"}",
1,
},
{
"eth_blockNumber",
nil,
"{\"id\":999,\"jsonrpc\":\"2.0\",\"result\":\"0x64\"}",
0,
},
{
"eth_call",
[]interface{}{
struct {
To string `json:"to"`
}{
"0x1234",
},
"latest",
},
"{\"id\":999,\"jsonrpc\":\"2.0\",\"result\":\"dummy_call\"}",
2,
},
{
"eth_call",
[]interface{}{
struct {
To string `json:"to"`
}{
"0x1234",
},
"pending",
},
"{\"id\":999,\"jsonrpc\":\"2.0\",\"result\":\"dummy_call\"}",
2,
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.method, func(t *testing.T) { t.Run(tt.method, func(t *testing.T) {
_, _, err := client.SendRPC(tt.method, tt.params) resRaw, _, err := client.SendRPC(tt.method, tt.params)
require.NoError(t, err) require.NoError(t, err)
res, _, err := client.SendRPC(tt.method, tt.params) resCache, _, err := client.SendRPC(tt.method, tt.params)
require.NoError(t, err) require.NoError(t, err)
RequireEqualJSON(t, []byte(tt.response), res) RequireEqualJSON(t, []byte(tt.response), resCache)
var count int RequireEqualJSON(t, resRaw, resCache)
for _, req := range backend.Requests() { require.Equal(t, tt.backendCalls, countRequests(backend, tt.method))
if bytes.Contains(req.Body, []byte(tt.method)) {
count++
}
}
require.Equal(t, 1, count)
backend.Reset() backend.Reset()
}) })
} }
hdlr.SetResponse("eth_blockNumber", "0x100")
time.Sleep(1500 * time.Millisecond)
resRaw, _, err := client.SendRPC("eth_blockNumber", nil)
RequireEqualJSON(t, []byte("{\"id\":999,\"jsonrpc\":\"2.0\",\"result\":\"0x100\"}"), resRaw)
}
func countRequests(backend *MockBackend, name string) int {
var count int
for _, req := range backend.Requests() {
if bytes.Contains(req.Body, []byte(name)) {
count++
}
}
return count
} }
...@@ -31,31 +31,48 @@ func SingleResponseHandler(code int, response string) http.HandlerFunc { ...@@ -31,31 +31,48 @@ func SingleResponseHandler(code int, response string) http.HandlerFunc {
} }
} }
func RPCResponseHandler(rpcResponses map[string]string) http.HandlerFunc { type RPCResponseHandler struct {
return func(w http.ResponseWriter, r *http.Request) { mtx sync.RWMutex
body, err := ioutil.ReadAll(r.Body) rpcResponses map[string]string
if err != nil { }
panic(err)
} func NewRPCResponseHandler(rpcResponses map[string]string) *RPCResponseHandler {
req, err := proxyd.ParseRPCReq(body) return &RPCResponseHandler{
if err != nil { rpcResponses: rpcResponses,
panic(err) }
} }
res := rpcResponses[req.Method]
if res == "" { func (h *RPCResponseHandler) SetResponse(method, response string) {
w.WriteHeader(400) h.mtx.Lock()
return defer h.mtx.Unlock()
} h.rpcResponses[method] = response
}
out := &proxyd.RPCRes{
JSONRPC: proxyd.JSONRPCVersion, func (h *RPCResponseHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
Result: res, body, err := ioutil.ReadAll(r.Body)
ID: req.ID, if err != nil {
} panic(err)
enc := json.NewEncoder(w) }
if err := enc.Encode(out); err != nil { req, err := proxyd.ParseRPCReq(body)
panic(err) if err != nil {
} panic(err)
}
h.mtx.RLock()
res := h.rpcResponses[req.Method]
h.mtx.RUnlock()
if res == "" {
w.WriteHeader(400)
return
}
out := &proxyd.RPCRes{
JSONRPC: proxyd.JSONRPCVersion,
Result: res,
ID: req.ID,
}
enc := json.NewEncoder(w)
if err := enc.Encode(out); err != nil {
panic(err)
} }
} }
......
...@@ -25,3 +25,5 @@ backends = ["good"] ...@@ -25,3 +25,5 @@ backends = ["good"]
eth_chainId = "main" eth_chainId = "main"
net_version = "main" net_version = "main"
eth_getBlockByNumber = "main" eth_getBlockByNumber = "main"
eth_blockNumber = "main"
eth_call = "main"
...@@ -7,10 +7,10 @@ import ( ...@@ -7,10 +7,10 @@ import (
) )
func TestRPCResJSON(t *testing.T) { func TestRPCResJSON(t *testing.T) {
tests := []struct{ tests := []struct {
name string name string
in *RPCRes in *RPCRes
out string out string
}{ }{
{ {
"string result", "string result",
...@@ -25,12 +25,12 @@ func TestRPCResJSON(t *testing.T) { ...@@ -25,12 +25,12 @@ func TestRPCResJSON(t *testing.T) {
"object result", "object result",
&RPCRes{ &RPCRes{
JSONRPC: JSONRPCVersion, JSONRPC: JSONRPCVersion,
Result: struct{ Result: struct {
Str string `json:"str"` Str string `json:"str"`
}{ }{
"test", "test",
}, },
ID: []byte("123"), ID: []byte("123"),
}, },
`{"jsonrpc":"2.0","result":{"str":"test"},"id":123}`, `{"jsonrpc":"2.0","result":{"str":"test"},"id":123}`,
}, },
...@@ -48,10 +48,10 @@ func TestRPCResJSON(t *testing.T) { ...@@ -48,10 +48,10 @@ func TestRPCResJSON(t *testing.T) {
&RPCRes{ &RPCRes{
JSONRPC: JSONRPCVersion, JSONRPC: JSONRPCVersion,
Error: &RPCErr{ Error: &RPCErr{
Code: 1234, Code: 1234,
Message: "test err", Message: "test err",
}, },
ID: []byte("123"), ID: []byte("123"),
}, },
`{"jsonrpc":"2.0","error":{"code":1234,"message":"test err"},"id":123}`, `{"jsonrpc":"2.0","error":{"code":1234,"message":"test err"},"id":123}`,
}, },
...@@ -72,4 +72,4 @@ func TestRPCResJSON(t *testing.T) { ...@@ -72,4 +72,4 @@ func TestRPCResJSON(t *testing.T) {
require.Equal(t, tt.out, string(out)) require.Equal(t, tt.out, string(out))
}) })
} }
} }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment