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