github.com/MaynardMiner/ethereumprogpow@v1.8.23/swarm/api/api_test.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum 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 go-ethereum 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 go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package api 18 19 import ( 20 "bytes" 21 "context" 22 "errors" 23 "flag" 24 "fmt" 25 "io" 26 "io/ioutil" 27 "math/big" 28 "os" 29 "testing" 30 31 "github.com/ethereumprogpow/ethereumprogpow/common" 32 "github.com/ethereumprogpow/ethereumprogpow/core/types" 33 "github.com/ethereumprogpow/ethereumprogpow/log" 34 "github.com/ethereumprogpow/ethereumprogpow/swarm/sctx" 35 "github.com/ethereumprogpow/ethereumprogpow/swarm/storage" 36 ) 37 38 func init() { 39 loglevel := flag.Int("loglevel", 2, "loglevel") 40 flag.Parse() 41 log.Root().SetHandler(log.CallerFileHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(os.Stderr, log.TerminalFormat(true))))) 42 } 43 44 func testAPI(t *testing.T, f func(*API, bool)) { 45 datadir, err := ioutil.TempDir("", "bzz-test") 46 if err != nil { 47 t.Fatalf("unable to create temp dir: %v", err) 48 } 49 defer os.RemoveAll(datadir) 50 fileStore, err := storage.NewLocalFileStore(datadir, make([]byte, 32)) 51 if err != nil { 52 return 53 } 54 api := NewAPI(fileStore, nil, nil, nil) 55 f(api, false) 56 f(api, true) 57 } 58 59 type testResponse struct { 60 reader storage.LazySectionReader 61 *Response 62 } 63 64 func checkResponse(t *testing.T, resp *testResponse, exp *Response) { 65 66 if resp.MimeType != exp.MimeType { 67 t.Errorf("incorrect mimeType. expected '%s', got '%s'", exp.MimeType, resp.MimeType) 68 } 69 if resp.Status != exp.Status { 70 t.Errorf("incorrect status. expected '%d', got '%d'", exp.Status, resp.Status) 71 } 72 if resp.Size != exp.Size { 73 t.Errorf("incorrect size. expected '%d', got '%d'", exp.Size, resp.Size) 74 } 75 if resp.reader != nil { 76 content := make([]byte, resp.Size) 77 read, _ := resp.reader.Read(content) 78 if int64(read) != exp.Size { 79 t.Errorf("incorrect content length. expected '%d...', got '%d...'", read, exp.Size) 80 } 81 resp.Content = string(content) 82 } 83 if resp.Content != exp.Content { 84 // if !bytes.Equal(resp.Content, exp.Content) 85 t.Errorf("incorrect content. expected '%s...', got '%s...'", string(exp.Content), string(resp.Content)) 86 } 87 } 88 89 // func expResponse(content []byte, mimeType string, status int) *Response { 90 func expResponse(content string, mimeType string, status int) *Response { 91 log.Trace(fmt.Sprintf("expected content (%v): %v ", len(content), content)) 92 return &Response{mimeType, status, int64(len(content)), content} 93 } 94 95 func testGet(t *testing.T, api *API, bzzhash, path string) *testResponse { 96 addr := storage.Address(common.Hex2Bytes(bzzhash)) 97 reader, mimeType, status, _, err := api.Get(context.TODO(), NOOPDecrypt, addr, path) 98 if err != nil { 99 t.Fatalf("unexpected error: %v", err) 100 } 101 quitC := make(chan bool) 102 size, err := reader.Size(context.TODO(), quitC) 103 if err != nil { 104 t.Fatalf("unexpected error: %v", err) 105 } 106 log.Trace(fmt.Sprintf("reader size: %v ", size)) 107 s := make([]byte, size) 108 _, err = reader.Read(s) 109 if err != io.EOF { 110 t.Fatalf("unexpected error: %v", err) 111 } 112 reader.Seek(0, 0) 113 return &testResponse{reader, &Response{mimeType, status, size, string(s)}} 114 // return &testResponse{reader, &Response{mimeType, status, reader.Size(), nil}} 115 } 116 117 func TestApiPut(t *testing.T) { 118 testAPI(t, func(api *API, toEncrypt bool) { 119 content := "hello" 120 exp := expResponse(content, "text/plain", 0) 121 ctx := context.TODO() 122 addr, wait, err := api.Put(ctx, content, exp.MimeType, toEncrypt) 123 if err != nil { 124 t.Fatalf("unexpected error: %v", err) 125 } 126 err = wait(ctx) 127 if err != nil { 128 t.Fatalf("unexpected error: %v", err) 129 } 130 resp := testGet(t, api, addr.Hex(), "") 131 checkResponse(t, resp, exp) 132 }) 133 } 134 135 // testResolver implements the Resolver interface and either returns the given 136 // hash if it is set, or returns a "name not found" error 137 type testResolveValidator struct { 138 hash *common.Hash 139 } 140 141 func newTestResolveValidator(addr string) *testResolveValidator { 142 r := &testResolveValidator{} 143 if addr != "" { 144 hash := common.HexToHash(addr) 145 r.hash = &hash 146 } 147 return r 148 } 149 150 func (t *testResolveValidator) Resolve(addr string) (common.Hash, error) { 151 if t.hash == nil { 152 return common.Hash{}, fmt.Errorf("DNS name not found: %q", addr) 153 } 154 return *t.hash, nil 155 } 156 157 func (t *testResolveValidator) Owner(node [32]byte) (addr common.Address, err error) { 158 return 159 } 160 func (t *testResolveValidator) HeaderByNumber(context.Context, *big.Int) (header *types.Header, err error) { 161 return 162 } 163 164 // TestAPIResolve tests resolving URIs which can either contain content hashes 165 // or ENS names 166 func TestAPIResolve(t *testing.T) { 167 ensAddr := "swarm.eth" 168 hashAddr := "1111111111111111111111111111111111111111111111111111111111111111" 169 resolvedAddr := "2222222222222222222222222222222222222222222222222222222222222222" 170 doesResolve := newTestResolveValidator(resolvedAddr) 171 doesntResolve := newTestResolveValidator("") 172 173 type test struct { 174 desc string 175 dns Resolver 176 addr string 177 immutable bool 178 result string 179 expectErr error 180 } 181 182 tests := []*test{ 183 { 184 desc: "DNS not configured, hash address, returns hash address", 185 dns: nil, 186 addr: hashAddr, 187 result: hashAddr, 188 }, 189 { 190 desc: "DNS not configured, ENS address, returns error", 191 dns: nil, 192 addr: ensAddr, 193 expectErr: errors.New(`no DNS to resolve name: "swarm.eth"`), 194 }, 195 { 196 desc: "DNS configured, hash address, hash resolves, returns resolved address", 197 dns: doesResolve, 198 addr: hashAddr, 199 result: resolvedAddr, 200 }, 201 { 202 desc: "DNS configured, immutable hash address, hash resolves, returns hash address", 203 dns: doesResolve, 204 addr: hashAddr, 205 immutable: true, 206 result: hashAddr, 207 }, 208 { 209 desc: "DNS configured, hash address, hash doesn't resolve, returns hash address", 210 dns: doesntResolve, 211 addr: hashAddr, 212 result: hashAddr, 213 }, 214 { 215 desc: "DNS configured, ENS address, name resolves, returns resolved address", 216 dns: doesResolve, 217 addr: ensAddr, 218 result: resolvedAddr, 219 }, 220 { 221 desc: "DNS configured, immutable ENS address, name resolves, returns error", 222 dns: doesResolve, 223 addr: ensAddr, 224 immutable: true, 225 expectErr: errors.New(`immutable address not a content hash: "swarm.eth"`), 226 }, 227 { 228 desc: "DNS configured, ENS address, name doesn't resolve, returns error", 229 dns: doesntResolve, 230 addr: ensAddr, 231 expectErr: errors.New(`DNS name not found: "swarm.eth"`), 232 }, 233 } 234 for _, x := range tests { 235 t.Run(x.desc, func(t *testing.T) { 236 api := &API{dns: x.dns} 237 uri := &URI{Addr: x.addr, Scheme: "bzz"} 238 if x.immutable { 239 uri.Scheme = "bzz-immutable" 240 } 241 res, err := api.ResolveURI(context.TODO(), uri, "") 242 if err == nil { 243 if x.expectErr != nil { 244 t.Fatalf("expected error %q, got result %q", x.expectErr, res) 245 } 246 if res.String() != x.result { 247 t.Fatalf("expected result %q, got %q", x.result, res) 248 } 249 } else { 250 if x.expectErr == nil { 251 t.Fatalf("expected no error, got %q", err) 252 } 253 if err.Error() != x.expectErr.Error() { 254 t.Fatalf("expected error %q, got %q", x.expectErr, err) 255 } 256 } 257 }) 258 } 259 } 260 261 func TestMultiResolver(t *testing.T) { 262 doesntResolve := newTestResolveValidator("") 263 264 ethAddr := "swarm.eth" 265 ethHash := "0x2222222222222222222222222222222222222222222222222222222222222222" 266 ethResolve := newTestResolveValidator(ethHash) 267 268 testAddr := "swarm.test" 269 testHash := "0x1111111111111111111111111111111111111111111111111111111111111111" 270 testResolve := newTestResolveValidator(testHash) 271 272 tests := []struct { 273 desc string 274 r Resolver 275 addr string 276 result string 277 err error 278 }{ 279 { 280 desc: "No resolvers, returns error", 281 r: NewMultiResolver(), 282 err: NewNoResolverError(""), 283 }, 284 { 285 desc: "One default resolver, returns resolved address", 286 r: NewMultiResolver(MultiResolverOptionWithResolver(ethResolve, "")), 287 addr: ethAddr, 288 result: ethHash, 289 }, 290 { 291 desc: "Two default resolvers, returns resolved address", 292 r: NewMultiResolver( 293 MultiResolverOptionWithResolver(ethResolve, ""), 294 MultiResolverOptionWithResolver(ethResolve, ""), 295 ), 296 addr: ethAddr, 297 result: ethHash, 298 }, 299 { 300 desc: "Two default resolvers, first doesn't resolve, returns resolved address", 301 r: NewMultiResolver( 302 MultiResolverOptionWithResolver(doesntResolve, ""), 303 MultiResolverOptionWithResolver(ethResolve, ""), 304 ), 305 addr: ethAddr, 306 result: ethHash, 307 }, 308 { 309 desc: "Default resolver doesn't resolve, tld resolver resolve, returns resolved address", 310 r: NewMultiResolver( 311 MultiResolverOptionWithResolver(doesntResolve, ""), 312 MultiResolverOptionWithResolver(ethResolve, "eth"), 313 ), 314 addr: ethAddr, 315 result: ethHash, 316 }, 317 { 318 desc: "Three TLD resolvers, third resolves, returns resolved address", 319 r: NewMultiResolver( 320 MultiResolverOptionWithResolver(doesntResolve, "eth"), 321 MultiResolverOptionWithResolver(doesntResolve, "eth"), 322 MultiResolverOptionWithResolver(ethResolve, "eth"), 323 ), 324 addr: ethAddr, 325 result: ethHash, 326 }, 327 { 328 desc: "One TLD resolver doesn't resolve, returns error", 329 r: NewMultiResolver( 330 MultiResolverOptionWithResolver(doesntResolve, ""), 331 MultiResolverOptionWithResolver(ethResolve, "eth"), 332 ), 333 addr: ethAddr, 334 result: ethHash, 335 }, 336 { 337 desc: "One defautl and one TLD resolver, all doesn't resolve, returns error", 338 r: NewMultiResolver( 339 MultiResolverOptionWithResolver(doesntResolve, ""), 340 MultiResolverOptionWithResolver(doesntResolve, "eth"), 341 ), 342 addr: ethAddr, 343 result: ethHash, 344 err: errors.New(`DNS name not found: "swarm.eth"`), 345 }, 346 { 347 desc: "Two TLD resolvers, both resolve, returns resolved address", 348 r: NewMultiResolver( 349 MultiResolverOptionWithResolver(ethResolve, "eth"), 350 MultiResolverOptionWithResolver(testResolve, "test"), 351 ), 352 addr: testAddr, 353 result: testHash, 354 }, 355 { 356 desc: "One TLD resolver, no default resolver, returns error for different TLD", 357 r: NewMultiResolver( 358 MultiResolverOptionWithResolver(ethResolve, "eth"), 359 ), 360 addr: testAddr, 361 err: NewNoResolverError("test"), 362 }, 363 } 364 for _, x := range tests { 365 t.Run(x.desc, func(t *testing.T) { 366 res, err := x.r.Resolve(x.addr) 367 if err == nil { 368 if x.err != nil { 369 t.Fatalf("expected error %q, got result %q", x.err, res.Hex()) 370 } 371 if res.Hex() != x.result { 372 t.Fatalf("expected result %q, got %q", x.result, res.Hex()) 373 } 374 } else { 375 if x.err == nil { 376 t.Fatalf("expected no error, got %q", err) 377 } 378 if err.Error() != x.err.Error() { 379 t.Fatalf("expected error %q, got %q", x.err, err) 380 } 381 } 382 }) 383 } 384 } 385 386 func TestDecryptOriginForbidden(t *testing.T) { 387 ctx := context.TODO() 388 ctx = sctx.SetHost(ctx, "swarm-gateways.net") 389 390 me := &ManifestEntry{ 391 Access: &AccessEntry{Type: AccessTypePass}, 392 } 393 394 api := NewAPI(nil, nil, nil, nil) 395 396 f := api.Decryptor(ctx, "") 397 err := f(me) 398 if err != ErrDecryptDomainForbidden { 399 t.Fatalf("should fail with ErrDecryptDomainForbidden, got %v", err) 400 } 401 } 402 403 func TestDecryptOrigin(t *testing.T) { 404 for _, v := range []struct { 405 host string 406 expectError error 407 }{ 408 { 409 host: "localhost", 410 expectError: ErrDecrypt, 411 }, 412 { 413 host: "127.0.0.1", 414 expectError: ErrDecrypt, 415 }, 416 { 417 host: "swarm-gateways.net", 418 expectError: ErrDecryptDomainForbidden, 419 }, 420 } { 421 ctx := context.TODO() 422 ctx = sctx.SetHost(ctx, v.host) 423 424 me := &ManifestEntry{ 425 Access: &AccessEntry{Type: AccessTypePass}, 426 } 427 428 api := NewAPI(nil, nil, nil, nil) 429 430 f := api.Decryptor(ctx, "") 431 err := f(me) 432 if err != v.expectError { 433 t.Fatalf("should fail with %v, got %v", v.expectError, err) 434 } 435 } 436 } 437 438 func TestDetectContentType(t *testing.T) { 439 for _, tc := range []struct { 440 file string 441 content string 442 expectedContentType string 443 }{ 444 { 445 file: "file-with-correct-css.css", 446 content: "body {background-color: orange}", 447 expectedContentType: "text/css; charset=utf-8", 448 }, 449 { 450 file: "empty-file.css", 451 content: "", 452 expectedContentType: "text/css; charset=utf-8", 453 }, 454 { 455 file: "empty-file.pdf", 456 content: "", 457 expectedContentType: "application/pdf", 458 }, 459 { 460 file: "empty-file.md", 461 content: "", 462 expectedContentType: "text/markdown; charset=utf-8", 463 }, 464 { 465 file: "empty-file-with-unknown-content.strangeext", 466 content: "", 467 expectedContentType: "text/plain; charset=utf-8", 468 }, 469 { 470 file: "file-with-unknown-extension-and-content.strangeext", 471 content: "Lorem Ipsum", 472 expectedContentType: "text/plain; charset=utf-8", 473 }, 474 { 475 file: "file-no-extension", 476 content: "Lorem Ipsum", 477 expectedContentType: "text/plain; charset=utf-8", 478 }, 479 { 480 file: "file-no-extension-no-content", 481 content: "", 482 expectedContentType: "text/plain; charset=utf-8", 483 }, 484 { 485 file: "css-file-with-html-inside.css", 486 content: "<!doctype html><html><head></head><body></body></html>", 487 expectedContentType: "text/css; charset=utf-8", 488 }, 489 } { 490 t.Run(tc.file, func(t *testing.T) { 491 detected, err := DetectContentType(tc.file, bytes.NewReader([]byte(tc.content))) 492 if err != nil { 493 t.Fatal(err) 494 } 495 496 if detected != tc.expectedContentType { 497 t.Fatalf("File: %s, Expected mime type %s, got %s", tc.file, tc.expectedContentType, detected) 498 } 499 500 }) 501 } 502 }