github.com/hyperion-hyn/go-ethereum@v2.4.0+incompatible/cmd/swarm/upload_test.go (about)

     1  // Copyright 2017 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  	"bytes"
    21  	"fmt"
    22  	"io"
    23  	"io/ioutil"
    24  	"net/http"
    25  	"os"
    26  	"path"
    27  	"path/filepath"
    28  	"runtime"
    29  	"strings"
    30  	"testing"
    31  	"time"
    32  
    33  	"github.com/ethereum/go-ethereum/log"
    34  	swarm "github.com/ethereum/go-ethereum/swarm/api/client"
    35  	swarmhttp "github.com/ethereum/go-ethereum/swarm/api/http"
    36  	"github.com/ethereum/go-ethereum/swarm/testutil"
    37  	"github.com/mattn/go-colorable"
    38  )
    39  
    40  func init() {
    41  	log.PrintOrigins(true)
    42  	log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true))))
    43  }
    44  
    45  // TestCLISwarmUp tests that running 'swarm up' makes the resulting file
    46  // available from all nodes via the HTTP API
    47  func TestCLISwarmUp(t *testing.T) {
    48  	if runtime.GOOS == "windows" {
    49  		t.Skip()
    50  	}
    51  
    52  	testCLISwarmUp(false, t)
    53  }
    54  func TestCLISwarmUpRecursive(t *testing.T) {
    55  	if runtime.GOOS == "windows" {
    56  		t.Skip()
    57  	}
    58  	testCLISwarmUpRecursive(false, t)
    59  }
    60  
    61  // TestCLISwarmUpEncrypted tests that running 'swarm encrypted-up' makes the resulting file
    62  // available from all nodes via the HTTP API
    63  func TestCLISwarmUpEncrypted(t *testing.T) {
    64  	if runtime.GOOS == "windows" {
    65  		t.Skip()
    66  	}
    67  	testCLISwarmUp(true, t)
    68  }
    69  func TestCLISwarmUpEncryptedRecursive(t *testing.T) {
    70  	if runtime.GOOS == "windows" {
    71  		t.Skip()
    72  	}
    73  	testCLISwarmUpRecursive(true, t)
    74  }
    75  
    76  func testCLISwarmUp(toEncrypt bool, t *testing.T) {
    77  	log.Info("starting 3 node cluster")
    78  	cluster := newTestCluster(t, 3)
    79  	defer cluster.Shutdown()
    80  
    81  	tmpFileName := testutil.TempFileWithContent(t, data)
    82  	defer os.Remove(tmpFileName)
    83  
    84  	// write data to file
    85  	hashRegexp := `[a-f\d]{64}`
    86  	flags := []string{
    87  		"--bzzapi", cluster.Nodes[0].URL,
    88  		"up",
    89  		tmpFileName}
    90  	if toEncrypt {
    91  		hashRegexp = `[a-f\d]{128}`
    92  		flags = []string{
    93  			"--bzzapi", cluster.Nodes[0].URL,
    94  			"up",
    95  			"--encrypt",
    96  			tmpFileName}
    97  	}
    98  	// upload the file with 'swarm up' and expect a hash
    99  	log.Info(fmt.Sprintf("uploading file with 'swarm up'"))
   100  	up := runSwarm(t, flags...)
   101  	_, matches := up.ExpectRegexp(hashRegexp)
   102  	up.ExpectExit()
   103  	hash := matches[0]
   104  	log.Info("file uploaded", "hash", hash)
   105  
   106  	// get the file from the HTTP API of each node
   107  	for _, node := range cluster.Nodes {
   108  		log.Info("getting file from node", "node", node.Name)
   109  
   110  		res, err := http.Get(node.URL + "/bzz:/" + hash)
   111  		if err != nil {
   112  			t.Fatal(err)
   113  		}
   114  		defer res.Body.Close()
   115  
   116  		reply, err := ioutil.ReadAll(res.Body)
   117  		if err != nil {
   118  			t.Fatal(err)
   119  		}
   120  		if res.StatusCode != 200 {
   121  			t.Fatalf("expected HTTP status 200, got %s", res.Status)
   122  		}
   123  		if string(reply) != data {
   124  			t.Fatalf("expected HTTP body %q, got %q", data, reply)
   125  		}
   126  		log.Debug("verifying uploaded file using `swarm down`")
   127  		//try to get the content with `swarm down`
   128  		tmpDownload, err := ioutil.TempDir("", "swarm-test")
   129  		tmpDownload = path.Join(tmpDownload, "tmpfile.tmp")
   130  		if err != nil {
   131  			t.Fatal(err)
   132  		}
   133  		defer os.RemoveAll(tmpDownload)
   134  
   135  		bzzLocator := "bzz:/" + hash
   136  		flags = []string{
   137  			"--bzzapi", cluster.Nodes[0].URL,
   138  			"down",
   139  			bzzLocator,
   140  			tmpDownload,
   141  		}
   142  
   143  		down := runSwarm(t, flags...)
   144  		down.ExpectExit()
   145  
   146  		fi, err := os.Stat(tmpDownload)
   147  		if err != nil {
   148  			t.Fatalf("could not stat path: %v", err)
   149  		}
   150  
   151  		switch mode := fi.Mode(); {
   152  		case mode.IsRegular():
   153  			downloadedBytes, err := ioutil.ReadFile(tmpDownload)
   154  			if err != nil {
   155  				t.Fatalf("had an error reading the downloaded file: %v", err)
   156  			}
   157  			if !bytes.Equal(downloadedBytes, bytes.NewBufferString(data).Bytes()) {
   158  				t.Fatalf("retrieved data and posted data not equal!")
   159  			}
   160  
   161  		default:
   162  			t.Fatalf("expected to download regular file, got %s", fi.Mode())
   163  		}
   164  	}
   165  
   166  	timeout := time.Duration(2 * time.Second)
   167  	httpClient := http.Client{
   168  		Timeout: timeout,
   169  	}
   170  
   171  	// try to squeeze a timeout by getting an non-existent hash from each node
   172  	for _, node := range cluster.Nodes {
   173  		_, err := httpClient.Get(node.URL + "/bzz:/1023e8bae0f70be7d7b5f74343088ba408a218254391490c85ae16278e230340")
   174  		// we're speeding up the timeout here since netstore has a 60 seconds timeout on a request
   175  		if err != nil && !strings.Contains(err.Error(), "Client.Timeout exceeded while awaiting headers") {
   176  			t.Fatal(err)
   177  		}
   178  		// this is disabled since it takes 60s due to netstore timeout
   179  		// if res.StatusCode != 404 {
   180  		// 	t.Fatalf("expected HTTP status 404, got %s", res.Status)
   181  		// }
   182  	}
   183  }
   184  
   185  func testCLISwarmUpRecursive(toEncrypt bool, t *testing.T) {
   186  	fmt.Println("starting 3 node cluster")
   187  	cluster := newTestCluster(t, 3)
   188  	defer cluster.Shutdown()
   189  
   190  	tmpUploadDir, err := ioutil.TempDir("", "swarm-test")
   191  	if err != nil {
   192  		t.Fatal(err)
   193  	}
   194  	defer os.RemoveAll(tmpUploadDir)
   195  	// create tmp files
   196  	for _, path := range []string{"tmp1", "tmp2"} {
   197  		if err := ioutil.WriteFile(filepath.Join(tmpUploadDir, path), bytes.NewBufferString(data).Bytes(), 0644); err != nil {
   198  			t.Fatal(err)
   199  		}
   200  	}
   201  
   202  	hashRegexp := `[a-f\d]{64}`
   203  	flags := []string{
   204  		"--bzzapi", cluster.Nodes[0].URL,
   205  		"--recursive",
   206  		"up",
   207  		tmpUploadDir}
   208  	if toEncrypt {
   209  		hashRegexp = `[a-f\d]{128}`
   210  		flags = []string{
   211  			"--bzzapi", cluster.Nodes[0].URL,
   212  			"--recursive",
   213  			"up",
   214  			"--encrypt",
   215  			tmpUploadDir}
   216  	}
   217  	// upload the file with 'swarm up' and expect a hash
   218  	log.Info(fmt.Sprintf("uploading file with 'swarm up'"))
   219  	up := runSwarm(t, flags...)
   220  	_, matches := up.ExpectRegexp(hashRegexp)
   221  	up.ExpectExit()
   222  	hash := matches[0]
   223  	log.Info("dir uploaded", "hash", hash)
   224  
   225  	// get the file from the HTTP API of each node
   226  	for _, node := range cluster.Nodes {
   227  		log.Info("getting file from node", "node", node.Name)
   228  		//try to get the content with `swarm down`
   229  		tmpDownload, err := ioutil.TempDir("", "swarm-test")
   230  		if err != nil {
   231  			t.Fatal(err)
   232  		}
   233  		defer os.RemoveAll(tmpDownload)
   234  		bzzLocator := "bzz:/" + hash
   235  		flagss := []string{
   236  			"--bzzapi", cluster.Nodes[0].URL,
   237  			"down",
   238  			"--recursive",
   239  			bzzLocator,
   240  			tmpDownload,
   241  		}
   242  
   243  		fmt.Println("downloading from swarm with recursive")
   244  		down := runSwarm(t, flagss...)
   245  		down.ExpectExit()
   246  
   247  		files, err := ioutil.ReadDir(tmpDownload)
   248  		for _, v := range files {
   249  			fi, err := os.Stat(path.Join(tmpDownload, v.Name()))
   250  			if err != nil {
   251  				t.Fatalf("got an error: %v", err)
   252  			}
   253  
   254  			switch mode := fi.Mode(); {
   255  			case mode.IsRegular():
   256  				if file, err := swarm.Open(path.Join(tmpDownload, v.Name())); err != nil {
   257  					t.Fatalf("encountered an error opening the file returned from the CLI: %v", err)
   258  				} else {
   259  					ff := make([]byte, len(data))
   260  					io.ReadFull(file, ff)
   261  					buf := bytes.NewBufferString(data)
   262  
   263  					if !bytes.Equal(ff, buf.Bytes()) {
   264  						t.Fatalf("retrieved data and posted data not equal!")
   265  					}
   266  				}
   267  			default:
   268  				t.Fatalf("this shouldnt happen")
   269  			}
   270  		}
   271  		if err != nil {
   272  			t.Fatalf("could not list files at: %v", files)
   273  		}
   274  	}
   275  }
   276  
   277  // TestCLISwarmUpDefaultPath tests swarm recursive upload with relative and absolute
   278  // default paths and with encryption.
   279  func TestCLISwarmUpDefaultPath(t *testing.T) {
   280  	if runtime.GOOS == "windows" {
   281  		t.Skip()
   282  	}
   283  	testCLISwarmUpDefaultPath(false, false, t)
   284  	testCLISwarmUpDefaultPath(false, true, t)
   285  	testCLISwarmUpDefaultPath(true, false, t)
   286  	testCLISwarmUpDefaultPath(true, true, t)
   287  }
   288  
   289  func testCLISwarmUpDefaultPath(toEncrypt bool, absDefaultPath bool, t *testing.T) {
   290  	srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil)
   291  	defer srv.Close()
   292  
   293  	tmp, err := ioutil.TempDir("", "swarm-defaultpath-test")
   294  	if err != nil {
   295  		t.Fatal(err)
   296  	}
   297  	defer os.RemoveAll(tmp)
   298  
   299  	err = ioutil.WriteFile(filepath.Join(tmp, "index.html"), []byte("<h1>Test</h1>"), 0666)
   300  	if err != nil {
   301  		t.Fatal(err)
   302  	}
   303  	err = ioutil.WriteFile(filepath.Join(tmp, "robots.txt"), []byte("Disallow: /"), 0666)
   304  	if err != nil {
   305  		t.Fatal(err)
   306  	}
   307  
   308  	defaultPath := "index.html"
   309  	if absDefaultPath {
   310  		defaultPath = filepath.Join(tmp, defaultPath)
   311  	}
   312  
   313  	args := []string{
   314  		"--bzzapi",
   315  		srv.URL,
   316  		"--recursive",
   317  		"--defaultpath",
   318  		defaultPath,
   319  		"up",
   320  		tmp,
   321  	}
   322  	if toEncrypt {
   323  		args = append(args, "--encrypt")
   324  	}
   325  
   326  	up := runSwarm(t, args...)
   327  	hashRegexp := `[a-f\d]{64,128}`
   328  	_, matches := up.ExpectRegexp(hashRegexp)
   329  	up.ExpectExit()
   330  	hash := matches[0]
   331  
   332  	client := swarm.NewClient(srv.URL)
   333  
   334  	m, isEncrypted, err := client.DownloadManifest(hash)
   335  	if err != nil {
   336  		t.Fatal(err)
   337  	}
   338  
   339  	if toEncrypt != isEncrypted {
   340  		t.Error("downloaded manifest is not encrypted")
   341  	}
   342  
   343  	var found bool
   344  	var entriesCount int
   345  	for _, e := range m.Entries {
   346  		entriesCount++
   347  		if e.Path == "" {
   348  			found = true
   349  		}
   350  	}
   351  
   352  	if !found {
   353  		t.Error("manifest default entry was not found")
   354  	}
   355  
   356  	if entriesCount != 3 {
   357  		t.Errorf("manifest contains %v entries, expected %v", entriesCount, 3)
   358  	}
   359  }