Skip to content

Commit

Permalink
Merge pull request #59 from VeerChaurasia/Testing-for-consensus/rpc
Browse files Browse the repository at this point in the history
Unit Testing for consensus/rpc
  • Loading branch information
star-gazer111 authored Sep 27, 2024
2 parents 505590b + e12e28e commit 987f84f
Show file tree
Hide file tree
Showing 5 changed files with 377 additions and 0 deletions.
84 changes: 84 additions & 0 deletions consensus/rpc/consensus_rpc_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package rpc
import (
"testing"
"github.com/BlocSoc-iitr/selene/consensus/consensus_core"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
// MockConsensusRpc is a mock implementation of the ConsensusRpc interface
type MockConsensusRpc struct {
mock.Mock
}
func (m *MockConsensusRpc) GetBootstrap(block_root [32]byte) (consensus_core.Bootstrap, error) {
args := m.Called(block_root)
return args.Get(0).(consensus_core.Bootstrap), args.Error(1)
}
func (m *MockConsensusRpc) GetUpdates(period uint64, count uint8) ([]consensus_core.Update, error) {
args := m.Called(period, count)
return args.Get(0).([]consensus_core.Update), args.Error(1)
}
func (m *MockConsensusRpc) GetFinalityUpdate() (consensus_core.FinalityUpdate, error) {
args := m.Called()
return args.Get(0).(consensus_core.FinalityUpdate), args.Error(1)
}
func (m *MockConsensusRpc) GetOptimisticUpdate() (consensus_core.OptimisticUpdate, error) {
args := m.Called()
return args.Get(0).(consensus_core.OptimisticUpdate), args.Error(1)
}
func (m *MockConsensusRpc) GetBlock(slot uint64) (consensus_core.BeaconBlock, error) {
args := m.Called(slot)
return args.Get(0).(consensus_core.BeaconBlock), args.Error(1)
}
func (m *MockConsensusRpc) ChainId() (uint64, error) {
args := m.Called()
return args.Get(0).(uint64), args.Error(1)
}
func TestNewConsensusRpc(t *testing.T) {
rpcURL := "http://example.com"
consensusRpc := NewConsensusRpc(rpcURL)
assert.Implements(t, (*ConsensusRpc)(nil), consensusRpc)
_, ok := consensusRpc.(*NimbusRpc)
assert.True(t, ok, "NewConsensusRpc should return a *NimbusRpc")
}

func TestConsensusRpcInterface(t *testing.T) {
mockRpc := new(MockConsensusRpc)
// Test GetBootstrap
mockBootstrap := consensus_core.Bootstrap{Header: consensus_core.Header{Slot: 1000}}
mockRpc.On("GetBootstrap", mock.Anything).Return(mockBootstrap, nil)
bootstrap, err := mockRpc.GetBootstrap([32]byte{})
assert.NoError(t, err)
assert.Equal(t, uint64(1000), bootstrap.Header.Slot)
// Test GetUpdates
mockUpdates := []consensus_core.Update{{AttestedHeader: consensus_core.Header{Slot: 2000}}}
mockRpc.On("GetUpdates", uint64(1), uint8(5)).Return(mockUpdates, nil)
updates, err := mockRpc.GetUpdates(1, 5)
assert.NoError(t, err)
assert.Equal(t, uint64(2000), updates[0].AttestedHeader.Slot)
// Test GetFinalityUpdate
mockFinalityUpdate := consensus_core.FinalityUpdate{FinalizedHeader: consensus_core.Header{Slot: 3000}}
mockRpc.On("GetFinalityUpdate").Return(mockFinalityUpdate, nil)
finalityUpdate, err := mockRpc.GetFinalityUpdate()
assert.NoError(t, err)
assert.Equal(t, uint64(3000), finalityUpdate.FinalizedHeader.Slot)
// Test GetOptimisticUpdate
mockOptimisticUpdate := consensus_core.OptimisticUpdate{SignatureSlot: 4000}
mockRpc.On("GetOptimisticUpdate").Return(mockOptimisticUpdate, nil)
optimisticUpdate, err := mockRpc.GetOptimisticUpdate()
assert.NoError(t, err)
assert.Equal(t, uint64(4000), optimisticUpdate.SignatureSlot)
// Test GetBlock
mockBlock := consensus_core.BeaconBlock{Slot: 5000}
mockRpc.On("GetBlock", uint64(5000)).Return(mockBlock, nil)
block, err := mockRpc.GetBlock(5000)
assert.NoError(t, err)
assert.Equal(t, uint64(5000), block.Slot)
// Test ChainId
mockChainId := uint64(1)
mockRpc.On("ChainId").Return(mockChainId, nil)
chainId, err := mockRpc.ChainId()
assert.NoError(t, err)
assert.Equal(t, uint64(1), chainId)
// Assert that all expected mock calls were made
mockRpc.AssertExpectations(t)
}
163 changes: 163 additions & 0 deletions consensus/rpc/mock_rpc_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
package rpc
import (
"encoding/json"
"os"
"path/filepath"
"testing"

"github.com/BlocSoc-iitr/selene/consensus/consensus_core"
)
func TestNewMockRpc(t *testing.T) {
path := "/tmp/testdata"
mockRpc := NewMockRpc(path)
if mockRpc.testdata != path {
t.Errorf("Expected testdata path to be %s, got %s", path, mockRpc.testdata)
}
}
func TestGetBootstrap(t *testing.T) {
tempDir, err := os.MkdirTemp("", "mock_rpc_test")
if err != nil {
t.Fatalf("Failed to create temp dir: %v", err)
}
defer os.RemoveAll(tempDir)
mockBootstrap := BootstrapResponse{
Data: consensus_core.Bootstrap{
Header: consensus_core.Header{
Slot: 1000,
},
},
}
bootstrapJSON, _ := json.Marshal(mockBootstrap)
err = os.WriteFile(filepath.Join(tempDir, "bootstrap.json"), bootstrapJSON, 0644)
if err != nil {
t.Fatalf("Failed to write mock bootstrap file: %v", err)
}
mockRpc := NewMockRpc(tempDir)
bootstrap, err := mockRpc.GetBootstrap([]byte{})
if err != nil {
t.Fatalf("GetBootstrap failed: %v", err)
}
if bootstrap.Header.Slot != 1000 {
t.Errorf("Expected bootstrap slot to be 1000, got %d", bootstrap.Header.Slot)
}
}
func TestGetUpdates(t *testing.T) {
tempDir, err := os.MkdirTemp("", "mock_rpc_test")
if err != nil {
t.Fatalf("Failed to create temp dir: %v", err)
}
defer os.RemoveAll(tempDir)
mockUpdates := UpdateResponse{
{Data: consensus_core.Update{SignatureSlot: 1}},
{Data: consensus_core.Update{SignatureSlot: 2}},
}
updatesJSON, _ := json.Marshal(mockUpdates)
err = os.WriteFile(filepath.Join(tempDir, "updates.json"), updatesJSON, 0644)
if err != nil {
t.Fatalf("Failed to write mock updates file: %v", err)
}
mockRpc := NewMockRpc(tempDir)
updates, err := mockRpc.GetUpdates(1, 2)
if err != nil {
t.Fatalf("GetUpdates failed: %v", err)
}
if len(updates) != 2 {
t.Errorf("Expected 2 updates, got %d", len(updates))
}
if updates[0].SignatureSlot != 1 || updates[1].SignatureSlot != 2 {
t.Errorf("Unexpected update signature slots")
}
}
func TestGetFinalityUpdate(t *testing.T) {
tempDir, err := os.MkdirTemp("", "mock_rpc_test")
if err != nil {
t.Fatalf("Failed to create temp dir: %v", err)
}
defer os.RemoveAll(tempDir)
mockFinality := FinalityUpdateResponse{
Data: consensus_core.FinalityUpdate{
FinalizedHeader: consensus_core.Header{
Slot: 2000,
},
},
}
finalityJSON, _ := json.Marshal(mockFinality)
err = os.WriteFile(filepath.Join(tempDir, "finality.json"), finalityJSON, 0644)
if err != nil {
t.Fatalf("Failed to write mock finality file: %v", err)
}
mockRpc := NewMockRpc(tempDir)
finality, err := mockRpc.GetFinalityUpdate()
if err != nil {
t.Fatalf("GetFinalityUpdate failed: %v", err)
}
if finality.FinalizedHeader.Slot != 2000 {
t.Errorf("Expected finality slot to be 2000, got %d", finality.FinalizedHeader.Slot)
}
}
func TestGetOptimisticUpdate(t *testing.T) {
tempDir, err := os.MkdirTemp("", "mock_rpc_test")
if err != nil {
t.Fatalf("Failed to create temp dir: %v", err)
}
defer os.RemoveAll(tempDir)
mockOptimistic := OptimisticUpdateResponse{
Data: consensus_core.OptimisticUpdate{
SignatureSlot: 3000,
},
}
optimisticJSON, _ := json.Marshal(mockOptimistic)
err = os.WriteFile(filepath.Join(tempDir, "optimistic.json"), optimisticJSON, 0644)
if err != nil {
t.Fatalf("Failed to write mock optimistic file: %v", err)
}
mockRpc := NewMockRpc(tempDir)
optimistic, err := mockRpc.GetOptimisticUpdate()
if err != nil {
t.Fatalf("GetOptimisticUpdate failed: %v", err)
}
if optimistic.SignatureSlot != 3000 {
t.Errorf("Expected optimistic signature slot to be 3000, got %d", optimistic.SignatureSlot)
}
}
func TestGetBlock(t *testing.T) {
tempDir, err := os.MkdirTemp("", "mock_rpc_test")
if err != nil {
t.Fatalf("Failed to create temp dir: %v", err)
}
defer os.RemoveAll(tempDir)
blocksDir := filepath.Join(tempDir, "blocks")
err = os.Mkdir(blocksDir, 0755)
if err != nil {
t.Fatalf("Failed to create blocks directory: %v", err)
}
mockBlock := BeaconBlockResponse{
Data: struct {
Message consensus_core.BeaconBlock
}{
Message: consensus_core.BeaconBlock{
Slot: 4000,
},
},
}
blockJSON, _ := json.Marshal(mockBlock)
err = os.WriteFile(filepath.Join(blocksDir, "4000.json"), blockJSON, 0644)
if err != nil {
t.Fatalf("Failed to write mock block file: %v", err)
}
mockRpc := NewMockRpc(tempDir)
block, err := mockRpc.GetBlock(4000)
if err != nil {
t.Fatalf("GetBlock failed: %v", err)
}
if block.Slot != 4000 {
t.Errorf("Expected block slot to be 4000, got %d", block.Slot)
}
}
func TestChainId(t *testing.T) {
mockRpc := NewMockRpc("/tmp/testdata")
_, err := mockRpc.ChainId()
if err == nil || err.Error() != "not implemented" {
t.Errorf("Expected 'not implemented' error, got %v", err)
}
}
128 changes: 128 additions & 0 deletions consensus/rpc/nimbus_rpc_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package rpc
import (
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"testing"
"github.com/BlocSoc-iitr/selene/consensus/consensus_core"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestNewNimbusRpc(t *testing.T) {
rpcURL := "http://example.com"
nimbusRpc := NewNimbusRpc(rpcURL)
assert.Equal(t, rpcURL, nimbusRpc.rpc)
}
func TestNimbusGetBootstrap(t *testing.T) {
blockRoot := [32]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32}
expectedPath := fmt.Sprintf("/eth/v1/beacon/light_client/bootstrap/0x%x", blockRoot)
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, expectedPath, r.URL.Path)
response := BootstrapResponse{
Data: consensus_core.Bootstrap{
Header: consensus_core.Header{
Slot: 1000,
},
},
}
err := json.NewEncoder(w).Encode(response)
require.NoError(t, err)
}))
defer server.Close()
nimbusRpc := NewNimbusRpc(server.URL)
bootstrap, err := nimbusRpc.GetBootstrap(blockRoot)
assert.NoError(t, err)
assert.Equal(t, uint64(1000), bootstrap.Header.Slot)
}
func TestNimbusGetUpdates(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, "/eth/v1/beacon/light_client/updates", r.URL.Path)
assert.Equal(t, "start_period=1000&count=5", r.URL.RawQuery)
response := UpdateResponse{
{Data: consensus_core.Update{AttestedHeader: consensus_core.Header{Slot: 1000}}},
{Data: consensus_core.Update{AttestedHeader: consensus_core.Header{Slot: 1001}}},
}
err := json.NewEncoder(w).Encode(response)
require.NoError(t, err)
}))
defer server.Close()
nimbusRpc := NewNimbusRpc(server.URL)
updates, err := nimbusRpc.GetUpdates(1000, 5)
assert.NoError(t, err)
assert.Len(t, updates, 2)
assert.Equal(t, uint64(1000), updates[0].AttestedHeader.Slot)
assert.Equal(t, uint64(1001), updates[1].AttestedHeader.Slot)
}
func TestNimbusGetFinalityUpdate(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, "/eth/v1/beacon/light_client/finality_update", r.URL.Path)
response := FinalityUpdateResponse{
Data: consensus_core.FinalityUpdate{
FinalizedHeader: consensus_core.Header{
Slot: 2000,
},
},
}
err := json.NewEncoder(w).Encode(response)
require.NoError(t, err)
}))
defer server.Close()
nimbusRpc := NewNimbusRpc(server.URL)
finalityUpdate, err := nimbusRpc.GetFinalityUpdate()
assert.NoError(t, err)
assert.Equal(t, uint64(2000), finalityUpdate.FinalizedHeader.Slot)
}
func TestNimbusGetOptimisticUpdate(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, "/eth/v1/beacon/light_client/optimistic_update", r.URL.Path)
response := OptimisticUpdateResponse{
Data: consensus_core.OptimisticUpdate{
SignatureSlot: 3000,
},
}
err := json.NewEncoder(w).Encode(response)
require.NoError(t, err)
}))
defer server.Close()
nimbusRpc := NewNimbusRpc(server.URL)
optimisticUpdate, err := nimbusRpc.GetOptimisticUpdate()
assert.NoError(t, err)
assert.Equal(t, uint64(3000), optimisticUpdate.SignatureSlot)
}
func TestNimbusGetBlock(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, "/eth/v2/beacon/blocks/4000", r.URL.Path)
response := BeaconBlockResponse{
Data: BeaconBlockData{
Message: consensus_core.BeaconBlock{
Slot: 4000,
},
},
}
err := json.NewEncoder(w).Encode(response)
require.NoError(t, err)
}))
defer server.Close()
nimbusRpc := NewNimbusRpc(server.URL)
block, err := nimbusRpc.GetBlock(4000)
assert.NoError(t, err)
assert.Equal(t, uint64(4000), block.Slot)
}
func TestNimbusChainId(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, "/eth/v1/config/spec", r.URL.Path)
response := SpecResponse{
Data: Spec{
ChainId: 5000,
},
}
err := json.NewEncoder(w).Encode(response)
require.NoError(t, err)
}))
defer server.Close()
nimbusRpc := NewNimbusRpc(server.URL)
chainId, err := nimbusRpc.ChainId()
assert.NoError(t, err)
assert.Equal(t, uint64(5000), chainId)
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ require (
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/stretchr/testify v1.9.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/supranational/blst v0.3.11 // indirect
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
Expand Down

0 comments on commit 987f84f

Please sign in to comment.