github.com/klaytn/klaytn@v1.10.2/node/sc/subbridge_test.go (about) 1 // Copyright 2019 The klaytn Authors 2 // This file is part of the klaytn library. 3 // 4 // The klaytn library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The klaytn library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the klaytn library. If not, see <http://www.gnu.org/licenses/>. 16 17 package sc 18 19 import ( 20 "fmt" 21 "io/ioutil" 22 "math/big" 23 "os" 24 "reflect" 25 "strings" 26 "testing" 27 28 "github.com/golang/mock/gomock" 29 "github.com/klaytn/klaytn/accounts" 30 "github.com/klaytn/klaytn/crypto" 31 "github.com/klaytn/klaytn/event" 32 "github.com/klaytn/klaytn/networks/p2p" 33 "github.com/klaytn/klaytn/networks/p2p/discover" 34 "github.com/klaytn/klaytn/node" 35 "github.com/stretchr/testify/assert" 36 ) 37 38 // testNewSubBridge returns a test SubBridge. 39 func testNewSubBridge(t *testing.T) *SubBridge { 40 tempDir, err := ioutil.TempDir(os.TempDir(), "klaytn-test-sb-") 41 if err != nil { 42 t.Fatal(err) 43 } 44 45 sCtx := node.NewServiceContext(&node.DefaultConfig, map[reflect.Type]node.Service{}, &event.TypeMux{}, &accounts.Manager{}) 46 sBridge, err := NewSubBridge(sCtx, &SCConfig{NetworkId: testNetVersion, DataDir: tempDir}) 47 if err != nil { 48 t.Fatal(err) 49 } 50 assert.NotNil(t, sBridge) 51 52 return sBridge 53 } 54 55 // removeData removes blockchain data generated during the SubBridge test. 56 func (sb *SubBridge) removeData(t *testing.T) { 57 if err := os.RemoveAll(sb.config.DataDir); err != nil { 58 t.Fatal(err) 59 } 60 } 61 62 // TestSubBridge_basic tests some getters and basic operation of SubBridge. 63 func TestSubBridge_basic(t *testing.T) { 64 // Create a test SubBridge 65 sBridge := testNewSubBridge(t) 66 defer sBridge.removeData(t) 67 68 // APIs returns default rpc APIs of MainBridge 69 apis := sBridge.APIs() 70 assert.Equal(t, 2, len(apis)) 71 assert.Equal(t, "subbridge", apis[0].Namespace) 72 assert.Equal(t, "subbridge", apis[1].Namespace) 73 74 // Test getters for elements of SubBridge 75 assert.Equal(t, true, sBridge.IsListening()) // Always returns `true` 76 assert.Equal(t, testProtocolVersion, sBridge.ProtocolVersion()) 77 assert.Equal(t, testNetVersion, sBridge.NetVersion()) 78 79 // New components of MainBridge which will update old components 80 bc := testBlockChain(t) 81 txPool := testTxPool(sBridge.config.DataDir, bc) 82 83 var comp []interface{} 84 comp = append(comp, bc) 85 comp = append(comp, txPool) 86 87 // Check initial status of components 88 assert.Nil(t, sBridge.blockchain) 89 assert.Nil(t, sBridge.txPool) 90 91 // Update and check MainBridge components 92 sBridge.SetComponents(comp) 93 assert.Equal(t, bc, sBridge.blockchain) 94 assert.Equal(t, txPool, sBridge.txPool) 95 96 // Start MainBridge and stop later 97 if err := sBridge.Start(p2p.SingleChannelServer{}); err != nil { 98 t.Fatal(err) 99 } 100 defer sBridge.Stop() 101 102 // TODO more test 103 } 104 105 // TestSubBridge_removePeer tests correct removal of a peer from `SubBridge.peers`. 106 func TestSubBridge_removePeer(t *testing.T) { 107 // Create a test SubBridge (it may have 0 peers) 108 sBridge := testNewSubBridge(t) 109 defer sBridge.removeData(t) 110 defer sBridge.chainDB.Close() 111 112 // Set components of SubBridge 113 bc := testBlockChain(t) 114 txPool := testTxPool(sBridge.config.DataDir, bc) 115 116 var comp []interface{} 117 comp = append(comp, bc) 118 comp = append(comp, txPool) 119 120 sBridge.SetComponents(comp) 121 122 // Prepare information of bridgePeer to be added and removed 123 nodeID := "0x1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d" 124 peer := p2p.NewPeer(discover.MustHexID(nodeID), "name", []p2p.Cap{}) 125 peerID := peer.ID() 126 bridgePeerID := fmt.Sprintf("%x", peerID[:8]) 127 128 // mockBridgePeer mocks BridgePeer 129 mockCtrl := gomock.NewController(t) 130 defer mockCtrl.Finish() 131 132 mockBridgePeer := NewMockBridgePeer(mockCtrl) 133 mockBridgePeer.EXPECT().GetID().Return(bridgePeerID).AnyTimes() 134 mockBridgePeer.EXPECT().GetChainID().Return(big.NewInt(0)).AnyTimes() 135 mockBridgePeer.EXPECT().GetP2PPeer().Return(peer).AnyTimes() 136 mockBridgePeer.EXPECT().SendServiceChainInfoRequest(gomock.Any()).Return(nil).AnyTimes() 137 mockBridgePeer.EXPECT().Close().Return().AnyTimes() 138 139 // Add the bridgePeer 140 if err := sBridge.peers.Register(mockBridgePeer); err != nil { 141 t.Fatal(err) 142 } 143 if err := sBridge.handler.RegisterNewPeer(mockBridgePeer); err != nil { 144 t.Fatal(err) 145 } 146 147 peerNum := sBridge.peers.Len() 148 149 // Try to remove a non-registered bridgePeer, and nothing happen 150 sBridge.removePeer("0x11111111") 151 assert.Equal(t, peerNum, sBridge.peers.Len()) 152 153 // Remove the registered bridgePeer 154 sBridge.removePeer(mockBridgePeer.GetID()) 155 assert.Equal(t, peerNum-1, sBridge.peers.Len()) 156 } 157 158 // TestSubBridge_handleMsg fails when a bridgePeer fails to read a message or reads a too long message. 159 func TestSubBridge_handleMsg(t *testing.T) { 160 // Create a test SubBridge 161 sBridge := testNewSubBridge(t) 162 defer sBridge.removeData(t) 163 defer sBridge.chainDB.Close() 164 165 // Elements for a bridgePeer 166 key, _ := crypto.GenerateKey() 167 nodeID := discover.PubkeyID(&key.PublicKey) 168 peer := p2p.NewPeer(nodeID, "name", []p2p.Cap{}) 169 pipe1, pipe2 := p2p.MsgPipe() 170 171 // bridgePeer will receive a message through rw1 172 bridgePeer := newBridgePeer(testProtocolVersion, peer, pipe1) 173 174 // Case1. Send a valid message and handle it successfully 175 { 176 data := "valid message" 177 go func() { 178 if err := p2p.Send(pipe2, StatusMsg, data); err != nil { 179 t.Error(err) 180 return 181 } 182 }() 183 184 if err := sBridge.handleMsg(bridgePeer); err != nil { 185 t.Fatal(err) 186 } 187 } 188 189 // Case2. Send an invalid message having large size and fail to handle 190 { 191 data := strings.Repeat("a", ProtocolMaxMsgSize+1) 192 go func() { 193 if err := p2p.Send(pipe2, StatusMsg, data); err != nil { 194 t.Error(err) 195 return 196 } 197 }() 198 199 err := sBridge.handleMsg(bridgePeer) 200 assert.True(t, strings.HasPrefix(err.Error(), "Message too long")) 201 } 202 203 // Case3. Return an error when it fails to read a message 204 { 205 _ = pipe2.Close() 206 207 err := sBridge.handleMsg(bridgePeer) 208 assert.Equal(t, p2p.ErrPipeClosed, err) 209 210 } 211 _ = pipe1.Close() 212 } 213 214 // TestSubBridge_handle tests the fail cases of `handle` function. 215 // There are no success cases in this test since `handle` has a infinite loop inside. 216 func TestSubBridge_handle(t *testing.T) { 217 // Create a test SubBridge 218 sBridge := testNewSubBridge(t) 219 defer sBridge.removeData(t) 220 defer sBridge.chainDB.Close() 221 222 // Set components of SubBridge 223 bc := testBlockChain(t) 224 txPool := testTxPool(sBridge.config.DataDir, bc) 225 226 var comp []interface{} 227 comp = append(comp, bc) 228 comp = append(comp, txPool) 229 230 sBridge.SetComponents(comp) 231 232 // Variables will be used as return values of mockBridgePeer 233 key, _ := crypto.GenerateKey() 234 nodeID := discover.PubkeyID(&key.PublicKey) 235 peer := p2p.NewPeer(nodeID, "name", []p2p.Cap{}) 236 peerID := peer.ID() 237 bridgePeerID := fmt.Sprintf("%x", peerID[:8]) 238 pipe, _ := p2p.MsgPipe() 239 240 // mockBridgePeer mocks BridgePeer 241 mockCtrl := gomock.NewController(t) 242 defer mockCtrl.Finish() 243 244 mockBridgePeer := NewMockBridgePeer(mockCtrl) 245 mockBridgePeer.EXPECT().GetID().Return(bridgePeerID).AnyTimes() 246 mockBridgePeer.EXPECT().GetChainID().Return(big.NewInt(0)).AnyTimes() 247 mockBridgePeer.EXPECT().GetP2PPeer().Return(peer).AnyTimes() 248 mockBridgePeer.EXPECT().GetP2PPeerID().Return(peerID).AnyTimes() 249 mockBridgePeer.EXPECT().GetRW().Return(pipe).AnyTimes() 250 mockBridgePeer.EXPECT().SendServiceChainInfoRequest(gomock.Any()).Return(nil).AnyTimes() 251 mockBridgePeer.EXPECT().Close().Return().AnyTimes() 252 253 // Case 1 - Error if `sBridge.peers.Len()` was equal or bigger than `sBridge.maxPeers` 254 { 255 // Set maxPeers to make the test fail 256 sBridge.maxPeers = sBridge.peers.Len() 257 258 err := sBridge.handle(mockBridgePeer) 259 assert.Equal(t, p2p.DiscTooManyPeers, err) 260 } 261 // Resolve the above failure condition by increasing maxPeers 262 sBridge.maxPeers += 5 263 264 // Case 2 - Error if handshake of BridgePeer failed 265 { 266 // Make handshake fail 267 mockBridgePeer.EXPECT().Handshake(sBridge.networkId, sBridge.getChainID(), gomock.Any(), sBridge.blockchain.CurrentHeader().Hash()).Return(p2p.ErrPipeClosed).Times(1) 268 269 err := sBridge.handle(mockBridgePeer) 270 assert.Equal(t, p2p.ErrPipeClosed, err) 271 } 272 // Resolve the above failure condition by making handshake success 273 mockBridgePeer.EXPECT().Handshake(sBridge.networkId, sBridge.getChainID(), gomock.Any(), sBridge.blockchain.CurrentHeader().Hash()).Return(nil).AnyTimes() 274 275 // Case 3 - Error when the same peer was registered before 276 { 277 // Pre-register a peer which will be added again 278 sBridge.peers.peers[bridgePeerID] = &baseBridgePeer{} 279 280 err := sBridge.handle(mockBridgePeer) 281 assert.Equal(t, errAlreadyRegistered, err) 282 } 283 // Resolve the above failure condition by deleting the registered peer 284 delete(sBridge.peers.peers, bridgePeerID) 285 286 // Case 4 - Error if `sBridge.handleMsg` failed 287 { 288 // Close of the peer's pipe make `sBridge.handleMsg` fail 289 _ = pipe.Close() 290 291 err := sBridge.handle(mockBridgePeer) 292 assert.Equal(t, p2p.ErrPipeClosed, err) 293 } 294 } 295 296 // TestSubBridge_SendRPCData tests SendRPCResponseData function of SubBridge. 297 // The function sends RPC response data to SubBridge's peers. 298 func TestSubBridge_SendRPCData(t *testing.T) { 299 // Create a test SubBridge 300 sBridge := testNewSubBridge(t) 301 defer sBridge.removeData(t) 302 defer sBridge.chainDB.Close() 303 304 // Test data used as a parameter of SendResponseRPC function 305 data := []byte{0x11, 0x22, 0x33} 306 307 // mockBridgePeer mocks BridgePeer 308 mockCtrl := gomock.NewController(t) 309 defer mockCtrl.Finish() 310 311 mockBridgePeer := NewMockBridgePeer(mockCtrl) 312 mockBridgePeer.EXPECT().GetID().Return("testID").AnyTimes() // for `sBridge.BridgePeerSet().Register(mockBridgePeer)` 313 314 // Register mockBridgePeer as a peer of `sBridge.BridgePeerSet` 315 if err := sBridge.BridgePeerSet().Register(mockBridgePeer); err != nil { 316 t.Fatal(err) 317 } 318 319 // Case 1 - Error if SendResponseRPC of mockBridgePeer failed 320 { 321 // Make mockBridgePeer return an error 322 mockBridgePeer.EXPECT().SendRequestRPC(data).Return(p2p.ErrPipeClosed).Times(1) 323 324 err := sBridge.SendRPCData(data) 325 assert.Equal(t, p2p.ErrPipeClosed, err) 326 } 327 328 // Case 2 - Success if SendResponseRPC of mockBridgePeer succeeded 329 { 330 // Make mockBridgePeer return nil 331 mockBridgePeer.EXPECT().SendRequestRPC(data).Return(nil).Times(1) 332 333 err := sBridge.SendRPCData(data) 334 assert.Equal(t, nil, err) 335 } 336 }