github.com/Synthesix/Sia@v1.3.3-0.20180413141344-f863baeed3ca/node/api/hostdb_test.go (about)

     1  package api
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"io/ioutil"
     8  	"net/url"
     9  	"path/filepath"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/Synthesix/Sia/build"
    14  	"github.com/Synthesix/Sia/crypto"
    15  	"github.com/Synthesix/Sia/modules"
    16  	"github.com/Synthesix/Sia/modules/consensus"
    17  	"github.com/Synthesix/Sia/modules/gateway"
    18  	"github.com/Synthesix/Sia/modules/host"
    19  	"github.com/Synthesix/Sia/modules/miner"
    20  	"github.com/Synthesix/Sia/modules/renter"
    21  	"github.com/Synthesix/Sia/modules/transactionpool"
    22  	"github.com/Synthesix/Sia/modules/wallet"
    23  )
    24  
    25  // TestHostDBHostsActiveHandler checks the behavior of the call to
    26  // /hostdb/active.
    27  func TestHostDBHostsActiveHandler(t *testing.T) {
    28  	if testing.Short() {
    29  		t.SkipNow()
    30  	}
    31  	st, err := createServerTester(t.Name())
    32  	if err != nil {
    33  		t.Fatal(err)
    34  	}
    35  	defer st.server.panicClose()
    36  
    37  	// Try the call with numhosts unset, and set to -1, 0, and 1.
    38  	var ah HostdbActiveGET
    39  	err = st.getAPI("/hostdb/active", &ah)
    40  	if err != nil {
    41  		t.Fatal(err)
    42  	}
    43  	if len(ah.Hosts) != 0 {
    44  		t.Fatal(len(ah.Hosts))
    45  	}
    46  	err = st.getAPI("/hostdb/active?numhosts=-1", &ah)
    47  	if err == nil {
    48  		t.Fatal("expecting an error, got:", err)
    49  	}
    50  	err = st.getAPI("/hostdb/active?numhosts=0", &ah)
    51  	if err != nil {
    52  		t.Fatal(err)
    53  	}
    54  	if len(ah.Hosts) != 0 {
    55  		t.Fatal(len(ah.Hosts))
    56  	}
    57  	err = st.getAPI("/hostdb/active?numhosts=1", &ah)
    58  	if err != nil {
    59  		t.Fatal(err)
    60  	}
    61  	if len(ah.Hosts) != 0 {
    62  		t.Fatal(len(ah.Hosts))
    63  	}
    64  
    65  	// announce the host and start accepting contracts
    66  	err = st.announceHost()
    67  	if err != nil {
    68  		t.Fatal(err)
    69  	}
    70  	err = st.acceptContracts()
    71  	if err != nil {
    72  		t.Fatal(err)
    73  	}
    74  	err = st.setHostStorage()
    75  	if err != nil {
    76  		t.Fatal(err)
    77  	}
    78  
    79  	// Try the call with with numhosts unset, and set to -1, 0, 1, and 2.
    80  	err = st.getAPI("/hostdb/active", &ah)
    81  	if err != nil {
    82  		t.Fatal(err)
    83  	}
    84  	if len(ah.Hosts) != 1 {
    85  		t.Fatal(len(ah.Hosts))
    86  	}
    87  	err = st.getAPI("/hostdb/active?numhosts=-1", &ah)
    88  	if err == nil {
    89  		t.Fatal("expecting an error, got:", err)
    90  	}
    91  	err = st.getAPI("/hostdb/active?numhosts=0", &ah)
    92  	if err != nil {
    93  		t.Fatal(err)
    94  	}
    95  	if len(ah.Hosts) != 0 {
    96  		t.Fatal(len(ah.Hosts))
    97  	}
    98  	err = st.getAPI("/hostdb/active?numhosts=1", &ah)
    99  	if err != nil {
   100  		t.Fatal(err)
   101  	}
   102  	if len(ah.Hosts) != 1 {
   103  		t.Fatal(len(ah.Hosts))
   104  	}
   105  	err = st.getAPI("/hostdb/active?numhosts=2", &ah)
   106  	if err != nil {
   107  		t.Fatal(err)
   108  	}
   109  	if len(ah.Hosts) != 1 {
   110  		t.Fatal(len(ah.Hosts))
   111  	}
   112  }
   113  
   114  // TestHostDBHostsAllHandler checks that announcing a host adds it to the list
   115  // of all hosts.
   116  func TestHostDBHostsAllHandler(t *testing.T) {
   117  	if testing.Short() {
   118  		t.SkipNow()
   119  	}
   120  	st, err := createServerTester(t.Name())
   121  	if err != nil {
   122  		t.Fatal(err)
   123  	}
   124  	defer st.server.panicClose()
   125  
   126  	// Try the call before any hosts have been declared.
   127  	var ah HostdbAllGET
   128  	if err = st.getAPI("/hostdb/all", &ah); err != nil {
   129  		t.Fatal(err)
   130  	}
   131  	if len(ah.Hosts) != 0 {
   132  		t.Fatalf("expected 0 hosts, got %v", len(ah.Hosts))
   133  	}
   134  	// Announce the host and try the call again.
   135  	if err = st.announceHost(); err != nil {
   136  		t.Fatal(err)
   137  	}
   138  	if err = st.getAPI("/hostdb/all", &ah); err != nil {
   139  		t.Fatal(err)
   140  	}
   141  	if len(ah.Hosts) != 1 {
   142  		t.Fatalf("expected 1 host, got %v", len(ah.Hosts))
   143  	}
   144  }
   145  
   146  // TestHostDBHostsHandler checks that the hosts handler is easily able to return
   147  func TestHostDBHostsHandler(t *testing.T) {
   148  	if testing.Short() {
   149  		t.SkipNow()
   150  	}
   151  	st, err := createServerTester(t.Name())
   152  	if err != nil {
   153  		t.Fatal(err)
   154  	}
   155  	defer st.server.panicClose()
   156  
   157  	// Announce the host and then get the list of hosts.
   158  	var ah HostdbActiveGET
   159  	if err = st.announceHost(); err != nil {
   160  		t.Fatal(err)
   161  	}
   162  	if err = st.getAPI("/hostdb/active", &ah); err != nil {
   163  		t.Fatal(err)
   164  	}
   165  	if len(ah.Hosts) != 1 {
   166  		t.Fatalf("expected 1 host, got %v", len(ah.Hosts))
   167  	}
   168  
   169  	// Parse the pubkey from the returned list of hosts and use it to form a
   170  	// request regarding the specific host.
   171  	keyString := ah.Hosts[0].PublicKey.String()
   172  	if keyString != ah.Hosts[0].PublicKeyString {
   173  		t.Error("actual key string and provided string do not match")
   174  	}
   175  	query := fmt.Sprintf("/hostdb/hosts/%s", ah.Hosts[0].PublicKeyString)
   176  
   177  	// Get the detailed info for the host.
   178  	var hh HostdbHostsGET
   179  	if err = st.getAPI(query, &hh); err != nil {
   180  		t.Fatal(err)
   181  	}
   182  
   183  	// Check that none of the values equal zero. A value of zero indicates that
   184  	// the field is no longer being tracked/reported, which could break
   185  	// compatibility for some apps. The default needs to be '1', not zero.
   186  	if hh.ScoreBreakdown.Score.IsZero() {
   187  		t.Error("Zero vaue score in score breakdown")
   188  	}
   189  	if hh.ScoreBreakdown.AgeAdjustment == 0 {
   190  		t.Error("Zero value in host score breakdown")
   191  	}
   192  	if hh.ScoreBreakdown.BurnAdjustment == 0 {
   193  		t.Error("Zero value in host score breakdown")
   194  	}
   195  	if hh.ScoreBreakdown.CollateralAdjustment == 0 {
   196  		t.Error("Zero value in host score breakdown")
   197  	}
   198  	if hh.ScoreBreakdown.PriceAdjustment == 0 {
   199  		t.Error("Zero value in host score breakdown")
   200  	}
   201  	if hh.ScoreBreakdown.StorageRemainingAdjustment == 0 {
   202  		t.Error("Zero value in host score breakdown")
   203  	}
   204  	if hh.ScoreBreakdown.UptimeAdjustment == 0 {
   205  		t.Error("Zero value in host score breakdown")
   206  	}
   207  	if hh.ScoreBreakdown.VersionAdjustment == 0 {
   208  		t.Error("Zero value in host score breakdown")
   209  	}
   210  
   211  	// Check that none of the supported values equals 1. A value of 1 indicates
   212  	// that the hostdb is not performing any penalties or rewards for that
   213  	// field, meaning that the calibration for that field is probably incorrect.
   214  	if hh.ScoreBreakdown.AgeAdjustment == 1 {
   215  		t.Error("One value in host score breakdown")
   216  	}
   217  	// Burn adjustment is not yet supported.
   218  	//
   219  	// if hh.ScoreBreakdown.BurnAdjustment == 1 {
   220  	//	t.Error("One value in host score breakdown")
   221  	// }
   222  	if hh.ScoreBreakdown.CollateralAdjustment == 1 {
   223  		t.Error("One value in host score breakdown")
   224  	}
   225  	if hh.ScoreBreakdown.PriceAdjustment == 1 {
   226  		t.Error("One value in host score breakdown")
   227  	}
   228  	if hh.ScoreBreakdown.StorageRemainingAdjustment == 1 {
   229  		t.Error("One value in host score breakdown")
   230  	}
   231  	if hh.ScoreBreakdown.UptimeAdjustment == 1 {
   232  		t.Error("One value in host score breakdown")
   233  	}
   234  	if hh.ScoreBreakdown.VersionAdjustment == 1 {
   235  		t.Error("One value in host score breakdown")
   236  	}
   237  }
   238  
   239  // assembleHostHostname is assembleServerTester but you can specify which
   240  // hostname the host should use.
   241  func assembleHostPort(key crypto.TwofishKey, hostHostname string, testdir string) (*serverTester, error) {
   242  	// assembleServerTester should not get called during short tests, as it
   243  	// takes a long time to run.
   244  	if testing.Short() {
   245  		panic("assembleServerTester called during short tests")
   246  	}
   247  
   248  	// Create the modules.
   249  	g, err := gateway.New("localhost:0", false, filepath.Join(testdir, modules.GatewayDir))
   250  	if err != nil {
   251  		return nil, err
   252  	}
   253  	cs, err := consensus.New(g, false, filepath.Join(testdir, modules.ConsensusDir))
   254  	if err != nil {
   255  		return nil, err
   256  	}
   257  	tp, err := transactionpool.New(cs, g, filepath.Join(testdir, modules.TransactionPoolDir))
   258  	if err != nil {
   259  		return nil, err
   260  	}
   261  	w, err := wallet.New(cs, tp, filepath.Join(testdir, modules.WalletDir))
   262  	if err != nil {
   263  		return nil, err
   264  	}
   265  	if !w.Encrypted() {
   266  		_, err = w.Encrypt(key)
   267  		if err != nil {
   268  			return nil, err
   269  		}
   270  	}
   271  	err = w.Unlock(key)
   272  	if err != nil {
   273  		return nil, err
   274  	}
   275  	m, err := miner.New(cs, tp, w, filepath.Join(testdir, modules.MinerDir))
   276  	if err != nil {
   277  		return nil, err
   278  	}
   279  	h, err := host.New(cs, tp, w, hostHostname, filepath.Join(testdir, modules.HostDir))
   280  	if err != nil {
   281  		return nil, err
   282  	}
   283  	r, err := renter.New(g, cs, w, tp, filepath.Join(testdir, modules.RenterDir))
   284  	if err != nil {
   285  		return nil, err
   286  	}
   287  	srv, err := NewServer("localhost:0", "Sia-Agent", "", cs, nil, g, h, m, r, tp, w)
   288  	if err != nil {
   289  		return nil, err
   290  	}
   291  
   292  	// Assemble the serverTester.
   293  	st := &serverTester{
   294  		cs:        cs,
   295  		gateway:   g,
   296  		host:      h,
   297  		miner:     m,
   298  		renter:    r,
   299  		tpool:     tp,
   300  		wallet:    w,
   301  		walletKey: key,
   302  
   303  		server: srv,
   304  
   305  		dir: testdir,
   306  	}
   307  
   308  	// TODO: A more reasonable way of listening for server errors.
   309  	go func() {
   310  		listenErr := srv.Serve()
   311  		if listenErr != nil {
   312  			panic(listenErr)
   313  		}
   314  	}()
   315  	return st, nil
   316  }
   317  
   318  // TestHostDBScanOnlineOffline checks that both online and offline hosts get
   319  // scanned in the hostdb.
   320  func TestHostDBScanOnlineOffline(t *testing.T) {
   321  	if testing.Short() || !build.VLONG {
   322  		t.SkipNow()
   323  	}
   324  	t.Parallel()
   325  	st, err := createServerTester(t.Name())
   326  	if err != nil {
   327  		t.Fatal(err)
   328  	}
   329  	defer st.panicClose()
   330  	stHost, err := blankServerTester(t.Name() + "-Host")
   331  	if err != nil {
   332  		t.Fatal(err)
   333  	}
   334  	sts := []*serverTester{st, stHost}
   335  	err = fullyConnectNodes(sts)
   336  	if err != nil {
   337  		t.Fatal(err)
   338  	}
   339  	err = fundAllNodes(sts)
   340  	if err != nil {
   341  		t.Fatal(err)
   342  	}
   343  
   344  	// Announce the host.
   345  	err = stHost.acceptContracts()
   346  	if err != nil {
   347  		t.Fatal(err)
   348  	}
   349  	err = stHost.setHostStorage()
   350  	if err != nil {
   351  		t.Fatal(err)
   352  	}
   353  	err = stHost.announceHost()
   354  	if err != nil {
   355  		t.Fatal(err)
   356  	}
   357  
   358  	// Verify the host is visible.
   359  	var ah HostdbActiveGET
   360  	for i := 0; i < 50; i++ {
   361  		if err = st.getAPI("/hostdb/active", &ah); err != nil {
   362  			t.Fatal(err)
   363  		}
   364  		if len(ah.Hosts) == 1 {
   365  			break
   366  		}
   367  		time.Sleep(time.Millisecond * 100)
   368  	}
   369  	if len(ah.Hosts) != 1 {
   370  		t.Fatalf("expected 1 host, got %v", len(ah.Hosts))
   371  	}
   372  	hostAddr := ah.Hosts[0].NetAddress
   373  
   374  	// Close the host and wait for a scan to knock the host out of the hostdb.
   375  	err = stHost.server.Close()
   376  	if err != nil {
   377  		t.Fatal(err)
   378  	}
   379  	err = retry(60, time.Second, func() error {
   380  		if err := st.getAPI("/hostdb/active", &ah); err != nil {
   381  			return err
   382  		}
   383  		if len(ah.Hosts) == 0 {
   384  			return nil
   385  		}
   386  		return errors.New("host still in hostdb")
   387  	})
   388  	if err != nil {
   389  		t.Fatal(err)
   390  	}
   391  
   392  	// Reopen the host and wait for a scan to bring the host back into the
   393  	// hostdb.
   394  	stHost, err = assembleHostPort(stHost.walletKey, string(hostAddr), stHost.dir)
   395  	if err != nil {
   396  		t.Fatal(err)
   397  	}
   398  	defer stHost.panicClose()
   399  	sts[1] = stHost
   400  	err = fullyConnectNodes(sts)
   401  	if err != nil {
   402  		t.Fatal(err)
   403  	}
   404  	err = retry(60, time.Second, func() error {
   405  		// Get the hostdb internals.
   406  		if err = st.getAPI("/hostdb/active", &ah); err != nil {
   407  			return err
   408  		}
   409  		if len(ah.Hosts) != 1 {
   410  			return fmt.Errorf("expected 1 host, got %v", len(ah.Hosts))
   411  		}
   412  		return nil
   413  	})
   414  	if err != nil {
   415  		t.Fatal(err)
   416  	}
   417  }
   418  
   419  // TestHostDBAndRenterDownloadDynamicIPs checks that the hostdb and the renter are
   420  // successfully able to follow a host that has changed IP addresses and then
   421  // re-announced.
   422  func TestHostDBAndRenterDownloadDynamicIPs(t *testing.T) {
   423  	if testing.Short() || !build.VLONG {
   424  		t.SkipNow()
   425  	}
   426  	t.Parallel()
   427  	st, err := createServerTester(t.Name())
   428  	if err != nil {
   429  		t.Fatal(err)
   430  	}
   431  	defer st.panicClose()
   432  	stHost, err := blankServerTester(t.Name() + "-Host")
   433  	if err != nil {
   434  		t.Fatal(err)
   435  	}
   436  	sts := []*serverTester{st, stHost}
   437  	err = fullyConnectNodes(sts)
   438  	if err != nil {
   439  		t.Fatal(err)
   440  	}
   441  	err = fundAllNodes(sts)
   442  	if err != nil {
   443  		t.Fatal(err)
   444  	}
   445  
   446  	// Announce the host.
   447  	err = stHost.acceptContracts()
   448  	if err != nil {
   449  		t.Fatal(err)
   450  	}
   451  	err = stHost.setHostStorage()
   452  	if err != nil {
   453  		t.Fatal(err)
   454  	}
   455  	err = stHost.announceHost()
   456  	if err != nil {
   457  		t.Fatal(err)
   458  	}
   459  
   460  	// Pull the host's net address and pubkey from the hostdb.
   461  	var ah HostdbActiveGET
   462  	for i := 0; i < 50; i++ {
   463  		if err = st.getAPI("/hostdb/active", &ah); err != nil {
   464  			t.Fatal(err)
   465  		}
   466  		if len(ah.Hosts) == 1 {
   467  			break
   468  		}
   469  		time.Sleep(time.Millisecond * 100)
   470  	}
   471  	if len(ah.Hosts) != 1 {
   472  		t.Fatalf("expected 1 host, got %v", len(ah.Hosts))
   473  	}
   474  	addr := ah.Hosts[0].NetAddress
   475  	pks := ah.Hosts[0].PublicKeyString
   476  
   477  	// Upload a file to the host.
   478  	allowanceValues := url.Values{}
   479  	testFunds := "10000000000000000000000000000" // 10k SC
   480  	testPeriod := "10"
   481  	testPeriodInt := 10
   482  	allowanceValues.Set("funds", testFunds)
   483  	allowanceValues.Set("period", testPeriod)
   484  	err = st.stdPostAPI("/renter", allowanceValues)
   485  	if err != nil {
   486  		t.Fatal(err)
   487  	}
   488  	// Create a file.
   489  	path := filepath.Join(st.dir, "test.dat")
   490  	err = createRandFile(path, 1024)
   491  	if err != nil {
   492  		t.Fatal(err)
   493  	}
   494  	// Upload the file to the renter.
   495  	uploadValues := url.Values{}
   496  	uploadValues.Set("source", path)
   497  	err = st.stdPostAPI("/renter/upload/test", uploadValues)
   498  	if err != nil {
   499  		t.Fatal(err)
   500  	}
   501  	// Only one piece will be uploaded (10% at current redundancy).
   502  	var rf RenterFiles
   503  	for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10); i++ {
   504  		st.getAPI("/renter/files", &rf)
   505  		time.Sleep(100 * time.Millisecond)
   506  	}
   507  	if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10 {
   508  		t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0])
   509  	}
   510  
   511  	// Try downloading the file.
   512  	downpath := filepath.Join(st.dir, "testdown.dat")
   513  	err = st.stdGetAPI("/renter/download/test?destination=" + downpath)
   514  	if err != nil {
   515  		t.Fatal(err)
   516  	}
   517  	// Check that the download has the right contents.
   518  	orig, err := ioutil.ReadFile(path)
   519  	if err != nil {
   520  		t.Fatal(err)
   521  	}
   522  	download, err := ioutil.ReadFile(downpath)
   523  	if err != nil {
   524  		t.Fatal(err)
   525  	}
   526  	if !bytes.Equal(orig, download) {
   527  		t.Fatal("data mismatch when downloading a file")
   528  	}
   529  
   530  	// Mine a block before resetting the host, so that the host doesn't lose
   531  	// it's contracts when the transaction pool resets.
   532  	_, err = st.miner.AddBlock()
   533  	if err != nil {
   534  		t.Fatal(err)
   535  	}
   536  	_, err = synchronizationCheck(sts)
   537  	if err != nil {
   538  		t.Fatal(err)
   539  	}
   540  	// Give time for the upgrade to happen.
   541  	time.Sleep(time.Second * 3)
   542  
   543  	// Close and re-open the host. This should reset the host's address, as the
   544  	// host should now be on a new port.
   545  	err = stHost.server.Close()
   546  	if err != nil {
   547  		t.Fatal(err)
   548  	}
   549  	stHost, err = assembleServerTester(stHost.walletKey, stHost.dir)
   550  	if err != nil {
   551  		t.Fatal(err)
   552  	}
   553  	defer stHost.panicClose()
   554  	sts[1] = stHost
   555  	err = fullyConnectNodes(sts)
   556  	if err != nil {
   557  		t.Fatal(err)
   558  	}
   559  	err = stHost.announceHost()
   560  	if err != nil {
   561  		t.Fatal(err)
   562  	}
   563  	// Pull the host's net address and pubkey from the hostdb.
   564  	err = retry(100, time.Millisecond*200, func() error {
   565  		// Get the hostdb internals.
   566  		if err = st.getAPI("/hostdb/active", &ah); err != nil {
   567  			return err
   568  		}
   569  
   570  		// Get the host's internals.
   571  		var hg HostGET
   572  		if err = stHost.getAPI("/host", &hg); err != nil {
   573  			return err
   574  		}
   575  
   576  		if len(ah.Hosts) != 1 {
   577  			return fmt.Errorf("expected 1 host, got %v", len(ah.Hosts))
   578  		}
   579  		if ah.Hosts[0].NetAddress != hg.ExternalSettings.NetAddress {
   580  			return fmt.Errorf("hostdb net address doesn't match host net address: %v : %v", ah.Hosts[0].NetAddress, hg.ExternalSettings.NetAddress)
   581  		}
   582  		return nil
   583  	})
   584  	if err != nil {
   585  		t.Fatal(err)
   586  	}
   587  	if ah.Hosts[0].PublicKeyString != pks {
   588  		t.Error("public key appears to have changed for host")
   589  	}
   590  	if ah.Hosts[0].NetAddress == addr {
   591  		t.Log("NetAddress did not change for the new host")
   592  	}
   593  
   594  	// Try downloading the file.
   595  	err = st.stdGetAPI("/renter/download/test?destination=" + downpath)
   596  	if err != nil {
   597  		t.Fatal(err)
   598  	}
   599  	// Check that the download has the right contents.
   600  	download, err = ioutil.ReadFile(downpath)
   601  	if err != nil {
   602  		t.Fatal(err)
   603  	}
   604  	if !bytes.Equal(orig, download) {
   605  		t.Fatal("data mismatch when downloading a file")
   606  	}
   607  
   608  	// Mine enough blocks that multiple renew cylces happen. After the renewing
   609  	// happens, the file should still be downloadable. This is to check that the
   610  	// renewal doesn't throw things off.
   611  	for i := 0; i < testPeriodInt; i++ {
   612  		_, err = st.miner.AddBlock()
   613  		if err != nil {
   614  			t.Fatal(err)
   615  		}
   616  		_, err = synchronizationCheck(sts)
   617  		if err != nil {
   618  			t.Fatal(err)
   619  		}
   620  	}
   621  	err = retry(100, time.Millisecond*100, func() error {
   622  		err = st.stdGetAPI("/renter/download/test?destination=" + downpath)
   623  		if err != nil {
   624  			return err
   625  		}
   626  		// Try downloading the file.
   627  		// Check that the download has the right contents.
   628  		download, err = ioutil.ReadFile(downpath)
   629  		if err != nil {
   630  			return err
   631  		}
   632  		if !bytes.Equal(orig, download) {
   633  			return errors.New("downloaded file does not equal the original")
   634  		}
   635  		return nil
   636  	})
   637  	if err != nil {
   638  		t.Fatal(err)
   639  	}
   640  }
   641  
   642  // TestHostDBAndRenterUploadDynamicIPs checks that the hostdb and the renter are
   643  // successfully able to follow a host that has changed IP addresses and then
   644  // re-announced.
   645  func TestHostDBAndRenterUploadDynamicIPs(t *testing.T) {
   646  	if testing.Short() || !build.VLONG {
   647  		t.SkipNow()
   648  	}
   649  	t.Parallel()
   650  	st, err := createServerTester(t.Name())
   651  	if err != nil {
   652  		t.Fatal(err)
   653  	}
   654  	defer st.panicClose()
   655  	stHost, err := blankServerTester(t.Name() + "-Host")
   656  	if err != nil {
   657  		t.Fatal(err)
   658  	}
   659  	sts := []*serverTester{st, stHost}
   660  	err = fullyConnectNodes(sts)
   661  	if err != nil {
   662  		t.Fatal(err)
   663  	}
   664  	err = fundAllNodes(sts)
   665  	if err != nil {
   666  		t.Fatal(err)
   667  	}
   668  
   669  	// Announce the host.
   670  	err = stHost.acceptContracts()
   671  	if err != nil {
   672  		t.Fatal(err)
   673  	}
   674  	err = stHost.setHostStorage()
   675  	if err != nil {
   676  		t.Fatal(err)
   677  	}
   678  	err = stHost.announceHost()
   679  	if err != nil {
   680  		t.Fatal(err)
   681  	}
   682  
   683  	// Pull the host's net address and pubkey from the hostdb.
   684  	var ah HostdbActiveGET
   685  	for i := 0; i < 50; i++ {
   686  		if err = st.getAPI("/hostdb/active", &ah); err != nil {
   687  			t.Fatal(err)
   688  		}
   689  		if len(ah.Hosts) == 1 {
   690  			break
   691  		}
   692  		time.Sleep(time.Millisecond * 100)
   693  	}
   694  	if len(ah.Hosts) != 1 {
   695  		t.Fatalf("expected 1 host, got %v", len(ah.Hosts))
   696  	}
   697  	addr := ah.Hosts[0].NetAddress
   698  	pks := ah.Hosts[0].PublicKeyString
   699  
   700  	// Upload a file to the host.
   701  	allowanceValues := url.Values{}
   702  	testFunds := "10000000000000000000000000000" // 10k SC
   703  	testPeriod := "10"
   704  	testPeriodInt := 10
   705  	allowanceValues.Set("funds", testFunds)
   706  	allowanceValues.Set("period", testPeriod)
   707  	err = st.stdPostAPI("/renter", allowanceValues)
   708  	if err != nil {
   709  		t.Fatal(err)
   710  	}
   711  	// Create a file.
   712  	path := filepath.Join(st.dir, "test.dat")
   713  	err = createRandFile(path, 1024)
   714  	if err != nil {
   715  		t.Fatal(err)
   716  	}
   717  	// Upload the file to the renter.
   718  	uploadValues := url.Values{}
   719  	uploadValues.Set("source", path)
   720  	err = st.stdPostAPI("/renter/upload/test", uploadValues)
   721  	if err != nil {
   722  		t.Fatal(err)
   723  	}
   724  	// Only one piece will be uploaded (10% at current redundancy).
   725  	var rf RenterFiles
   726  	for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10); i++ {
   727  		st.getAPI("/renter/files", &rf)
   728  		time.Sleep(100 * time.Millisecond)
   729  	}
   730  	if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10 {
   731  		t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0])
   732  	}
   733  
   734  	// Mine a block before resetting the host, so that the host doesn't lose
   735  	// it's contracts when the transaction pool resets.
   736  	_, err = st.miner.AddBlock()
   737  	if err != nil {
   738  		t.Fatal(err)
   739  	}
   740  	_, err = synchronizationCheck(sts)
   741  	if err != nil {
   742  		t.Fatal(err)
   743  	}
   744  	// Give time for the upgrade to happen.
   745  	time.Sleep(time.Second * 3)
   746  
   747  	// Close and re-open the host. This should reset the host's address, as the
   748  	// host should now be on a new port.
   749  	err = stHost.server.Close()
   750  	if err != nil {
   751  		t.Fatal(err)
   752  	}
   753  	stHost, err = assembleServerTester(stHost.walletKey, stHost.dir)
   754  	if err != nil {
   755  		t.Fatal(err)
   756  	}
   757  	defer stHost.panicClose()
   758  	sts[1] = stHost
   759  	err = fullyConnectNodes(sts)
   760  	if err != nil {
   761  		t.Fatal(err)
   762  	}
   763  	err = stHost.announceHost()
   764  	if err != nil {
   765  		t.Fatal(err)
   766  	}
   767  	// Pull the host's net address and pubkey from the hostdb.
   768  	err = retry(50, time.Millisecond*100, func() error {
   769  		// Get the hostdb internals.
   770  		if err = st.getAPI("/hostdb/active", &ah); err != nil {
   771  			return err
   772  		}
   773  
   774  		// Get the host's internals.
   775  		var hg HostGET
   776  		if err = stHost.getAPI("/host", &hg); err != nil {
   777  			return err
   778  		}
   779  
   780  		if len(ah.Hosts) != 1 {
   781  			return fmt.Errorf("expected 1 host, got %v", len(ah.Hosts))
   782  		}
   783  		if ah.Hosts[0].NetAddress != hg.ExternalSettings.NetAddress {
   784  			return fmt.Errorf("hostdb net address doesn't match host net address: %v : %v", ah.Hosts[0].NetAddress, hg.ExternalSettings.NetAddress)
   785  		}
   786  		return nil
   787  	})
   788  	if err != nil {
   789  		t.Fatal(err)
   790  	}
   791  	if ah.Hosts[0].PublicKeyString != pks {
   792  		t.Error("public key appears to have changed for host")
   793  	}
   794  	if ah.Hosts[0].NetAddress == addr {
   795  		t.Log("NetAddress did not change for the new host")
   796  	}
   797  
   798  	// Try uploading a second file.
   799  	path2 := filepath.Join(st.dir, "test2.dat")
   800  	test2Size := modules.SectorSize*2 + 1
   801  	err = createRandFile(path2, int(test2Size))
   802  	if err != nil {
   803  		t.Fatal(err)
   804  	}
   805  	uploadValues = url.Values{}
   806  	uploadValues.Set("source", path2)
   807  	err = st.stdPostAPI("/renter/upload/test2", uploadValues)
   808  	if err != nil {
   809  		t.Fatal(err)
   810  	}
   811  	// Only one piece will be uploaded (10% at current redundancy).
   812  	for i := 0; i < 200 && (len(rf.Files) != 2 || rf.Files[0].UploadProgress < 10 || rf.Files[1].UploadProgress < 10); i++ {
   813  		st.getAPI("/renter/files", &rf)
   814  		time.Sleep(100 * time.Millisecond)
   815  	}
   816  	if len(rf.Files) != 2 || rf.Files[0].UploadProgress < 10 || rf.Files[1].UploadProgress < 10 {
   817  		t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0], rf.Files[1])
   818  	}
   819  
   820  	// Try downloading the second file.
   821  	downpath2 := filepath.Join(st.dir, "testdown2.dat")
   822  	err = st.stdGetAPI("/renter/download/test2?destination=" + downpath2)
   823  	if err != nil {
   824  		t.Fatal(err)
   825  	}
   826  	// Check that the download has the right contents.
   827  	orig2, err := ioutil.ReadFile(path2)
   828  	if err != nil {
   829  		t.Fatal(err)
   830  	}
   831  	download2, err := ioutil.ReadFile(downpath2)
   832  	if err != nil {
   833  		t.Fatal(err)
   834  	}
   835  	if !bytes.Equal(orig2, download2) {
   836  		t.Fatal("data mismatch when downloading a file")
   837  	}
   838  
   839  	// Mine enough blocks that multiple renew cylces happen. After the renewing
   840  	// happens, the file should still be downloadable. This is to check that the
   841  	// renewal doesn't throw things off.
   842  	for i := 0; i < testPeriodInt; i++ {
   843  		_, err = st.miner.AddBlock()
   844  		if err != nil {
   845  			t.Fatal(err)
   846  		}
   847  		_, err = synchronizationCheck(sts)
   848  		if err != nil {
   849  			t.Fatal(err)
   850  		}
   851  		// Give time for the upgrade to happen.
   852  		time.Sleep(time.Second * 3)
   853  	}
   854  
   855  	// Try downloading the file.
   856  	downpath := filepath.Join(st.dir, "testdown.dat")
   857  	err = st.stdGetAPI("/renter/download/test?destination=" + downpath)
   858  	if err != nil {
   859  		t.Fatal(err)
   860  	}
   861  	// Check that the download has the right contents.
   862  	download, err := ioutil.ReadFile(downpath)
   863  	if err != nil {
   864  		t.Fatal(err)
   865  	}
   866  	orig, err := ioutil.ReadFile(path)
   867  	if err != nil {
   868  		t.Fatal(err)
   869  	}
   870  	if !bytes.Equal(orig, download) {
   871  		t.Fatal("data mismatch when downloading a file")
   872  	}
   873  
   874  	// Try downloading the second file.
   875  	err = st.stdGetAPI("/renter/download/test2?destination=" + downpath2)
   876  	if err != nil {
   877  		t.Fatal(err)
   878  	}
   879  	// Check that the download has the right contents.
   880  	orig2, err = ioutil.ReadFile(path2)
   881  	if err != nil {
   882  		t.Fatal(err)
   883  	}
   884  	download2, err = ioutil.ReadFile(downpath2)
   885  	if err != nil {
   886  		t.Fatal(err)
   887  	}
   888  	if !bytes.Equal(orig2, download2) {
   889  		t.Fatal("data mismatch when downloading a file")
   890  	}
   891  }
   892  
   893  // TestHostDBAndRenterFormDynamicIPs checks that the hostdb and the renter are
   894  // successfully able to follow a host that has changed IP addresses and then
   895  // re-announced.
   896  func TestHostDBAndRenterFormDynamicIPs(t *testing.T) {
   897  	if testing.Short() || !build.VLONG {
   898  		t.SkipNow()
   899  	}
   900  	t.Parallel()
   901  	st, err := createServerTester(t.Name())
   902  	if err != nil {
   903  		t.Fatal(err)
   904  	}
   905  	defer st.panicClose()
   906  	stHost, err := blankServerTester(t.Name() + "-Host")
   907  	if err != nil {
   908  		t.Fatal(err)
   909  	}
   910  	sts := []*serverTester{st, stHost}
   911  	err = fullyConnectNodes(sts)
   912  	if err != nil {
   913  		t.Fatal(err)
   914  	}
   915  	err = fundAllNodes(sts)
   916  	if err != nil {
   917  		t.Fatal(err)
   918  	}
   919  
   920  	// Announce the host.
   921  	err = stHost.acceptContracts()
   922  	if err != nil {
   923  		t.Fatal(err)
   924  	}
   925  	err = stHost.setHostStorage()
   926  	if err != nil {
   927  		t.Fatal(err)
   928  	}
   929  	err = stHost.announceHost()
   930  	if err != nil {
   931  		t.Fatal(err)
   932  	}
   933  
   934  	// Pull the host's net address and pubkey from the hostdb.
   935  	var ah HostdbActiveGET
   936  	for i := 0; i < 50; i++ {
   937  		if err = st.getAPI("/hostdb/active", &ah); err != nil {
   938  			t.Fatal(err)
   939  		}
   940  		if len(ah.Hosts) == 1 {
   941  			break
   942  		}
   943  		time.Sleep(time.Millisecond * 100)
   944  	}
   945  	if len(ah.Hosts) != 1 {
   946  		t.Fatalf("expected 1 host, got %v", len(ah.Hosts))
   947  	}
   948  	addr := ah.Hosts[0].NetAddress
   949  	pks := ah.Hosts[0].PublicKeyString
   950  
   951  	// Mine a block before resetting the host, so that the host doesn't lose
   952  	// it's contracts when the transaction pool resets.
   953  	_, err = st.miner.AddBlock()
   954  	if err != nil {
   955  		t.Fatal(err)
   956  	}
   957  	_, err = synchronizationCheck(sts)
   958  	if err != nil {
   959  		t.Fatal(err)
   960  	}
   961  	// Give time for the upgrade to happen.
   962  	time.Sleep(time.Second * 3)
   963  
   964  	// Close and re-open the host. This should reset the host's address, as the
   965  	// host should now be on a new port.
   966  	err = stHost.server.Close()
   967  	if err != nil {
   968  		t.Fatal(err)
   969  	}
   970  	stHost, err = assembleServerTester(stHost.walletKey, stHost.dir)
   971  	if err != nil {
   972  		t.Fatal(err)
   973  	}
   974  	defer stHost.panicClose()
   975  	sts[1] = stHost
   976  	err = fullyConnectNodes(sts)
   977  	if err != nil {
   978  		t.Fatal(err)
   979  	}
   980  	err = stHost.announceHost()
   981  	if err != nil {
   982  		t.Fatal(err)
   983  	}
   984  	// Pull the host's net address and pubkey from the hostdb.
   985  	err = retry(50, time.Millisecond*100, func() error {
   986  		// Get the hostdb internals.
   987  		if err = st.getAPI("/hostdb/active", &ah); err != nil {
   988  			return err
   989  		}
   990  
   991  		// Get the host's internals.
   992  		var hg HostGET
   993  		if err = stHost.getAPI("/host", &hg); err != nil {
   994  			return err
   995  		}
   996  
   997  		if len(ah.Hosts) != 1 {
   998  			return fmt.Errorf("expected 1 host, got %v", len(ah.Hosts))
   999  		}
  1000  		if ah.Hosts[0].NetAddress != hg.ExternalSettings.NetAddress {
  1001  			return fmt.Errorf("hostdb net address doesn't match host net address: %v : %v", ah.Hosts[0].NetAddress, hg.ExternalSettings.NetAddress)
  1002  		}
  1003  		return nil
  1004  	})
  1005  	if err != nil {
  1006  		t.Fatal(err)
  1007  	}
  1008  	if ah.Hosts[0].PublicKeyString != pks {
  1009  		t.Error("public key appears to have changed for host")
  1010  	}
  1011  	if ah.Hosts[0].NetAddress == addr {
  1012  		t.Log("NetAddress did not change for the new host")
  1013  	}
  1014  
  1015  	// Upload a file to the host.
  1016  	allowanceValues := url.Values{}
  1017  	testFunds := "10000000000000000000000000000" // 10k SC
  1018  	testPeriod := "10"
  1019  	testPeriodInt := 10
  1020  	allowanceValues.Set("funds", testFunds)
  1021  	allowanceValues.Set("period", testPeriod)
  1022  	err = st.stdPostAPI("/renter", allowanceValues)
  1023  	if err != nil {
  1024  		t.Fatal(err)
  1025  	}
  1026  	// Create a file.
  1027  	path := filepath.Join(st.dir, "test.dat")
  1028  	err = createRandFile(path, 1024)
  1029  	if err != nil {
  1030  		t.Fatal(err)
  1031  	}
  1032  	// Upload the file to the renter.
  1033  	uploadValues := url.Values{}
  1034  	uploadValues.Set("source", path)
  1035  	err = st.stdPostAPI("/renter/upload/test", uploadValues)
  1036  	if err != nil {
  1037  		t.Fatal(err)
  1038  	}
  1039  	// Only one piece will be uploaded (10% at current redundancy).
  1040  	var rf RenterFiles
  1041  	for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10); i++ {
  1042  		st.getAPI("/renter/files", &rf)
  1043  		time.Sleep(100 * time.Millisecond)
  1044  	}
  1045  	if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10 {
  1046  		t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0])
  1047  	}
  1048  
  1049  	// Try downloading the file.
  1050  	downpath := filepath.Join(st.dir, "testdown.dat")
  1051  	err = st.stdGetAPI("/renter/download/test?destination=" + downpath)
  1052  	if err != nil {
  1053  		t.Fatal(err)
  1054  	}
  1055  	// Check that the download has the right contents.
  1056  	orig, err := ioutil.ReadFile(path)
  1057  	if err != nil {
  1058  		t.Fatal(err)
  1059  	}
  1060  	download, err := ioutil.ReadFile(downpath)
  1061  	if err != nil {
  1062  		t.Fatal(err)
  1063  	}
  1064  	if !bytes.Equal(orig, download) {
  1065  		t.Fatal("data mismatch when downloading a file")
  1066  	}
  1067  
  1068  	// Mine enough blocks that multiple renew cylces happen. After the renewing
  1069  	// happens, the file should still be downloadable. This is to check that the
  1070  	// renewal doesn't throw things off.
  1071  	for i := 0; i < testPeriodInt; i++ {
  1072  		_, err = st.miner.AddBlock()
  1073  		if err != nil {
  1074  			t.Fatal(err)
  1075  		}
  1076  		_, err = synchronizationCheck(sts)
  1077  		if err != nil {
  1078  			t.Fatal(err)
  1079  		}
  1080  		// Give time for the upgrade to happen.
  1081  		time.Sleep(time.Second * 3)
  1082  	}
  1083  
  1084  	// Try downloading the file.
  1085  	err = st.stdGetAPI("/renter/download/test?destination=" + downpath)
  1086  	if err != nil {
  1087  		t.Fatal(err)
  1088  	}
  1089  	// Check that the download has the right contents.
  1090  	download, err = ioutil.ReadFile(downpath)
  1091  	if err != nil {
  1092  		t.Fatal(err)
  1093  	}
  1094  	if !bytes.Equal(orig, download) {
  1095  		t.Fatal("data mismatch when downloading a file")
  1096  	}
  1097  }
  1098  
  1099  // TestHostDBAndRenterRenewDynamicIPs checks that the hostdb and the renter are
  1100  // successfully able to follow a host that has changed IP addresses and then
  1101  // re-announced.
  1102  func TestHostDBAndRenterRenewDynamicIPs(t *testing.T) {
  1103  	if testing.Short() || !build.VLONG {
  1104  		t.SkipNow()
  1105  	}
  1106  	t.Parallel()
  1107  	st, err := createServerTester(t.Name())
  1108  	if err != nil {
  1109  		t.Fatal(err)
  1110  	}
  1111  	defer st.panicClose()
  1112  	stHost, err := blankServerTester(t.Name() + "-Host")
  1113  	if err != nil {
  1114  		t.Fatal(err)
  1115  	}
  1116  	sts := []*serverTester{st, stHost}
  1117  	err = fullyConnectNodes(sts)
  1118  	if err != nil {
  1119  		t.Fatal(err)
  1120  	}
  1121  	err = fundAllNodes(sts)
  1122  	if err != nil {
  1123  		t.Fatal(err)
  1124  	}
  1125  
  1126  	// Announce the host.
  1127  	err = stHost.acceptContracts()
  1128  	if err != nil {
  1129  		t.Fatal(err)
  1130  	}
  1131  	err = stHost.setHostStorage()
  1132  	if err != nil {
  1133  		t.Fatal(err)
  1134  	}
  1135  	err = stHost.announceHost()
  1136  	if err != nil {
  1137  		t.Fatal(err)
  1138  	}
  1139  	var ah HostdbActiveGET
  1140  	err = retry(50, 100*time.Millisecond, func() error {
  1141  		if err := st.getAPI("/hostdb/active", &ah); err != nil {
  1142  			return err
  1143  		}
  1144  		if len(ah.Hosts) != 1 {
  1145  			return errors.New("host not found in hostdb")
  1146  		}
  1147  		return nil
  1148  	})
  1149  
  1150  	// Upload a file to the host.
  1151  	allowanceValues := url.Values{}
  1152  	testFunds := "10000000000000000000000000000" // 10k SC
  1153  	testPeriod := "10"
  1154  	testPeriodInt := 10
  1155  	allowanceValues.Set("funds", testFunds)
  1156  	allowanceValues.Set("period", testPeriod)
  1157  	err = st.stdPostAPI("/renter", allowanceValues)
  1158  	if err != nil {
  1159  		t.Fatal(err)
  1160  	}
  1161  	// Create a file.
  1162  	path := filepath.Join(st.dir, "test.dat")
  1163  	err = createRandFile(path, 1024)
  1164  	if err != nil {
  1165  		t.Fatal(err)
  1166  	}
  1167  	// Upload the file to the renter.
  1168  	uploadValues := url.Values{}
  1169  	uploadValues.Set("source", path)
  1170  	err = st.stdPostAPI("/renter/upload/test", uploadValues)
  1171  	if err != nil {
  1172  		t.Fatal(err)
  1173  	}
  1174  	// Only one piece will be uploaded (10% at current redundancy).
  1175  	var rf RenterFiles
  1176  	for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10); i++ {
  1177  		st.getAPI("/renter/files", &rf)
  1178  		time.Sleep(100 * time.Millisecond)
  1179  	}
  1180  	if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10 {
  1181  		t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0])
  1182  	}
  1183  
  1184  	// Try downloading the file.
  1185  	downpath := filepath.Join(st.dir, "testdown.dat")
  1186  	err = st.stdGetAPI("/renter/download/test?destination=" + downpath)
  1187  	if err != nil {
  1188  		t.Fatal(err)
  1189  	}
  1190  	// Check that the download has the right contents.
  1191  	orig, err := ioutil.ReadFile(path)
  1192  	if err != nil {
  1193  		t.Fatal(err)
  1194  	}
  1195  	download, err := ioutil.ReadFile(downpath)
  1196  	if err != nil {
  1197  		t.Fatal(err)
  1198  	}
  1199  	if !bytes.Equal(orig, download) {
  1200  		t.Fatal("data mismatch when downloading a file")
  1201  	}
  1202  
  1203  	// Mine a block before resetting the host, so that the host doesn't lose
  1204  	// it's contracts when the transaction pool resets.
  1205  	_, err = st.miner.AddBlock()
  1206  	if err != nil {
  1207  		t.Fatal(err)
  1208  	}
  1209  	_, err = synchronizationCheck(sts)
  1210  	if err != nil {
  1211  		t.Fatal(err)
  1212  	}
  1213  	// Give time for the upgrade to happen.
  1214  	time.Sleep(time.Second * 3)
  1215  
  1216  	// Close and re-open the host. This should reset the host's address, as the
  1217  	// host should now be on a new port.
  1218  	err = stHost.server.Close()
  1219  	if err != nil {
  1220  		t.Fatal(err)
  1221  	}
  1222  	stHost, err = assembleServerTester(stHost.walletKey, stHost.dir)
  1223  	if err != nil {
  1224  		t.Fatal(err)
  1225  	}
  1226  	defer stHost.panicClose()
  1227  	sts[1] = stHost
  1228  	err = fullyConnectNodes(sts)
  1229  	if err != nil {
  1230  		t.Fatal(err)
  1231  	}
  1232  	err = stHost.announceHost()
  1233  	if err != nil {
  1234  		t.Fatal(err)
  1235  	}
  1236  	err = waitForBlock(stHost.cs.CurrentBlock().ID(), st)
  1237  	if err != nil {
  1238  		t.Fatal()
  1239  	}
  1240  	// Pull the host's net address and pubkey from the hostdb.
  1241  	err = retry(50, time.Millisecond*100, func() error {
  1242  		// Get the hostdb internals.
  1243  		if err = st.getAPI("/hostdb/active", &ah); err != nil {
  1244  			return err
  1245  		}
  1246  
  1247  		// Get the host's internals.
  1248  		var hg HostGET
  1249  		if err = stHost.getAPI("/host", &hg); err != nil {
  1250  			return err
  1251  		}
  1252  
  1253  		if len(ah.Hosts) != 1 {
  1254  			return fmt.Errorf("expected 1 host, got %v", len(ah.Hosts))
  1255  		}
  1256  		if ah.Hosts[0].NetAddress != hg.ExternalSettings.NetAddress {
  1257  			return fmt.Errorf("hostdb net address doesn't match host net address: %v : %v", ah.Hosts[0].NetAddress, hg.ExternalSettings.NetAddress)
  1258  		}
  1259  		return nil
  1260  	})
  1261  	if err != nil {
  1262  		t.Fatal(err)
  1263  	}
  1264  
  1265  	// Mine enough blocks that multiple renew cylces happen. After the renewing
  1266  	// happens, the file should still be downloadable.
  1267  	for i := 0; i < testPeriodInt; i++ {
  1268  		_, err = st.miner.AddBlock()
  1269  		if err != nil {
  1270  			t.Fatal(err)
  1271  		}
  1272  		_, err = synchronizationCheck(sts)
  1273  		if err != nil {
  1274  			t.Fatal(err)
  1275  		}
  1276  		// Give time for the upgrade to happen.
  1277  		time.Sleep(time.Second * 3)
  1278  	}
  1279  
  1280  	// Try downloading the file.
  1281  	err = st.stdGetAPI("/renter/download/test?destination=" + downpath)
  1282  	if err != nil {
  1283  		t.Fatal(err)
  1284  	}
  1285  	// Check that the download has the right contents.
  1286  	download, err = ioutil.ReadFile(downpath)
  1287  	if err != nil {
  1288  		t.Fatal(err)
  1289  	}
  1290  	if !bytes.Equal(orig, download) {
  1291  		t.Fatal("data mismatch when downloading a file")
  1292  	}
  1293  }