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  }