github.com/ethersphere/bee/v2@v2.2.0/pkg/api/peer_test.go (about) 1 // Copyright 2020 The Swarm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package api_test 6 7 import ( 8 "context" 9 "errors" 10 "net/http" 11 "testing" 12 13 "github.com/ethereum/go-ethereum/common" 14 "github.com/ethersphere/bee/v2/pkg/api" 15 "github.com/ethersphere/bee/v2/pkg/bzz" 16 "github.com/ethersphere/bee/v2/pkg/crypto" 17 "github.com/ethersphere/bee/v2/pkg/jsonhttp" 18 "github.com/ethersphere/bee/v2/pkg/jsonhttp/jsonhttptest" 19 "github.com/ethersphere/bee/v2/pkg/p2p" 20 "github.com/ethersphere/bee/v2/pkg/p2p/mock" 21 "github.com/ethersphere/bee/v2/pkg/swarm" 22 ma "github.com/multiformats/go-multiaddr" 23 ) 24 25 func TestConnect(t *testing.T) { 26 t.Parallel() 27 28 underlay := "/ip4/127.0.0.1/tcp/1634/p2p/16Uiu2HAkx8ULY8cTXhdVAcMmLcH9AsTKz6uBQ7DPLKRjMLgBVYkS" 29 errorUnderlay := "/ip4/127.0.0.1/tcp/1634/p2p/16Uiu2HAkw88cjH2orYrB6fDui4eUNdmgkwnDM8W681UbfsPgM9QY" 30 testErr := errors.New("test error") 31 32 privateKey, err := crypto.GenerateSecp256k1Key() 33 if err != nil { 34 t.Fatal(err) 35 } 36 37 block := common.HexToHash("0x1").Bytes() 38 39 overlay, err := crypto.NewOverlayAddress(privateKey.PublicKey, 0, block) 40 if err != nil { 41 t.Fatal(err) 42 } 43 underlama, err := ma.NewMultiaddr(underlay) 44 if err != nil { 45 t.Fatal(err) 46 } 47 48 bzzAddress, err := bzz.NewAddress(crypto.NewDefaultSigner(privateKey), underlama, overlay, 0, nil) 49 if err != nil { 50 t.Fatal(err) 51 } 52 53 testServer, _, _, _ := newTestServer(t, testServerOptions{ 54 P2P: mock.New(mock.WithConnectFunc(func(ctx context.Context, addr ma.Multiaddr) (*bzz.Address, error) { 55 if addr.String() == errorUnderlay { 56 return nil, testErr 57 } 58 return bzzAddress, nil 59 })), 60 }) 61 62 t.Run("ok", func(t *testing.T) { 63 t.Parallel() 64 jsonhttptest.Request(t, testServer, http.MethodPost, "/connect"+underlay, http.StatusOK, 65 jsonhttptest.WithExpectedJSONResponse(api.PeerConnectResponse{ 66 Address: overlay.String(), 67 }), 68 ) 69 }) 70 71 t.Run("error", func(t *testing.T) { 72 t.Parallel() 73 jsonhttptest.Request(t, testServer, http.MethodPost, "/connect"+errorUnderlay, http.StatusInternalServerError, 74 jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{ 75 Code: http.StatusInternalServerError, 76 Message: testErr.Error(), 77 }), 78 ) 79 }) 80 81 t.Run("error - add peer", func(t *testing.T) { 82 t.Parallel() 83 testServer, _, _, _ := newTestServer(t, testServerOptions{ 84 P2P: mock.New(mock.WithConnectFunc(func(ctx context.Context, addr ma.Multiaddr) (*bzz.Address, error) { 85 if addr.String() == errorUnderlay { 86 return nil, testErr 87 } 88 return bzzAddress, nil 89 })), 90 }) 91 92 jsonhttptest.Request(t, testServer, http.MethodPost, "/connect"+errorUnderlay, http.StatusInternalServerError, 93 jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{ 94 Code: http.StatusInternalServerError, 95 Message: testErr.Error(), 96 }), 97 ) 98 }) 99 } 100 101 func TestDisconnect(t *testing.T) { 102 t.Parallel() 103 104 address := swarm.MustParseHexAddress("ca1e9f3938cc1425c6061b96ad9eb93e134dfe8734ad490164ef20af9d1cf59c") 105 unknownAddress := swarm.MustParseHexAddress("ca1e9f3938cc1425c6061b96ad9eb93e134dfe8734ad490164ef20af9d1cf59e") 106 errorAddress := swarm.MustParseHexAddress("ca1e9f3938cc1425c6061b96ad9eb93e134dfe8734ad490164ef20af9d1cf59a") 107 testErr := errors.New("test error") 108 109 testServer, _, _, _ := newTestServer(t, testServerOptions{ 110 P2P: mock.New(mock.WithDisconnectFunc(func(addr swarm.Address, reason string) error { 111 if reason != "user requested disconnect" { 112 return testErr 113 } 114 115 if addr.Equal(address) { 116 return nil 117 } 118 119 if addr.Equal(errorAddress) { 120 return testErr 121 } 122 123 return p2p.ErrPeerNotFound 124 })), 125 }) 126 127 t.Run("ok", func(t *testing.T) { 128 t.Parallel() 129 130 jsonhttptest.Request(t, testServer, http.MethodDelete, "/peers/"+address.String(), http.StatusOK, 131 jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{ 132 Code: http.StatusOK, 133 Message: http.StatusText(http.StatusOK), 134 }), 135 ) 136 }) 137 138 t.Run("unknown", func(t *testing.T) { 139 t.Parallel() 140 141 jsonhttptest.Request(t, testServer, http.MethodDelete, "/peers/"+unknownAddress.String(), http.StatusNotFound, 142 jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{ 143 Code: http.StatusNotFound, 144 Message: "peer not found", 145 }), 146 ) 147 }) 148 149 t.Run("error", func(t *testing.T) { 150 t.Parallel() 151 152 jsonhttptest.Request(t, testServer, http.MethodDelete, "/peers/"+errorAddress.String(), http.StatusInternalServerError, 153 jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{ 154 Code: http.StatusInternalServerError, 155 Message: testErr.Error(), 156 }), 157 ) 158 }) 159 } 160 161 func TestPeer(t *testing.T) { 162 t.Parallel() 163 164 overlay := swarm.MustParseHexAddress("ca1e9f3938cc1425c6061b96ad9eb93e134dfe8734ad490164ef20af9d1cf59c") 165 testServer, _, _, _ := newTestServer(t, testServerOptions{ 166 P2P: mock.New(mock.WithPeersFunc(func() []p2p.Peer { 167 return []p2p.Peer{{Address: overlay}} 168 })), 169 }) 170 171 t.Run("ok", func(t *testing.T) { 172 t.Parallel() 173 174 jsonhttptest.Request(t, testServer, http.MethodGet, "/peers", http.StatusOK, 175 jsonhttptest.WithExpectedJSONResponse(api.PeersResponse{ 176 Peers: []api.Peer{{Address: overlay}}, 177 }), 178 ) 179 }) 180 } 181 182 func TestBlocklistedPeers(t *testing.T) { 183 t.Parallel() 184 185 overlay := swarm.MustParseHexAddress("ca1e9f3938cc1425c6061b96ad9eb93e134dfe8734ad490164ef20af9d1cf59c") 186 testServer, _, _, _ := newTestServer(t, testServerOptions{ 187 P2P: mock.New(mock.WithBlocklistedPeersFunc(func() ([]p2p.BlockListedPeer, error) { 188 return []p2p.BlockListedPeer{{Peer: p2p.Peer{Address: overlay}}}, nil 189 })), 190 }) 191 192 jsonhttptest.Request(t, testServer, http.MethodGet, "/blocklist", http.StatusOK, 193 jsonhttptest.WithExpectedJSONResponse(api.BlockedListedPeersResponse{ 194 Peers: []api.BlockListedPeer{{Peer: api.Peer{Address: overlay}, Duration: 0}}, 195 }), 196 ) 197 } 198 199 func TestBlocklistedPeersErr(t *testing.T) { 200 t.Parallel() 201 202 overlay := swarm.MustParseHexAddress("ca1e9f3938cc1425c6061b96ad9eb93e134dfe8734ad490164ef20af9d1cf59c") 203 testServer, _, _, _ := newTestServer(t, testServerOptions{ 204 P2P: mock.New(mock.WithBlocklistedPeersFunc(func() ([]p2p.BlockListedPeer, error) { 205 return []p2p.BlockListedPeer{{Peer: p2p.Peer{Address: overlay}}}, errors.New("some error") 206 })), 207 }) 208 209 jsonhttptest.Request(t, testServer, http.MethodGet, "/blocklist", http.StatusInternalServerError, 210 jsonhttptest.WithExpectedJSONResponse( 211 jsonhttp.StatusResponse{ 212 Code: http.StatusInternalServerError, 213 Message: "get blocklisted peers failed", 214 }), 215 ) 216 } 217 218 func Test_peerConnectHandler_invalidInputs(t *testing.T) { 219 t.Parallel() 220 221 client, _, _, _ := newTestServer(t, testServerOptions{}) 222 223 tests := []struct { 224 name string 225 multiAddress string 226 want jsonhttp.StatusResponse 227 }{{ 228 name: "multi-address - invalid value", 229 multiAddress: "ca1e9f3938cc1425c6061b96ad9eb93e134dfe8734ad490164ef20af9d1cf59a", 230 want: jsonhttp.StatusResponse{ 231 Code: http.StatusBadRequest, 232 Message: "invalid path params", 233 Reasons: []jsonhttp.Reason{ 234 { 235 Field: "multi-address", 236 Error: "failed to parse multiaddr \"/ca1e9f3938cc1425c6061b96ad9eb93e134dfe8734ad490164ef20af9d1cf59a\": unknown protocol ca1e9f3938cc1425c6061b96ad9eb93e134dfe8734ad490164ef20af9d1cf59a", 237 }, 238 }, 239 }, 240 }} 241 242 for _, tc := range tests { 243 tc := tc 244 t.Run(tc.name, func(t *testing.T) { 245 t.Parallel() 246 247 jsonhttptest.Request(t, client, http.MethodPost, "/connect/"+tc.multiAddress, tc.want.Code, 248 jsonhttptest.WithExpectedJSONResponse(tc.want), 249 ) 250 }) 251 } 252 } 253 254 func Test_peerDisconnectHandler_invalidInputs(t *testing.T) { 255 t.Parallel() 256 257 client, _, _, _ := newTestServer(t, testServerOptions{}) 258 259 tests := []struct { 260 name string 261 address string 262 want jsonhttp.StatusResponse 263 }{{ 264 name: "address - odd hex string", 265 address: "123", 266 want: jsonhttp.StatusResponse{ 267 Code: http.StatusBadRequest, 268 Message: "invalid path params", 269 Reasons: []jsonhttp.Reason{ 270 { 271 Field: "address", 272 Error: api.ErrHexLength.Error(), 273 }, 274 }, 275 }, 276 }, { 277 name: "address - invalid hex character", 278 address: "123G", 279 want: jsonhttp.StatusResponse{ 280 Code: http.StatusBadRequest, 281 Message: "invalid path params", 282 Reasons: []jsonhttp.Reason{ 283 { 284 Field: "address", 285 Error: api.HexInvalidByteError('G').Error(), 286 }, 287 }, 288 }, 289 }} 290 291 for _, tc := range tests { 292 tc := tc 293 t.Run(tc.name, func(t *testing.T) { 294 t.Parallel() 295 296 jsonhttptest.Request(t, client, http.MethodDelete, "/peers/"+tc.address, tc.want.Code, 297 jsonhttptest.WithExpectedJSONResponse(tc.want), 298 ) 299 }) 300 } 301 }