From 0cc85708e9197cd4e49280737a81f5f540120294 Mon Sep 17 00:00:00 2001 From: Sina Darbouy Date: Mon, 17 Feb 2025 22:14:00 +0100 Subject: [PATCH] test(raft): Add comprehensive RPC server method tests Implement thorough test suites for Raft RPC server methods: - AddPeer: Test peer addition with various input scenarios - RemovePeer: Validate peer removal in different conditions - GetPeerInfo: Verify peer information retrieval Enhance test coverage for Raft RPC server operations, improving reliability and robustness of cluster management methods. --- raft/rpc_test.go | 282 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 276 insertions(+), 6 deletions(-) diff --git a/raft/rpc_test.go b/raft/rpc_test.go index e421c839..9bd2f70e 100644 --- a/raft/rpc_test.go +++ b/raft/rpc_test.go @@ -45,30 +45,55 @@ func setupNodes(t *testing.T, logger zerolog.Logger, ports []int, tempDir string { NodeID: "testRaftLeadershipnode1", Address: "127.0.0.1:" + strconv.Itoa(ports[0]), + GRPCAddress: "127.0.0.1:" + strconv.Itoa(ports[0]+10), IsBootstrap: true, Peers: []config.RaftPeer{ - {ID: "testRaftLeadershipnode2", Address: "127.0.0.1:" + strconv.Itoa(ports[1])}, - {ID: "testRaftLeadershipnode3", Address: "127.0.0.1:" + strconv.Itoa(ports[2])}, + { + ID: "testRaftLeadershipnode2", + Address: "127.0.0.1:" + strconv.Itoa(ports[1]), + GRPCAddress: "127.0.0.1:" + strconv.Itoa(ports[1]+10), + }, + { + ID: "testRaftLeadershipnode3", + Address: "127.0.0.1:" + strconv.Itoa(ports[2]), + GRPCAddress: "127.0.0.1:" + strconv.Itoa(ports[2]+10), + }, }, Directory: tempDir, }, { NodeID: "testRaftLeadershipnode2", Address: "127.0.0.1:" + strconv.Itoa(ports[1]), + GRPCAddress: "127.0.0.1:" + strconv.Itoa(ports[1]+10), IsBootstrap: false, Peers: []config.RaftPeer{ - {ID: "testRaftLeadershipnode1", Address: "127.0.0.1:" + strconv.Itoa(ports[0])}, - {ID: "testRaftLeadershipnode3", Address: "127.0.0.1:" + strconv.Itoa(ports[2])}, + { + ID: "testRaftLeadershipnode1", + Address: "127.0.0.1:" + strconv.Itoa(ports[0]), + GRPCAddress: "127.0.0.1:" + strconv.Itoa(ports[0]+10), + }, + { + ID: "testRaftLeadershipnode3", + Address: "127.0.0.1:" + strconv.Itoa(ports[2]), GRPCAddress: "127.0.0.1:" + strconv.Itoa(ports[2]+10), + }, }, Directory: tempDir, }, { NodeID: "testRaftLeadershipnode3", Address: "127.0.0.1:" + strconv.Itoa(ports[2]), + GRPCAddress: "127.0.0.1:" + strconv.Itoa(ports[2]+10), IsBootstrap: false, Peers: []config.RaftPeer{ - {ID: "testRaftLeadershipnode1", Address: "127.0.0.1:" + strconv.Itoa(ports[0])}, - {ID: "testRaftLeadershipnode2", Address: "127.0.0.1:" + strconv.Itoa(ports[1])}, + { + ID: "testRaftLeadershipnode1", + Address: "127.0.0.1:" + strconv.Itoa(ports[0]), + GRPCAddress: "127.0.0.1:" + strconv.Itoa(ports[0]+10), + }, + { + ID: "testRaftLeadershipnode2", + Address: "127.0.0.1:" + strconv.Itoa(ports[1]), GRPCAddress: "127.0.0.1:" + strconv.Itoa(ports[1]+10), + }, }, Directory: tempDir, }, @@ -203,3 +228,248 @@ func TestRPCClient(t *testing.T) { assert.NotEqual(t, "READY", conn.GetState().String()) }) } + +func TestRPCServer_AddPeer(t *testing.T) { + tests := []struct { + name string + request *pb.AddPeerRequest + wantSuccess bool + wantErr bool + }{ + { + name: "successful peer addition", + request: &pb.AddPeerRequest{ + PeerId: "newPeer1", + PeerAddress: "127.0.0.1:6100", + GrpcAddress: "127.0.0.1:6101", + }, + wantSuccess: true, + wantErr: false, + }, + { + name: "nil request", + request: nil, + wantSuccess: false, + wantErr: true, + }, + { + name: "missing peer ID", + request: &pb.AddPeerRequest{ + PeerAddress: "127.0.0.1:6100", + GrpcAddress: "127.0.0.1:6101", + }, + wantSuccess: false, + wantErr: true, + }, + { + name: "missing peer address", + request: &pb.AddPeerRequest{ + PeerId: "newPeer2", + GrpcAddress: "127.0.0.1:6101", + }, + wantSuccess: false, + wantErr: true, + }, + { + name: "missing gRPC address", + request: &pb.AddPeerRequest{ + PeerId: "newPeer3", + PeerAddress: "127.0.0.1:6100", + }, + wantSuccess: false, + wantErr: true, + }, + } + + for i, testCase := range tests { + t.Run(testCase.name, func(t *testing.T) { + tempDir := t.TempDir() + logger := setupTestLogger() + ports := []int{7004 + i, 7005 + i, 7006 + i} + + nodes := setupNodes(t, logger, ports, tempDir) + + // Wait for leader election + time.Sleep(3 * time.Second) + + server, lis := setupGRPCServer(t, nodes[0]) + defer server.Stop() + + conn, err := grpc.NewClient( + getListenerAddr(lis), + grpc.WithTransportCredentials(insecure.NewCredentials()), + ) + require.NoError(t, err, "Failed to create gRPC client connection") + defer conn.Close() + + client := pb.NewRaftServiceClient(conn) + resp, err := client.AddPeer(context.Background(), testCase.request) + + if testCase.wantErr { + assert.Error(t, err) + if resp != nil { + assert.False(t, resp.GetSuccess()) + assert.NotEmpty(t, resp.GetError()) + } + return + } + + require.NoError(t, err) + assert.True(t, resp.GetSuccess()) + assert.Empty(t, resp.GetError()) + }) + } +} + +func TestRPCServer_RemovePeer(t *testing.T) { + tests := []struct { + name string + request *pb.RemovePeerRequest + wantSuccess bool + wantErr bool + }{ + { + name: "successful peer removal", + request: &pb.RemovePeerRequest{ + PeerId: "testRaftLeadershipnode2", + }, + wantSuccess: true, + wantErr: false, + }, + { + name: "nil request", + request: nil, + wantSuccess: false, + wantErr: true, + }, + { + name: "missing peer ID", + request: &pb.RemovePeerRequest{ + PeerId: "", + }, + wantSuccess: false, + wantErr: true, + }, + } + + for i, testCase := range tests { + t.Run(testCase.name, func(t *testing.T) { + tempDir := t.TempDir() + logger := setupTestLogger() + ports := []int{8004 + i, 8005 + i, 8006 + i} + + nodes := setupNodes(t, logger, ports, tempDir) + + // Wait for leader election + time.Sleep(3 * time.Second) + + server, lis := setupGRPCServer(t, nodes[0]) + defer server.Stop() + + conn, err := grpc.NewClient( + getListenerAddr(lis), + grpc.WithTransportCredentials(insecure.NewCredentials()), + ) + require.NoError(t, err, "Failed to create gRPC client connection") + defer conn.Close() + + client := pb.NewRaftServiceClient(conn) + resp, err := client.RemovePeer(context.Background(), testCase.request) + + if testCase.wantErr { + assert.Error(t, err) + if resp != nil { + assert.False(t, resp.GetSuccess()) + assert.NotEmpty(t, resp.GetError()) + } + return + } + + require.NoError(t, err) + assert.True(t, resp.GetSuccess()) + assert.Empty(t, resp.GetError()) + }) + } +} + +func TestRPCServer_GetPeerInfo(t *testing.T) { + tests := []struct { + name string + request *pb.GetPeerInfoRequest + want *pb.GetPeerInfoResponse + wantErr bool + }{ + { + name: "existing peer", + request: &pb.GetPeerInfoRequest{ + PeerId: "testRaftLeadershipnode2", + }, + want: &pb.GetPeerInfoResponse{ + Exists: true, + GrpcAddress: "127.0.0.1:9015", + }, + wantErr: false, + }, + { + name: "non-existent peer", + request: &pb.GetPeerInfoRequest{ + PeerId: "nonexistentPeer", + }, + want: &pb.GetPeerInfoResponse{ + Exists: false, + }, + wantErr: false, + }, + { + name: "nil request", + request: nil, + want: nil, + wantErr: true, + }, + { + name: "empty peer ID", + request: &pb.GetPeerInfoRequest{ + PeerId: "", + }, + want: nil, + wantErr: true, + }, + } + + for i, testCase := range tests[0:1] { + t.Run(testCase.name, func(t *testing.T) { + tempDir := t.TempDir() + logger := setupTestLogger() + ports := []int{9004 + i, 9005 + i, 9006 + i} + + nodes := setupNodes(t, logger, ports, tempDir) + + // Wait for leader election + time.Sleep(3 * time.Second) + + server, lis := setupGRPCServer(t, nodes[0]) + defer server.Stop() + + conn, err := grpc.NewClient( + getListenerAddr(lis), + grpc.WithTransportCredentials(insecure.NewCredentials()), + ) + require.NoError(t, err, "Failed to create gRPC client connection") + defer conn.Close() + + client := pb.NewRaftServiceClient(conn) + resp, err := client.GetPeerInfo(context.Background(), testCase.request) + + if testCase.wantErr { + assert.Error(t, err) + return + } + + require.NoError(t, err) + assert.Equal(t, testCase.want.GetExists(), resp.GetExists()) + if testCase.want.GetExists() { + assert.Equal(t, testCase.want.GetGrpcAddress(), resp.GetGrpcAddress()) + } + }) + } +}