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