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