github.com/nitinawathare/ethereumassignment3@v0.0.0-20211021213010-f07344c2b868/go-ethereum/cmd/swarm/global-store/explorer_test.go (about) 1 // Copyright 2019 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU 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 // go-ethereum 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 General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 17 package main 18 19 import ( 20 "encoding/json" 21 "fmt" 22 "net/http" 23 "sort" 24 "testing" 25 26 "github.com/ethereum/go-ethereum/common" 27 "github.com/ethereum/go-ethereum/swarm/storage/mock/explorer" 28 mockRPC "github.com/ethereum/go-ethereum/swarm/storage/mock/rpc" 29 ) 30 31 // TestExplorer validates basic chunk explorer functionality by storing 32 // a small set of chunk and making http requests on exposed endpoint. 33 // Full chunk explorer validation is done in mock/explorer package. 34 func TestExplorer(t *testing.T) { 35 addr := findFreeTCPAddress(t) 36 explorerAddr := findFreeTCPAddress(t) 37 testCmd := runGlobalStore(t, "ws", "--addr", addr, "--explorer-address", explorerAddr) 38 defer testCmd.Kill() 39 40 client := websocketClient(t, addr) 41 42 store := mockRPC.NewGlobalStore(client) 43 defer store.Close() 44 45 nodeKeys := map[string][]string{ 46 "a1": {"b1", "b2", "b3"}, 47 "a2": {"b3", "b4", "b5"}, 48 } 49 50 keyNodes := make(map[string][]string) 51 52 for addr, keys := range nodeKeys { 53 for _, key := range keys { 54 keyNodes[key] = append(keyNodes[key], addr) 55 } 56 } 57 58 invalidAddr := "c1" 59 invalidKey := "d1" 60 61 for addr, keys := range nodeKeys { 62 for _, key := range keys { 63 err := store.Put(common.HexToAddress(addr), common.Hex2Bytes(key), []byte("data")) 64 if err != nil { 65 t.Fatal(err) 66 } 67 } 68 } 69 70 endpoint := "http://" + explorerAddr 71 72 t.Run("has key", func(t *testing.T) { 73 for addr, keys := range nodeKeys { 74 for _, key := range keys { 75 testStatusResponse(t, endpoint+"/api/has-key/"+addr+"/"+key, http.StatusOK) 76 testStatusResponse(t, endpoint+"/api/has-key/"+invalidAddr+"/"+key, http.StatusNotFound) 77 } 78 testStatusResponse(t, endpoint+"/api/has-key/"+addr+"/"+invalidKey, http.StatusNotFound) 79 } 80 testStatusResponse(t, endpoint+"/api/has-key/"+invalidAddr+"/"+invalidKey, http.StatusNotFound) 81 }) 82 83 t.Run("keys", func(t *testing.T) { 84 var keys []string 85 for key := range keyNodes { 86 keys = append(keys, key) 87 } 88 sort.Strings(keys) 89 testKeysResponse(t, endpoint+"/api/keys", explorer.KeysResponse{ 90 Keys: keys, 91 }) 92 }) 93 94 t.Run("nodes", func(t *testing.T) { 95 var nodes []string 96 for addr := range nodeKeys { 97 nodes = append(nodes, common.HexToAddress(addr).Hex()) 98 } 99 sort.Strings(nodes) 100 testNodesResponse(t, endpoint+"/api/nodes", explorer.NodesResponse{ 101 Nodes: nodes, 102 }) 103 }) 104 105 t.Run("node keys", func(t *testing.T) { 106 for addr, keys := range nodeKeys { 107 testKeysResponse(t, endpoint+"/api/keys?node="+addr, explorer.KeysResponse{ 108 Keys: keys, 109 }) 110 } 111 testKeysResponse(t, endpoint+"/api/keys?node="+invalidAddr, explorer.KeysResponse{}) 112 }) 113 114 t.Run("key nodes", func(t *testing.T) { 115 for key, addrs := range keyNodes { 116 var nodes []string 117 for _, addr := range addrs { 118 nodes = append(nodes, common.HexToAddress(addr).Hex()) 119 } 120 sort.Strings(nodes) 121 testNodesResponse(t, endpoint+"/api/nodes?key="+key, explorer.NodesResponse{ 122 Nodes: nodes, 123 }) 124 } 125 testNodesResponse(t, endpoint+"/api/nodes?key="+invalidKey, explorer.NodesResponse{}) 126 }) 127 } 128 129 // TestExplorer_CORSOrigin validates if chunk explorer returns 130 // correct CORS origin header in GET and OPTIONS requests. 131 func TestExplorer_CORSOrigin(t *testing.T) { 132 origin := "http://localhost/" 133 addr := findFreeTCPAddress(t) 134 explorerAddr := findFreeTCPAddress(t) 135 testCmd := runGlobalStore(t, "ws", 136 "--addr", addr, 137 "--explorer-address", explorerAddr, 138 "--explorer-cors-origin", origin, 139 ) 140 defer testCmd.Kill() 141 142 // wait until the server is started 143 waitHTTPEndpoint(t, explorerAddr) 144 145 url := "http://" + explorerAddr + "/api/keys" 146 147 t.Run("get", func(t *testing.T) { 148 req, err := http.NewRequest(http.MethodGet, url, nil) 149 if err != nil { 150 t.Fatal(err) 151 } 152 req.Header.Set("Origin", origin) 153 154 resp, err := http.DefaultClient.Do(req) 155 if err != nil { 156 t.Fatal(err) 157 } 158 header := resp.Header.Get("Access-Control-Allow-Origin") 159 if header != origin { 160 t.Errorf("got Access-Control-Allow-Origin header %q, want %q", header, origin) 161 } 162 }) 163 164 t.Run("preflight", func(t *testing.T) { 165 req, err := http.NewRequest(http.MethodOptions, url, nil) 166 if err != nil { 167 t.Fatal(err) 168 } 169 req.Header.Set("Origin", origin) 170 req.Header.Set("Access-Control-Request-Method", "GET") 171 172 resp, err := http.DefaultClient.Do(req) 173 if err != nil { 174 t.Fatal(err) 175 } 176 header := resp.Header.Get("Access-Control-Allow-Origin") 177 if header != origin { 178 t.Errorf("got Access-Control-Allow-Origin header %q, want %q", header, origin) 179 } 180 }) 181 } 182 183 // testStatusResponse makes an http request to provided url 184 // and validates if response is explorer.StatusResponse for 185 // the expected status code. 186 func testStatusResponse(t *testing.T, url string, code int) { 187 t.Helper() 188 189 resp, err := http.Get(url) 190 if err != nil { 191 t.Fatal(err) 192 } 193 if resp.StatusCode != code { 194 t.Errorf("got status code %v, want %v", resp.StatusCode, code) 195 } 196 var r explorer.StatusResponse 197 if err := json.NewDecoder(resp.Body).Decode(&r); err != nil { 198 t.Fatal(err) 199 } 200 if r.Code != code { 201 t.Errorf("got response code %v, want %v", r.Code, code) 202 } 203 if r.Message != http.StatusText(code) { 204 t.Errorf("got response message %q, want %q", r.Message, http.StatusText(code)) 205 } 206 } 207 208 // testKeysResponse makes an http request to provided url 209 // and validates if response machhes expected explorer.KeysResponse. 210 func testKeysResponse(t *testing.T, url string, want explorer.KeysResponse) { 211 t.Helper() 212 213 resp, err := http.Get(url) 214 if err != nil { 215 t.Fatal(err) 216 } 217 if resp.StatusCode != http.StatusOK { 218 t.Errorf("got status code %v, want %v", resp.StatusCode, http.StatusOK) 219 } 220 var r explorer.KeysResponse 221 if err := json.NewDecoder(resp.Body).Decode(&r); err != nil { 222 t.Fatal(err) 223 } 224 if fmt.Sprint(r.Keys) != fmt.Sprint(want.Keys) { 225 t.Errorf("got keys %v, want %v", r.Keys, want.Keys) 226 } 227 if r.Next != want.Next { 228 t.Errorf("got next %s, want %s", r.Next, want.Next) 229 } 230 } 231 232 // testNodeResponse makes an http request to provided url 233 // and validates if response machhes expected explorer.NodeResponse. 234 func testNodesResponse(t *testing.T, url string, want explorer.NodesResponse) { 235 t.Helper() 236 237 resp, err := http.Get(url) 238 if err != nil { 239 t.Fatal(err) 240 } 241 if resp.StatusCode != http.StatusOK { 242 t.Errorf("got status code %v, want %v", resp.StatusCode, http.StatusOK) 243 } 244 var r explorer.NodesResponse 245 if err := json.NewDecoder(resp.Body).Decode(&r); err != nil { 246 t.Fatal(err) 247 } 248 if fmt.Sprint(r.Nodes) != fmt.Sprint(want.Nodes) { 249 t.Errorf("got nodes %v, want %v", r.Nodes, want.Nodes) 250 } 251 if r.Next != want.Next { 252 t.Errorf("got next %s, want %s", r.Next, want.Next) 253 } 254 }