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()))
...@@ -39,16 +41,19 @@ func TestCaching(t *testing.T) { ...@@ -39,16 +41,19 @@ func TestCaching(t *testing.T) {
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)
RequireEqualJSON(t, resRaw, resCache)
require.Equal(t, tt.backendCalls, countRequests(backend, tt.method))
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 var count int
for _, req := range backend.Requests() { for _, req := range backend.Requests() {
if bytes.Contains(req.Body, []byte(tt.method)) { if bytes.Contains(req.Body, []byte(name)) {
count++ count++
} }
} }
require.Equal(t, 1, count) return count
backend.Reset()
})
}
} }
...@@ -31,8 +31,24 @@ func SingleResponseHandler(code int, response string) http.HandlerFunc { ...@@ -31,8 +31,24 @@ 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
rpcResponses map[string]string
}
func NewRPCResponseHandler(rpcResponses map[string]string) *RPCResponseHandler {
return &RPCResponseHandler{
rpcResponses: rpcResponses,
}
}
func (h *RPCResponseHandler) SetResponse(method, response string) {
h.mtx.Lock()
defer h.mtx.Unlock()
h.rpcResponses[method] = response
}
func (h *RPCResponseHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
body, err := ioutil.ReadAll(r.Body) body, err := ioutil.ReadAll(r.Body)
if err != nil { if err != nil {
panic(err) panic(err)
...@@ -41,7 +57,9 @@ func RPCResponseHandler(rpcResponses map[string]string) http.HandlerFunc { ...@@ -41,7 +57,9 @@ func RPCResponseHandler(rpcResponses map[string]string) http.HandlerFunc {
if err != nil { if err != nil {
panic(err) panic(err)
} }
res := rpcResponses[req.Method] h.mtx.RLock()
res := h.rpcResponses[req.Method]
h.mtx.RUnlock()
if res == "" { if res == "" {
w.WriteHeader(400) w.WriteHeader(400)
return return
...@@ -56,7 +74,6 @@ func RPCResponseHandler(rpcResponses map[string]string) http.HandlerFunc { ...@@ -56,7 +74,6 @@ func RPCResponseHandler(rpcResponses map[string]string) http.HandlerFunc {
if err := enc.Encode(out); err != nil { if err := enc.Encode(out); err != nil {
panic(err) panic(err)
} }
}
} }
func NewMockBackend(handler http.Handler) *MockBackend { func NewMockBackend(handler http.Handler) *MockBackend {
......
...@@ -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,7 +7,7 @@ import ( ...@@ -7,7 +7,7 @@ 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
...@@ -25,7 +25,7 @@ func TestRPCResJSON(t *testing.T) { ...@@ -25,7 +25,7 @@ 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",
......
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