From ece86b28c3490bd7016ff33cd961b570e2154ce4 Mon Sep 17 00:00:00 2001 From: VeerChaurasia Date: Sun, 22 Sep 2024 16:11:26 +0530 Subject: [PATCH 1/2] Implemented Testing for Nimbus_rpc and mock_rpc --- consensus/rpc/mock_rpc_test.go | 163 +++++++++++++++++++++++++++++++ consensus/rpc/nimbus_rpc_test.go | 128 ++++++++++++++++++++++++ 2 files changed, 291 insertions(+) create mode 100644 consensus/rpc/mock_rpc_test.go create mode 100644 consensus/rpc/nimbus_rpc_test.go diff --git a/consensus/rpc/mock_rpc_test.go b/consensus/rpc/mock_rpc_test.go new file mode 100644 index 0000000..b371a54 --- /dev/null +++ b/consensus/rpc/mock_rpc_test.go @@ -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) + } +} diff --git a/consensus/rpc/nimbus_rpc_test.go b/consensus/rpc/nimbus_rpc_test.go new file mode 100644 index 0000000..3e00074 --- /dev/null +++ b/consensus/rpc/nimbus_rpc_test.go @@ -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) +} \ No newline at end of file From e12e28e0f2ffd13ca04e2757f1a81d48c674a4a9 Mon Sep 17 00:00:00 2001 From: VeerChaurasia Date: Sun, 22 Sep 2024 16:15:19 +0530 Subject: [PATCH 2/2] Implemented Tests for consensus_rpc --- consensus/rpc/consensus_rpc_test.go | 84 +++++++++++++++++++++++++++++ go.mod | 1 + go.sum | 1 + 3 files changed, 86 insertions(+) create mode 100644 consensus/rpc/consensus_rpc_test.go diff --git a/consensus/rpc/consensus_rpc_test.go b/consensus/rpc/consensus_rpc_test.go new file mode 100644 index 0000000..14a3617 --- /dev/null +++ b/consensus/rpc/consensus_rpc_test.go @@ -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) +} \ No newline at end of file diff --git a/go.mod b/go.mod index d3224ef..ce01ecf 100644 --- a/go.mod +++ b/go.mod @@ -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 diff --git a/go.sum b/go.sum index 602c81c..1de4e33 100644 --- a/go.sum +++ b/go.sum @@ -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=