github.com/FUSIONFoundation/efsn@v3.6.2-0.20200916075423-dbb5dd5d2cc7+incompatible/cmd/swarm/manifest_test.go (about)

     1  // Copyright 2018 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  	"io/ioutil"
    22  	"os"
    23  	"path/filepath"
    24  	"testing"
    25  
    26  	"github.com/FusionFoundation/efsn/swarm/api"
    27  	swarm "github.com/FusionFoundation/efsn/swarm/api/client"
    28  )
    29  
    30  // TestManifestChange tests manifest add, update and remove
    31  // cli commands without encryption.
    32  func TestManifestChange(t *testing.T) {
    33  	testManifestChange(t, false)
    34  }
    35  
    36  // TestManifestChange tests manifest add, update and remove
    37  // cli commands with encryption enabled.
    38  func TestManifestChangeEncrypted(t *testing.T) {
    39  	testManifestChange(t, true)
    40  }
    41  
    42  // testManifestChange performs cli commands:
    43  // - manifest add
    44  // - manifest update
    45  // - manifest remove
    46  // on a manifest, testing the functionality of this
    47  // comands on paths that are in root manifest or a nested one.
    48  // Argument encrypt controls whether to use encryption or not.
    49  func testManifestChange(t *testing.T, encrypt bool) {
    50  	t.Parallel()
    51  	cluster := newTestCluster(t, 1)
    52  	defer cluster.Shutdown()
    53  
    54  	tmp, err := ioutil.TempDir("", "swarm-manifest-test")
    55  	if err != nil {
    56  		t.Fatal(err)
    57  	}
    58  	defer os.RemoveAll(tmp)
    59  
    60  	origDir := filepath.Join(tmp, "orig")
    61  	if err := os.Mkdir(origDir, 0777); err != nil {
    62  		t.Fatal(err)
    63  	}
    64  
    65  	indexDataFilename := filepath.Join(origDir, "index.html")
    66  	err = ioutil.WriteFile(indexDataFilename, []byte("<h1>Test</h1>"), 0666)
    67  	if err != nil {
    68  		t.Fatal(err)
    69  	}
    70  	// Files paths robots.txt and robots.html share the same prefix "robots."
    71  	// which will result a manifest with a nested manifest under path "robots.".
    72  	// This will allow testing manifest changes on both root and nested manifest.
    73  	err = ioutil.WriteFile(filepath.Join(origDir, "robots.txt"), []byte("Disallow: /"), 0666)
    74  	if err != nil {
    75  		t.Fatal(err)
    76  	}
    77  	err = ioutil.WriteFile(filepath.Join(origDir, "robots.html"), []byte("<strong>No Robots Allowed</strong>"), 0666)
    78  	if err != nil {
    79  		t.Fatal(err)
    80  	}
    81  	err = ioutil.WriteFile(filepath.Join(origDir, "mutants.txt"), []byte("Frank\nMarcus"), 0666)
    82  	if err != nil {
    83  		t.Fatal(err)
    84  	}
    85  
    86  	args := []string{
    87  		"--bzzapi",
    88  		cluster.Nodes[0].URL,
    89  		"--recursive",
    90  		"--defaultpath",
    91  		indexDataFilename,
    92  		"up",
    93  		origDir,
    94  	}
    95  	if encrypt {
    96  		args = append(args, "--encrypt")
    97  	}
    98  
    99  	origManifestHash := runSwarmExpectHash(t, args...)
   100  
   101  	checkHashLength(t, origManifestHash, encrypt)
   102  
   103  	client := swarm.NewClient(cluster.Nodes[0].URL)
   104  
   105  	// upload a new file and use its manifest to add it the original manifest.
   106  	t.Run("add", func(t *testing.T) {
   107  		humansData := []byte("Ann\nBob")
   108  		humansDataFilename := filepath.Join(tmp, "humans.txt")
   109  		err = ioutil.WriteFile(humansDataFilename, humansData, 0666)
   110  		if err != nil {
   111  			t.Fatal(err)
   112  		}
   113  
   114  		humansManifestHash := runSwarmExpectHash(t,
   115  			"--bzzapi",
   116  			cluster.Nodes[0].URL,
   117  			"up",
   118  			humansDataFilename,
   119  		)
   120  
   121  		newManifestHash := runSwarmExpectHash(t,
   122  			"--bzzapi",
   123  			cluster.Nodes[0].URL,
   124  			"manifest",
   125  			"add",
   126  			origManifestHash,
   127  			"humans.txt",
   128  			humansManifestHash,
   129  		)
   130  
   131  		checkHashLength(t, newManifestHash, encrypt)
   132  
   133  		newManifest := downloadManifest(t, client, newManifestHash, encrypt)
   134  
   135  		var found bool
   136  		for _, e := range newManifest.Entries {
   137  			if e.Path == "humans.txt" {
   138  				found = true
   139  				if e.Size != int64(len(humansData)) {
   140  					t.Errorf("expected humans.txt size %v, got %v", len(humansData), e.Size)
   141  				}
   142  				if e.ModTime.IsZero() {
   143  					t.Errorf("got zero mod time for humans.txt")
   144  				}
   145  				ct := "text/plain; charset=utf-8"
   146  				if e.ContentType != ct {
   147  					t.Errorf("expected content type %q, got %q", ct, e.ContentType)
   148  				}
   149  				break
   150  			}
   151  		}
   152  		if !found {
   153  			t.Fatal("no humans.txt in new manifest")
   154  		}
   155  
   156  		checkFile(t, client, newManifestHash, "humans.txt", humansData)
   157  	})
   158  
   159  	// upload a new file and use its manifest to add it the original manifest,
   160  	// but ensure that the file will be in the nested manifest of the original one.
   161  	t.Run("add nested", func(t *testing.T) {
   162  		robotsData := []byte(`{"disallow": "/"}`)
   163  		robotsDataFilename := filepath.Join(tmp, "robots.json")
   164  		err = ioutil.WriteFile(robotsDataFilename, robotsData, 0666)
   165  		if err != nil {
   166  			t.Fatal(err)
   167  		}
   168  
   169  		robotsManifestHash := runSwarmExpectHash(t,
   170  			"--bzzapi",
   171  			cluster.Nodes[0].URL,
   172  			"up",
   173  			robotsDataFilename,
   174  		)
   175  
   176  		newManifestHash := runSwarmExpectHash(t,
   177  			"--bzzapi",
   178  			cluster.Nodes[0].URL,
   179  			"manifest",
   180  			"add",
   181  			origManifestHash,
   182  			"robots.json",
   183  			robotsManifestHash,
   184  		)
   185  
   186  		checkHashLength(t, newManifestHash, encrypt)
   187  
   188  		newManifest := downloadManifest(t, client, newManifestHash, encrypt)
   189  
   190  		var found bool
   191  	loop:
   192  		for _, e := range newManifest.Entries {
   193  			if e.Path == "robots." {
   194  				nestedManifest := downloadManifest(t, client, e.Hash, encrypt)
   195  				for _, e := range nestedManifest.Entries {
   196  					if e.Path == "json" {
   197  						found = true
   198  						if e.Size != int64(len(robotsData)) {
   199  							t.Errorf("expected robots.json size %v, got %v", len(robotsData), e.Size)
   200  						}
   201  						if e.ModTime.IsZero() {
   202  							t.Errorf("got zero mod time for robots.json")
   203  						}
   204  						ct := "application/json"
   205  						if e.ContentType != ct {
   206  							t.Errorf("expected content type %q, got %q", ct, e.ContentType)
   207  						}
   208  						break loop
   209  					}
   210  				}
   211  			}
   212  		}
   213  		if !found {
   214  			t.Fatal("no robots.json in new manifest")
   215  		}
   216  
   217  		checkFile(t, client, newManifestHash, "robots.json", robotsData)
   218  	})
   219  
   220  	// upload a new file and use its manifest to change the file it the original manifest.
   221  	t.Run("update", func(t *testing.T) {
   222  		indexData := []byte("<h1>Ethereum Swarm</h1>")
   223  		indexDataFilename := filepath.Join(tmp, "index.html")
   224  		err = ioutil.WriteFile(indexDataFilename, indexData, 0666)
   225  		if err != nil {
   226  			t.Fatal(err)
   227  		}
   228  
   229  		indexManifestHash := runSwarmExpectHash(t,
   230  			"--bzzapi",
   231  			cluster.Nodes[0].URL,
   232  			"up",
   233  			indexDataFilename,
   234  		)
   235  
   236  		newManifestHash := runSwarmExpectHash(t,
   237  			"--bzzapi",
   238  			cluster.Nodes[0].URL,
   239  			"manifest",
   240  			"update",
   241  			origManifestHash,
   242  			"index.html",
   243  			indexManifestHash,
   244  		)
   245  
   246  		checkHashLength(t, newManifestHash, encrypt)
   247  
   248  		newManifest := downloadManifest(t, client, newManifestHash, encrypt)
   249  
   250  		var found bool
   251  		for _, e := range newManifest.Entries {
   252  			if e.Path == "index.html" {
   253  				found = true
   254  				if e.Size != int64(len(indexData)) {
   255  					t.Errorf("expected index.html size %v, got %v", len(indexData), e.Size)
   256  				}
   257  				if e.ModTime.IsZero() {
   258  					t.Errorf("got zero mod time for index.html")
   259  				}
   260  				ct := "text/html; charset=utf-8"
   261  				if e.ContentType != ct {
   262  					t.Errorf("expected content type %q, got %q", ct, e.ContentType)
   263  				}
   264  				break
   265  			}
   266  		}
   267  		if !found {
   268  			t.Fatal("no index.html in new manifest")
   269  		}
   270  
   271  		checkFile(t, client, newManifestHash, "index.html", indexData)
   272  
   273  		// check default entry change
   274  		checkFile(t, client, newManifestHash, "", indexData)
   275  	})
   276  
   277  	// upload a new file and use its manifest to change the file it the original manifest,
   278  	// but ensure that the file is in the nested manifest of the original one.
   279  	t.Run("update nested", func(t *testing.T) {
   280  		robotsData := []byte(`<string>Only humans allowed!!!</strong>`)
   281  		robotsDataFilename := filepath.Join(tmp, "robots.html")
   282  		err = ioutil.WriteFile(robotsDataFilename, robotsData, 0666)
   283  		if err != nil {
   284  			t.Fatal(err)
   285  		}
   286  
   287  		humansManifestHash := runSwarmExpectHash(t,
   288  			"--bzzapi",
   289  			cluster.Nodes[0].URL,
   290  			"up",
   291  			robotsDataFilename,
   292  		)
   293  
   294  		newManifestHash := runSwarmExpectHash(t,
   295  			"--bzzapi",
   296  			cluster.Nodes[0].URL,
   297  			"manifest",
   298  			"update",
   299  			origManifestHash,
   300  			"robots.html",
   301  			humansManifestHash,
   302  		)
   303  
   304  		checkHashLength(t, newManifestHash, encrypt)
   305  
   306  		newManifest := downloadManifest(t, client, newManifestHash, encrypt)
   307  
   308  		var found bool
   309  	loop:
   310  		for _, e := range newManifest.Entries {
   311  			if e.Path == "robots." {
   312  				nestedManifest := downloadManifest(t, client, e.Hash, encrypt)
   313  				for _, e := range nestedManifest.Entries {
   314  					if e.Path == "html" {
   315  						found = true
   316  						if e.Size != int64(len(robotsData)) {
   317  							t.Errorf("expected robots.html size %v, got %v", len(robotsData), e.Size)
   318  						}
   319  						if e.ModTime.IsZero() {
   320  							t.Errorf("got zero mod time for robots.html")
   321  						}
   322  						ct := "text/html; charset=utf-8"
   323  						if e.ContentType != ct {
   324  							t.Errorf("expected content type %q, got %q", ct, e.ContentType)
   325  						}
   326  						break loop
   327  					}
   328  				}
   329  			}
   330  		}
   331  		if !found {
   332  			t.Fatal("no robots.html in new manifest")
   333  		}
   334  
   335  		checkFile(t, client, newManifestHash, "robots.html", robotsData)
   336  	})
   337  
   338  	// remove a file from the manifest.
   339  	t.Run("remove", func(t *testing.T) {
   340  		newManifestHash := runSwarmExpectHash(t,
   341  			"--bzzapi",
   342  			cluster.Nodes[0].URL,
   343  			"manifest",
   344  			"remove",
   345  			origManifestHash,
   346  			"mutants.txt",
   347  		)
   348  
   349  		checkHashLength(t, newManifestHash, encrypt)
   350  
   351  		newManifest := downloadManifest(t, client, newManifestHash, encrypt)
   352  
   353  		var found bool
   354  		for _, e := range newManifest.Entries {
   355  			if e.Path == "mutants.txt" {
   356  				found = true
   357  				break
   358  			}
   359  		}
   360  		if found {
   361  			t.Fatal("mutants.txt is not removed")
   362  		}
   363  	})
   364  
   365  	// remove a file from the manifest, but ensure that the file is in
   366  	// the nested manifest of the original one.
   367  	t.Run("remove nested", func(t *testing.T) {
   368  		newManifestHash := runSwarmExpectHash(t,
   369  			"--bzzapi",
   370  			cluster.Nodes[0].URL,
   371  			"manifest",
   372  			"remove",
   373  			origManifestHash,
   374  			"robots.html",
   375  		)
   376  
   377  		checkHashLength(t, newManifestHash, encrypt)
   378  
   379  		newManifest := downloadManifest(t, client, newManifestHash, encrypt)
   380  
   381  		var found bool
   382  	loop:
   383  		for _, e := range newManifest.Entries {
   384  			if e.Path == "robots." {
   385  				nestedManifest := downloadManifest(t, client, e.Hash, encrypt)
   386  				for _, e := range nestedManifest.Entries {
   387  					if e.Path == "html" {
   388  						found = true
   389  						break loop
   390  					}
   391  				}
   392  			}
   393  		}
   394  		if found {
   395  			t.Fatal("robots.html in not removed")
   396  		}
   397  	})
   398  }
   399  
   400  // TestNestedDefaultEntryUpdate tests if the default entry is updated
   401  // if the file in nested manifest used for it is also updated.
   402  func TestNestedDefaultEntryUpdate(t *testing.T) {
   403  	testNestedDefaultEntryUpdate(t, false)
   404  }
   405  
   406  // TestNestedDefaultEntryUpdateEncrypted tests if the default entry
   407  // of encrypted upload is updated if the file in nested manifest
   408  // used for it is also updated.
   409  func TestNestedDefaultEntryUpdateEncrypted(t *testing.T) {
   410  	testNestedDefaultEntryUpdate(t, true)
   411  }
   412  
   413  func testNestedDefaultEntryUpdate(t *testing.T, encrypt bool) {
   414  	t.Parallel()
   415  	cluster := newTestCluster(t, 1)
   416  	defer cluster.Shutdown()
   417  
   418  	tmp, err := ioutil.TempDir("", "swarm-manifest-test")
   419  	if err != nil {
   420  		t.Fatal(err)
   421  	}
   422  	defer os.RemoveAll(tmp)
   423  
   424  	origDir := filepath.Join(tmp, "orig")
   425  	if err := os.Mkdir(origDir, 0777); err != nil {
   426  		t.Fatal(err)
   427  	}
   428  
   429  	indexData := []byte("<h1>Test</h1>")
   430  	indexDataFilename := filepath.Join(origDir, "index.html")
   431  	err = ioutil.WriteFile(indexDataFilename, indexData, 0666)
   432  	if err != nil {
   433  		t.Fatal(err)
   434  	}
   435  	// Add another file with common prefix as the default entry to test updates of
   436  	// default entry with nested manifests.
   437  	err = ioutil.WriteFile(filepath.Join(origDir, "index.txt"), []byte("Test"), 0666)
   438  	if err != nil {
   439  		t.Fatal(err)
   440  	}
   441  
   442  	args := []string{
   443  		"--bzzapi",
   444  		cluster.Nodes[0].URL,
   445  		"--recursive",
   446  		"--defaultpath",
   447  		indexDataFilename,
   448  		"up",
   449  		origDir,
   450  	}
   451  	if encrypt {
   452  		args = append(args, "--encrypt")
   453  	}
   454  
   455  	origManifestHash := runSwarmExpectHash(t, args...)
   456  
   457  	checkHashLength(t, origManifestHash, encrypt)
   458  
   459  	client := swarm.NewClient(cluster.Nodes[0].URL)
   460  
   461  	newIndexData := []byte("<h1>Ethereum Swarm</h1>")
   462  	newIndexDataFilename := filepath.Join(tmp, "index.html")
   463  	err = ioutil.WriteFile(newIndexDataFilename, newIndexData, 0666)
   464  	if err != nil {
   465  		t.Fatal(err)
   466  	}
   467  
   468  	newIndexManifestHash := runSwarmExpectHash(t,
   469  		"--bzzapi",
   470  		cluster.Nodes[0].URL,
   471  		"up",
   472  		newIndexDataFilename,
   473  	)
   474  
   475  	newManifestHash := runSwarmExpectHash(t,
   476  		"--bzzapi",
   477  		cluster.Nodes[0].URL,
   478  		"manifest",
   479  		"update",
   480  		origManifestHash,
   481  		"index.html",
   482  		newIndexManifestHash,
   483  	)
   484  
   485  	checkHashLength(t, newManifestHash, encrypt)
   486  
   487  	newManifest := downloadManifest(t, client, newManifestHash, encrypt)
   488  
   489  	var found bool
   490  	for _, e := range newManifest.Entries {
   491  		if e.Path == "index." {
   492  			found = true
   493  			newManifest = downloadManifest(t, client, e.Hash, encrypt)
   494  			break
   495  		}
   496  	}
   497  	if !found {
   498  		t.Fatal("no index. path in new manifest")
   499  	}
   500  
   501  	found = false
   502  	for _, e := range newManifest.Entries {
   503  		if e.Path == "html" {
   504  			found = true
   505  			if e.Size != int64(len(newIndexData)) {
   506  				t.Errorf("expected index.html size %v, got %v", len(newIndexData), e.Size)
   507  			}
   508  			if e.ModTime.IsZero() {
   509  				t.Errorf("got zero mod time for index.html")
   510  			}
   511  			ct := "text/html; charset=utf-8"
   512  			if e.ContentType != ct {
   513  				t.Errorf("expected content type %q, got %q", ct, e.ContentType)
   514  			}
   515  			break
   516  		}
   517  	}
   518  	if !found {
   519  		t.Fatal("no html in new manifest")
   520  	}
   521  
   522  	checkFile(t, client, newManifestHash, "index.html", newIndexData)
   523  
   524  	// check default entry change
   525  	checkFile(t, client, newManifestHash, "", newIndexData)
   526  }
   527  
   528  func runSwarmExpectHash(t *testing.T, args ...string) (hash string) {
   529  	t.Helper()
   530  	hashRegexp := `[a-f\d]{64,128}`
   531  	up := runSwarm(t, args...)
   532  	_, matches := up.ExpectRegexp(hashRegexp)
   533  	up.ExpectExit()
   534  
   535  	if len(matches) < 1 {
   536  		t.Fatal("no matches found")
   537  	}
   538  	return matches[0]
   539  }
   540  
   541  func checkHashLength(t *testing.T, hash string, encrypted bool) {
   542  	t.Helper()
   543  	l := len(hash)
   544  	if encrypted && l != 128 {
   545  		t.Errorf("expected hash length 128, got %v", l)
   546  	}
   547  	if !encrypted && l != 64 {
   548  		t.Errorf("expected hash length 64, got %v", l)
   549  	}
   550  }
   551  
   552  func downloadManifest(t *testing.T, client *swarm.Client, hash string, encrypted bool) (manifest *api.Manifest) {
   553  	t.Helper()
   554  	m, isEncrypted, err := client.DownloadManifest(hash)
   555  	if err != nil {
   556  		t.Fatal(err)
   557  	}
   558  
   559  	if encrypted != isEncrypted {
   560  		t.Error("new manifest encryption flag is not correct")
   561  	}
   562  	return m
   563  }
   564  
   565  func checkFile(t *testing.T, client *swarm.Client, hash, path string, expected []byte) {
   566  	t.Helper()
   567  	f, err := client.Download(hash, path)
   568  	if err != nil {
   569  		t.Fatal(err)
   570  	}
   571  
   572  	got, err := ioutil.ReadAll(f)
   573  	if err != nil {
   574  		t.Fatal(err)
   575  	}
   576  	if !bytes.Equal(got, expected) {
   577  		t.Errorf("expected file content %q, got %q", expected, got)
   578  	}
   579  }