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

     1  package api
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  	"io/ioutil"
     9  	"net/url"
    10  	"os"
    11  	"path/filepath"
    12  	"strconv"
    13  	"strings"
    14  	"testing"
    15  	"time"
    16  
    17  	"github.com/Synthesix/Sia/build"
    18  	"github.com/Synthesix/Sia/modules"
    19  	"github.com/Synthesix/Sia/modules/renter"
    20  	"github.com/Synthesix/Sia/modules/renter/contractor"
    21  	"github.com/Synthesix/Sia/types"
    22  	"github.com/NebulousLabs/fastrand"
    23  )
    24  
    25  const (
    26  	testFunds       = "10000000000000000000000000000" // 10k SC
    27  	testPeriod      = "5"
    28  	testRenewWindow = "2"
    29  )
    30  
    31  // createRandFile creates a file on disk and fills it with random bytes.
    32  func createRandFile(path string, size int) error {
    33  	return ioutil.WriteFile(path, fastrand.Bytes(size), 0600)
    34  }
    35  
    36  // setupTestDownload creates a server tester with an uploaded file of size
    37  // `size` and name `name`.
    38  func setupTestDownload(t *testing.T, size int, name string, waitOnAvailability bool) (*serverTester, string) {
    39  	st, err := createServerTester(t.Name())
    40  	if err != nil {
    41  		t.Fatal(err)
    42  	}
    43  
    44  	// Announce the host and start accepting contracts.
    45  	err = st.announceHost()
    46  	if err != nil {
    47  		t.Fatal(err)
    48  	}
    49  	err = st.acceptContracts()
    50  	if err != nil {
    51  		t.Fatal(err)
    52  	}
    53  	err = st.setHostStorage()
    54  	if err != nil {
    55  		t.Fatal(err)
    56  	}
    57  
    58  	// Set an allowance for the renter, allowing a contract to be formed.
    59  	allowanceValues := url.Values{}
    60  	testFunds := testFunds
    61  	testPeriod := "10"
    62  	renewWindow := "5"
    63  	allowanceValues.Set("funds", testFunds)
    64  	allowanceValues.Set("period", testPeriod)
    65  	allowanceValues.Set("renewwindow", renewWindow)
    66  	allowanceValues.Set("hosts", fmt.Sprint(recommendedHosts))
    67  	err = st.stdPostAPI("/renter", allowanceValues)
    68  	if err != nil {
    69  		t.Fatal(err)
    70  	}
    71  
    72  	// Create a file.
    73  	path := filepath.Join(build.SiaTestingDir, "api", t.Name(), name)
    74  	err = createRandFile(path, size)
    75  	if err != nil {
    76  		t.Fatal(err)
    77  	}
    78  
    79  	// Upload to host.
    80  	uploadValues := url.Values{}
    81  	uploadValues.Set("source", path)
    82  	uploadValues.Set("renew", "true")
    83  	uploadValues.Set("datapieces", "1")
    84  	uploadValues.Set("paritypieces", "1")
    85  	err = st.stdPostAPI("/renter/upload/"+name, uploadValues)
    86  	if err != nil {
    87  		t.Fatal(err)
    88  	}
    89  
    90  	if waitOnAvailability {
    91  		// wait for the file to become available
    92  		err = retry(200, time.Second, func() error {
    93  			var rf RenterFiles
    94  			st.getAPI("/renter/files", &rf)
    95  			if len(rf.Files) != 1 || !rf.Files[0].Available {
    96  				return fmt.Errorf("the uploading is not succeeding for some reason: %v\n", rf.Files[0])
    97  			}
    98  			return nil
    99  		})
   100  		if err != nil {
   101  			t.Fatal(err)
   102  		}
   103  	}
   104  
   105  	return st, path
   106  }
   107  
   108  // runDownloadTest uploads a file and downloads it using the specified
   109  // parameters, verifying that the parameters are applied correctly and the file
   110  // is downloaded successfully.
   111  func runDownloadTest(t *testing.T, filesize, offset, length int64, useHttpResp bool, testName string) error {
   112  	ulSiaPath := testName + ".dat"
   113  	st, path := setupTestDownload(t, int(filesize), ulSiaPath, true)
   114  	defer func() {
   115  		st.server.panicClose()
   116  		os.Remove(path)
   117  	}()
   118  
   119  	// Read the section to be downloaded from the original file.
   120  	uf, err := os.Open(path) // Uploaded file.
   121  	if err != nil {
   122  		return err
   123  	}
   124  	var originalBytes bytes.Buffer
   125  	_, err = uf.Seek(offset, 0)
   126  	if err != nil {
   127  		return err
   128  	}
   129  	_, err = io.CopyN(&originalBytes, uf, length)
   130  	if err != nil {
   131  		return err
   132  	}
   133  
   134  	// Download the original file from the passed offsets.
   135  	fname := testName + "-download.dat"
   136  	downpath := filepath.Join(st.dir, fname)
   137  	defer os.Remove(downpath)
   138  
   139  	dlURL := fmt.Sprintf("/renter/download/%s?offset=%d&length=%d", ulSiaPath, offset, length)
   140  
   141  	var downbytes bytes.Buffer
   142  
   143  	if useHttpResp {
   144  		dlURL += "&httpresp=true"
   145  		// Make request.
   146  		resp, err := HttpGET("http://" + st.server.listener.Addr().String() + dlURL)
   147  		if err != nil {
   148  			return err
   149  		}
   150  		defer resp.Body.Close()
   151  
   152  		_, err = io.Copy(&downbytes, resp.Body)
   153  		if err != nil {
   154  			return err
   155  		}
   156  	} else {
   157  		dlURL += "&destination=" + downpath
   158  		err := st.getAPI(dlURL, nil)
   159  		if err != nil {
   160  			return err
   161  		}
   162  		// wait for the download to complete
   163  		err = retry(30, time.Second, func() error {
   164  			var rdq RenterDownloadQueue
   165  			err = st.getAPI("/renter/downloads", &rdq)
   166  			if err != nil {
   167  				return err
   168  			}
   169  			for _, download := range rdq.Downloads {
   170  				if download.Received == download.Filesize && download.SiaPath == ulSiaPath {
   171  					return nil
   172  				}
   173  			}
   174  			return errors.New("file not downloaded")
   175  		})
   176  		if err != nil {
   177  			t.Fatal(err)
   178  		}
   179  
   180  		// open the downloaded file
   181  		df, err := os.Open(downpath)
   182  		if err != nil {
   183  			return err
   184  		}
   185  		defer df.Close()
   186  
   187  		_, err = io.Copy(&downbytes, df)
   188  		if err != nil {
   189  			return err
   190  		}
   191  	}
   192  
   193  	// should have correct length
   194  	if int64(downbytes.Len()) != length {
   195  		return fmt.Errorf("downloaded file has incorrect size: %d, %d expected", downbytes.Len(), length)
   196  	}
   197  
   198  	// should be byte-for-byte equal to the original uploaded file
   199  	if !bytes.Equal(originalBytes.Bytes(), downbytes.Bytes()) {
   200  		return fmt.Errorf("downloaded content differs from original content")
   201  	}
   202  
   203  	return nil
   204  }
   205  
   206  // TestRenterDownloadError tests that the /renter/download route sets the
   207  // download's error field if it fails.
   208  func TestRenterDownloadError(t *testing.T) {
   209  	if testing.Short() {
   210  		t.SkipNow()
   211  	}
   212  	t.Parallel()
   213  
   214  	st, _ := setupTestDownload(t, 1e4, "test.dat", false)
   215  	defer st.server.Close()
   216  
   217  	// don't wait for the upload to complete, try to download immediately to
   218  	// intentionally cause a download error
   219  	downpath := filepath.Join(st.dir, "down.dat")
   220  	expectedErr := st.getAPI("/renter/download/test.dat?destination="+downpath, nil)
   221  	if expectedErr == nil {
   222  		t.Fatal("download unexpectedly succeeded")
   223  	}
   224  
   225  	// verify the file has the expected error
   226  	var rdq RenterDownloadQueue
   227  	err := st.getAPI("/renter/downloads", &rdq)
   228  	if err != nil {
   229  		t.Fatal(err)
   230  	}
   231  	for _, download := range rdq.Downloads {
   232  		if download.SiaPath == "test.dat" && download.Received == download.Filesize && download.Error == expectedErr.Error() {
   233  			t.Fatal("download had unexpected error: ", download.Error)
   234  		}
   235  	}
   236  }
   237  
   238  // TestValidDownloads tests valid and boundary parameter combinations.
   239  func TestValidDownloads(t *testing.T) {
   240  	if testing.Short() {
   241  		t.SkipNow()
   242  	}
   243  	t.Parallel()
   244  
   245  	sectorSize := int64(modules.SectorSize)
   246  
   247  	testParams := []struct {
   248  		filesize,
   249  		offset,
   250  		length int64
   251  		useHttpResp bool
   252  		testName    string
   253  	}{
   254  		// file-backed tests.
   255  		{sectorSize, 40, sectorSize - 40, false, "OffsetSingleChunk"},
   256  		{sectorSize * 2, 20, sectorSize*2 - 20, false, "OffsetTwoChunk"},
   257  		{int64(float64(sectorSize) * 2.4), 20, int64(float64(sectorSize)*2.4) - 20, false, "OffsetThreeChunk"},
   258  		{sectorSize, 0, sectorSize / 2, false, "ShortLengthSingleChunk"},
   259  		{sectorSize, sectorSize / 4, sectorSize / 2, false, "ShortLengthAndOffsetSingleChunk"},
   260  		{sectorSize * 2, 0, int64(float64(sectorSize) * 2 * 0.75), false, "ShortLengthTwoChunk"},
   261  		{int64(float64(sectorSize) * 2.7), 0, int64(2.2 * float64(sectorSize)), false, "ShortLengthThreeChunkInThirdChunk"},
   262  		{int64(float64(sectorSize) * 2.7), 0, int64(1.6 * float64(sectorSize)), false, "ShortLengthThreeChunkInSecondChunk"},
   263  		{sectorSize * 5, 0, int64(float64(sectorSize*5) * 0.75), false, "ShortLengthMultiChunk"},
   264  		{sectorSize * 2, 50, int64(float64(sectorSize*2) * 0.75), false, "ShortLengthAndOffsetTwoChunk"},
   265  		{sectorSize * 3, 50, int64(float64(sectorSize*3) * 0.5), false, "ShortLengthAndOffsetThreeChunkInSecondChunk"},
   266  		{sectorSize * 3, 50, int64(float64(sectorSize*3) * 0.75), false, "ShortLengthAndOffsetThreeChunkInThirdChunk"},
   267  
   268  		// http response tests.
   269  		{sectorSize, 40, sectorSize - 40, true, "HttpRespOffsetSingleChunk"},
   270  		{sectorSize * 2, 40, sectorSize*2 - 40, true, "HttpRespOffsetTwoChunk"},
   271  		{sectorSize * 5, 40, sectorSize*5 - 40, true, "HttpRespOffsetManyChunks"},
   272  		{sectorSize, 40, 4 * sectorSize / 5, true, "RespOffsetAndLengthSingleChunk"},
   273  		{sectorSize * 2, 80, 3 * (sectorSize * 2) / 4, true, "RespOffsetAndLengthTwoChunk"},
   274  		{sectorSize * 5, 150, 3 * (sectorSize * 5) / 4, true, "HttpRespOffsetAndLengthManyChunks"},
   275  		{sectorSize * 5, 150, sectorSize * 5 / 4, true, "HttpRespOffsetAndLengthManyChunksSubsetOfChunks"},
   276  	}
   277  	for i, params := range testParams {
   278  		params := params
   279  		t.Run(fmt.Sprintf("%v-%v", t.Name(), i), func(st *testing.T) {
   280  			st.Parallel()
   281  			err := runDownloadTest(st, params.filesize, params.offset, params.length, params.useHttpResp, params.testName)
   282  			if err != nil {
   283  				st.Fatal(err)
   284  			}
   285  		})
   286  	}
   287  }
   288  
   289  func runDownloadParamTest(t *testing.T, length, offset, filesize int) error {
   290  	ulSiaPath := "test.dat"
   291  
   292  	st, _ := setupTestDownload(t, int(filesize), ulSiaPath, true)
   293  	defer st.server.Close()
   294  
   295  	// Download the original file from offset 40 and length 10.
   296  	fname := "offsetsinglechunk.dat"
   297  	downpath := filepath.Join(st.dir, fname)
   298  	dlURL := fmt.Sprintf("/renter/download/%s?destination=%s", ulSiaPath, downpath)
   299  	dlURL += fmt.Sprintf("&length=%d", length)
   300  	dlURL += fmt.Sprintf("&offset=%d", offset)
   301  	return st.getAPI(dlURL, nil)
   302  }
   303  
   304  func TestInvalidDownloadParameters(t *testing.T) {
   305  	if testing.Short() || !build.VLONG {
   306  		t.SkipNow()
   307  	}
   308  	t.Parallel()
   309  
   310  	testParams := []struct {
   311  		length   int
   312  		offset   int
   313  		filesize int
   314  		errorMsg string
   315  	}{
   316  		{0, -10, 1e4, "/download not prompting error when passing negative offset."},
   317  		{0, 1e4, 1e4, "/download not prompting error when passing offset equal to filesize."},
   318  		{1e4 + 1, 0, 1e4, "/download not prompting error when passing length exceeding filesize."},
   319  		{1e4 + 11, 10, 1e4, "/download not prompting error when passing length exceeding filesize with non-zero offset."},
   320  		{-1, 0, 1e4, "/download not prompting error when passing negative length."},
   321  	}
   322  
   323  	for _, params := range testParams {
   324  		err := runDownloadParamTest(t, params.length, params.offset, params.filesize)
   325  		if err == nil {
   326  			t.Fatal(params.errorMsg)
   327  		}
   328  	}
   329  }
   330  
   331  func TestRenterDownloadAsyncAndHttpRespError(t *testing.T) {
   332  	if testing.Short() {
   333  		t.SkipNow()
   334  	}
   335  	t.Parallel()
   336  
   337  	filesize := 1e4
   338  	ulSiaPath := "test.dat"
   339  
   340  	st, _ := setupTestDownload(t, int(filesize), ulSiaPath, true)
   341  	defer st.server.Close()
   342  
   343  	// Download the original file from offset 40 and length 10.
   344  	fname := "offsetsinglechunk.dat"
   345  	dlURL := fmt.Sprintf("/renter/download/%s?destination=%s&async=true&httpresp=true", ulSiaPath, fname)
   346  	err := st.getAPI(dlURL, nil)
   347  	if err == nil {
   348  		t.Fatalf("/download not prompting error when only passing both async and httpresp fields.")
   349  	}
   350  }
   351  
   352  func TestRenterDownloadAsyncNonexistentFile(t *testing.T) {
   353  	if testing.Short() {
   354  		t.SkipNow()
   355  	}
   356  	t.Parallel()
   357  
   358  	st, err := createServerTester(t.Name())
   359  	if err != nil {
   360  		t.Fatal(err)
   361  	}
   362  	defer st.server.Close()
   363  
   364  	downpath := filepath.Join(st.dir, "testfile")
   365  	err = st.getAPI(fmt.Sprintf("/renter/downloadasync/doesntexist?destination=%v", downpath), nil)
   366  	if err == nil || err.Error() != fmt.Sprintf("download failed: no file with that path: doesntexist") {
   367  		t.Fatal("downloadasync did not return error on nonexistent file")
   368  	}
   369  }
   370  
   371  func TestRenterDownloadAsyncAndNotDestinationError(t *testing.T) {
   372  	if testing.Short() {
   373  		t.SkipNow()
   374  	}
   375  	t.Parallel()
   376  
   377  	filesize := 1e4
   378  	ulSiaPath := "test.dat"
   379  
   380  	st, _ := setupTestDownload(t, int(filesize), ulSiaPath, true)
   381  	defer st.server.Close()
   382  
   383  	// Download the original file from offset 40 and length 10.
   384  	dlURL := fmt.Sprintf("/renter/download/%s?async=true", ulSiaPath)
   385  	err := st.getAPI(dlURL, nil)
   386  	if err == nil {
   387  		t.Fatal("/download not prompting error when async is specified but destination is empty.")
   388  	}
   389  }
   390  
   391  func TestRenterDownloadHttpRespAndDestinationError(t *testing.T) {
   392  	if testing.Short() {
   393  		t.SkipNow()
   394  	}
   395  	t.Parallel()
   396  
   397  	filesize := 1e4
   398  	ulSiaPath := "test.dat"
   399  
   400  	st, _ := setupTestDownload(t, int(filesize), ulSiaPath, true)
   401  	defer st.server.Close()
   402  
   403  	// Download the original file from offset 40 and length 10.
   404  	fname := "test.dat"
   405  	dlURL := fmt.Sprintf("/renter/download/%s?destination=%shttpresp=true", ulSiaPath, fname)
   406  	err := st.getAPI(dlURL, nil)
   407  	if err == nil {
   408  		t.Fatal("/download not prompting error when httpresp is specified and destination is non-empty.")
   409  	}
   410  }
   411  
   412  // TestRenterAsyncDownloadError tests that the /renter/asyncdownload route sets
   413  // the download's error field if it fails.
   414  func TestRenterAsyncDownloadError(t *testing.T) {
   415  	if testing.Short() {
   416  		t.SkipNow()
   417  	}
   418  	t.Parallel()
   419  
   420  	st, _ := setupTestDownload(t, 1e4, "test.dat", false)
   421  	defer st.server.panicClose()
   422  
   423  	// don't wait for the upload to complete, try to download immediately to
   424  	// intentionally cause a download error
   425  	downpath := filepath.Join(st.dir, "asyncdown.dat")
   426  	st.getAPI("/renter/downloadasync/test.dat?destination="+downpath, nil)
   427  
   428  	// verify the file has an error
   429  	var rdq RenterDownloadQueue
   430  	err := st.getAPI("/renter/downloads", &rdq)
   431  	if err != nil {
   432  		t.Fatal(err)
   433  	}
   434  	for _, download := range rdq.Downloads {
   435  		if download.SiaPath == "test.dat" && download.Received == download.Filesize && download.Error == "" {
   436  			t.Fatal("download had nil error")
   437  		}
   438  	}
   439  }
   440  
   441  // TestRenterAsyncDownload tests that the /renter/downloadasync route works
   442  // correctly.
   443  func TestRenterAsyncDownload(t *testing.T) {
   444  	if testing.Short() {
   445  		t.SkipNow()
   446  	}
   447  	t.Parallel()
   448  
   449  	st, _ := setupTestDownload(t, 1e4, "test.dat", true)
   450  	defer st.server.panicClose()
   451  
   452  	// Download the file asynchronously.
   453  	downpath := filepath.Join(st.dir, "asyncdown.dat")
   454  	err := st.getAPI("/renter/downloadasync/test.dat?destination="+downpath, nil)
   455  	if err != nil {
   456  		t.Fatal(err)
   457  	}
   458  
   459  	// download should eventually complete
   460  	var rdq RenterDownloadQueue
   461  	success := false
   462  	for start := time.Now(); time.Since(start) < 30*time.Second; time.Sleep(time.Millisecond * 10) {
   463  		err = st.getAPI("/renter/downloads", &rdq)
   464  		if err != nil {
   465  			t.Fatal(err)
   466  		}
   467  		for _, download := range rdq.Downloads {
   468  			if download.Received == download.Filesize && download.SiaPath == "test.dat" {
   469  				success = true
   470  			}
   471  		}
   472  		if success {
   473  			break
   474  		}
   475  	}
   476  	if !success {
   477  		t.Fatal("/renter/downloadasync did not download our test file")
   478  	}
   479  }
   480  
   481  // TestRenterPaths tests that the /renter routes handle path parameters
   482  // properly.
   483  func TestRenterPaths(t *testing.T) {
   484  	if testing.Short() {
   485  		t.SkipNow()
   486  	}
   487  	t.Parallel()
   488  	st, err := createServerTester(t.Name())
   489  	if err != nil {
   490  		t.Fatal(err)
   491  	}
   492  	defer st.server.panicClose()
   493  
   494  	// Announce the host.
   495  	err = st.announceHost()
   496  	if err != nil {
   497  		t.Fatal(err)
   498  	}
   499  
   500  	// Create a file.
   501  	path := filepath.Join(build.SiaTestingDir, "api", t.Name(), "test.dat")
   502  	err = createRandFile(path, 1024)
   503  	if err != nil {
   504  		t.Fatal(err)
   505  	}
   506  
   507  	// Upload to host.
   508  	uploadValues := url.Values{}
   509  	uploadValues.Set("source", path)
   510  	uploadValues.Set("renew", "true")
   511  	err = st.stdPostAPI("/renter/upload/foo/bar/test", uploadValues)
   512  	if err != nil {
   513  		t.Fatal(err)
   514  	}
   515  
   516  	// File should be listed by the renter.
   517  	var rf RenterFiles
   518  	err = st.getAPI("/renter/files", &rf)
   519  	if err != nil {
   520  		t.Fatal(err)
   521  	}
   522  	if len(rf.Files) != 1 || rf.Files[0].SiaPath != "foo/bar/test" {
   523  		t.Fatal("/renter/files did not return correct file:", rf)
   524  	}
   525  }
   526  
   527  // TestRenterConflicts tests that the renter handles naming conflicts properly.
   528  func TestRenterConflicts(t *testing.T) {
   529  	if testing.Short() {
   530  		t.SkipNow()
   531  	}
   532  	t.Parallel()
   533  	st, err := createServerTester(t.Name())
   534  	if err != nil {
   535  		t.Fatal(err)
   536  	}
   537  	defer st.server.panicClose()
   538  
   539  	// Announce the host.
   540  	err = st.announceHost()
   541  	if err != nil {
   542  		t.Fatal(err)
   543  	}
   544  
   545  	// Create a file.
   546  	path := filepath.Join(build.SiaTestingDir, "api", t.Name(), "test.dat")
   547  	err = createRandFile(path, 1024)
   548  	if err != nil {
   549  		t.Fatal(err)
   550  	}
   551  
   552  	// Upload to host, using a path designed to cause conflicts. The renter
   553  	// should automatically create a folder called foo/bar.sia. Later, we'll
   554  	// exploit this by uploading a file called foo/bar.
   555  	uploadValues := url.Values{}
   556  	uploadValues.Set("source", path)
   557  	uploadValues.Set("renew", "true")
   558  	err = st.stdPostAPI("/renter/upload/foo/bar.sia/test", uploadValues)
   559  	if err != nil {
   560  		t.Fatal(err)
   561  	}
   562  
   563  	// File should be listed by the renter.
   564  	var rf RenterFiles
   565  	err = st.getAPI("/renter/files", &rf)
   566  	if err != nil {
   567  		t.Fatal(err)
   568  	}
   569  	if len(rf.Files) != 1 || rf.Files[0].SiaPath != "foo/bar.sia/test" {
   570  		t.Fatal("/renter/files did not return correct file:", rf)
   571  	}
   572  
   573  	// Upload using the same nickname.
   574  	err = st.stdPostAPI("/renter/upload/foo/bar.sia/test", uploadValues)
   575  	expectedErr := Error{"upload failed: " + renter.ErrPathOverload.Error()}
   576  	if err != expectedErr {
   577  		t.Fatalf("expected %v, got %v", Error{"upload failed: " + renter.ErrPathOverload.Error()}, err)
   578  	}
   579  
   580  	// Upload using nickname that conflicts with folder.
   581  	err = st.stdPostAPI("/renter/upload/foo/bar", uploadValues)
   582  	if err == nil {
   583  		t.Fatal("expecting conflict error, got nil")
   584  	}
   585  }
   586  
   587  // TestRenterHandlerContracts checks that contract formation between a host and
   588  // renter behaves as expected, and that contract spending is the right amount.
   589  func TestRenterHandlerContracts(t *testing.T) {
   590  	if testing.Short() {
   591  		t.SkipNow()
   592  	}
   593  	t.Parallel()
   594  	st, err := createServerTester(t.Name())
   595  	if err != nil {
   596  		t.Fatal(err)
   597  	}
   598  	defer st.server.panicClose()
   599  
   600  	// Anounce the host and start accepting contracts.
   601  	if err := st.announceHost(); err != nil {
   602  		t.Fatal(err)
   603  	}
   604  	if err = st.acceptContracts(); err != nil {
   605  		t.Fatal(err)
   606  	}
   607  	if err = st.setHostStorage(); err != nil {
   608  		t.Fatal(err)
   609  	}
   610  
   611  	// The renter should not have any contracts yet.
   612  	var contracts RenterContracts
   613  	if err = st.getAPI("/renter/contracts", &contracts); err != nil {
   614  		t.Fatal(err)
   615  	}
   616  	if len(contracts.Contracts) != 0 {
   617  		t.Fatalf("expected renter to have 0 contracts; got %v", len(contracts.Contracts))
   618  	}
   619  
   620  	// Set an allowance for the renter, allowing a contract to be formed.
   621  	allowanceValues := url.Values{}
   622  	allowanceValues.Set("funds", testFunds)
   623  	allowanceValues.Set("period", testPeriod)
   624  	allowanceValues.Set("renewwindow", testRenewWindow)
   625  	allowanceValues.Set("hosts", fmt.Sprint(recommendedHosts))
   626  	if err = st.stdPostAPI("/renter", allowanceValues); err != nil {
   627  		t.Fatal(err)
   628  	}
   629  
   630  	// Block until the allowance has finished forming contracts.
   631  	err = build.Retry(50, time.Millisecond*250, func() error {
   632  		var rc RenterContracts
   633  		err = st.getAPI("/renter/contracts", &rc)
   634  		if err != nil {
   635  			return errors.New("couldn't get renter stats")
   636  		}
   637  		if len(rc.Contracts) != 1 {
   638  			return errors.New("no contracts")
   639  		}
   640  		return nil
   641  	})
   642  	if err != nil {
   643  		t.Fatal("allowance setting failed")
   644  	}
   645  
   646  	// The renter should now have 1 contract.
   647  	if err = st.getAPI("/renter/contracts", &contracts); err != nil {
   648  		t.Fatal(err)
   649  	}
   650  	if len(contracts.Contracts) != 1 {
   651  		t.Fatalf("expected renter to have 1 contract; got %v", len(contracts.Contracts))
   652  	}
   653  	if !contracts.Contracts[0].GoodForUpload || !contracts.Contracts[0].GoodForRenew {
   654  		t.Errorf("expected contract to be good for upload and renew")
   655  	}
   656  
   657  	// Check the renter's contract spending.
   658  	var get RenterGET
   659  	if err = st.getAPI("/renter", &get); err != nil {
   660  		t.Fatal(err)
   661  	}
   662  	expectedContractSpending := types.ZeroCurrency
   663  	for _, contract := range contracts.Contracts {
   664  		expectedContractSpending = expectedContractSpending.Add(contract.TotalCost)
   665  	}
   666  	if got := get.FinancialMetrics.ContractSpending; got.Cmp(expectedContractSpending) != 0 {
   667  		t.Fatalf("expected contract spending to be %v; got %v", expectedContractSpending, got)
   668  	}
   669  }
   670  
   671  // TestRenterHandlerGetAndPost checks that valid /renter calls successfully set
   672  // allowance values, while /renter calls with invalid allowance values are
   673  // correctly handled.
   674  func TestRenterHandlerGetAndPost(t *testing.T) {
   675  	if testing.Short() {
   676  		t.SkipNow()
   677  	}
   678  	t.Parallel()
   679  	st, err := createServerTester(t.Name())
   680  	if err != nil {
   681  		t.Fatal(err)
   682  	}
   683  	defer st.server.panicClose()
   684  
   685  	// Anounce the host and start accepting contracts.
   686  	if err := st.announceHost(); err != nil {
   687  		t.Fatal(err)
   688  	}
   689  	if err = st.acceptContracts(); err != nil {
   690  		t.Fatal(err)
   691  	}
   692  	if err = st.setHostStorage(); err != nil {
   693  		t.Fatal(err)
   694  	}
   695  
   696  	// Set an allowance for the renter, allowing a contract to be formed.
   697  	allowanceValues := url.Values{}
   698  	allowanceValues.Set("funds", testFunds)
   699  	allowanceValues.Set("period", testPeriod)
   700  	allowanceValues.Set("renewwindow", testRenewWindow)
   701  	allowanceValues.Set("hosts", fmt.Sprint(recommendedHosts))
   702  	if err = st.stdPostAPI("/renter", allowanceValues); err != nil {
   703  		t.Fatal(err)
   704  	}
   705  
   706  	// Check that a call to /renter returns the expected values.
   707  	var get RenterGET
   708  	if err = st.getAPI("/renter", &get); err != nil {
   709  		t.Fatal(err)
   710  	}
   711  	// Check the renter's funds.
   712  	expectedFunds, ok := scanAmount(testFunds)
   713  	if !ok {
   714  		t.Fatal("scanAmount failed")
   715  	}
   716  	if got := get.Settings.Allowance.Funds; got.Cmp(expectedFunds) != 0 {
   717  		t.Fatalf("expected funds to be %v; got %v", expectedFunds, got)
   718  	}
   719  	// Check the renter's period.
   720  	intPeriod, err := strconv.Atoi(testPeriod)
   721  	if err != nil {
   722  		t.Fatal(err)
   723  	}
   724  	expectedPeriod := types.BlockHeight(intPeriod)
   725  	if got := get.Settings.Allowance.Period; got != expectedPeriod {
   726  		t.Fatalf("expected period to be %v; got %v", expectedPeriod, got)
   727  	}
   728  	// Check the renter's renew window.
   729  	expectedRenewWindow := expectedPeriod / 2
   730  	if got := get.Settings.Allowance.RenewWindow; got != expectedRenewWindow {
   731  		t.Fatalf("expected renew window to be %v; got %v", expectedRenewWindow, got)
   732  	}
   733  	// Try an invalid period string.
   734  	allowanceValues.Set("period", "-1")
   735  	err = st.stdPostAPI("/renter", allowanceValues)
   736  	if err == nil || !strings.Contains(err.Error(), "unable to parse period") {
   737  		t.Errorf("expected error to begin with 'unable to parse period'; got %v", err)
   738  	}
   739  	// Try to set a zero renew window
   740  	allowanceValues.Set("period", "2")
   741  	allowanceValues.Set("renewwindow", "0")
   742  	err = st.stdPostAPI("/renter", allowanceValues)
   743  	if err == nil || err.Error() != contractor.ErrAllowanceZeroWindow.Error() {
   744  		t.Errorf("expected error to be %v, got %v", contractor.ErrAllowanceZeroWindow, err)
   745  	}
   746  	// Try to set a negative bandwidth limit
   747  	allowanceValues.Set("maxdownloadspeed", "-1")
   748  	allowanceValues.Set("renewwindow", "1")
   749  	err = st.stdPostAPI("/renter", allowanceValues)
   750  	if err == nil || err.Error() != "download/upload rate limit can't be below 0" {
   751  		t.Errorf("expected error to be 'download/upload rate limit...'; got %v", err)
   752  	}
   753  	allowanceValues.Set("maxuploadspeed", "-1")
   754  	err = st.stdPostAPI("/renter", allowanceValues)
   755  	if err == nil || err.Error() != "download/upload rate limit can't be below 0" {
   756  		t.Errorf("expected error to be 'download/upload rate limit...'; got %v", err)
   757  	}
   758  }
   759  
   760  // TestRenterLoadNonexistent checks that attempting to upload or download a
   761  // nonexistent file triggers the appropriate error.
   762  func TestRenterLoadNonexistent(t *testing.T) {
   763  	if testing.Short() {
   764  		t.SkipNow()
   765  	}
   766  	t.Parallel()
   767  	st, err := createServerTester(t.Name())
   768  	if err != nil {
   769  		t.Fatal(err)
   770  	}
   771  	defer st.server.panicClose()
   772  
   773  	// Anounce the host and start accepting contracts.
   774  	if err := st.announceHost(); err != nil {
   775  		t.Fatal(err)
   776  	}
   777  	if err = st.acceptContracts(); err != nil {
   778  		t.Fatal(err)
   779  	}
   780  	if err = st.setHostStorage(); err != nil {
   781  		t.Fatal(err)
   782  	}
   783  
   784  	// Set an allowance for the renter, allowing a contract to be formed.
   785  	allowanceValues := url.Values{}
   786  	allowanceValues.Set("funds", testFunds)
   787  	allowanceValues.Set("period", testPeriod)
   788  	allowanceValues.Set("renewwindow", testRenewWindow)
   789  	allowanceValues.Set("hosts", fmt.Sprint(recommendedHosts))
   790  	if err = st.stdPostAPI("/renter", allowanceValues); err != nil {
   791  		t.Fatal(err)
   792  	}
   793  
   794  	// Try uploading a nonexistent file.
   795  	fakepath := filepath.Join(st.dir, "dne.dat")
   796  	uploadValues := url.Values{}
   797  	uploadValues.Set("source", fakepath)
   798  	err = st.stdPostAPI("/renter/upload/dne", uploadValues)
   799  	if err == nil {
   800  		t.Errorf("expected error when uploading nonexistent file")
   801  	}
   802  
   803  	// Try downloading a nonexistent file.
   804  	downpath := filepath.Join(st.dir, "dnedown.dat")
   805  	err = st.stdGetAPI("/renter/download/dne?destination=" + downpath)
   806  	hasPrefix := strings.HasPrefix(err.Error(), "download failed: no file with that path")
   807  	if err == nil || !hasPrefix {
   808  		t.Errorf("expected error to be 'download failed: no file with that path'; got %v instead", err)
   809  	}
   810  
   811  	// The renter's downloads queue should be empty.
   812  	var queue RenterDownloadQueue
   813  	if err = st.getAPI("/renter/downloads", &queue); err != nil {
   814  		t.Fatal(err)
   815  	}
   816  	if len(queue.Downloads) != 0 {
   817  		t.Fatalf("expected renter to have 0 downloads in the queue; got %v", len(queue.Downloads))
   818  	}
   819  }
   820  
   821  // TestRenterHandlerRename checks that valid /renter/rename calls are
   822  // successful, and that invalid calls fail with the appropriate error.
   823  func TestRenterHandlerRename(t *testing.T) {
   824  	if testing.Short() {
   825  		t.SkipNow()
   826  	}
   827  	t.Parallel()
   828  	st, err := createServerTester(t.Name())
   829  	if err != nil {
   830  		t.Fatal(err)
   831  	}
   832  	defer st.server.panicClose()
   833  
   834  	// Anounce the host and start accepting contracts.
   835  	if err := st.announceHost(); err != nil {
   836  		t.Fatal(err)
   837  	}
   838  	if err = st.acceptContracts(); err != nil {
   839  		t.Fatal(err)
   840  	}
   841  	if err = st.setHostStorage(); err != nil {
   842  		t.Fatal(err)
   843  	}
   844  
   845  	// Try renaming a nonexistent file.
   846  	renameValues := url.Values{}
   847  	renameValues.Set("newsiapath", "newdne")
   848  	err = st.stdPostAPI("/renter/rename/dne", renameValues)
   849  	if err == nil || err.Error() != renter.ErrUnknownPath.Error() {
   850  		t.Errorf("expected error to be %v; got %v", renter.ErrUnknownPath, err)
   851  	}
   852  
   853  	// Set an allowance for the renter, allowing a contract to be formed.
   854  	allowanceValues := url.Values{}
   855  	allowanceValues.Set("funds", testFunds)
   856  	allowanceValues.Set("period", testPeriod)
   857  	allowanceValues.Set("renewwindow", testRenewWindow)
   858  	allowanceValues.Set("hosts", fmt.Sprint(recommendedHosts))
   859  	if err = st.stdPostAPI("/renter", allowanceValues); err != nil {
   860  		t.Fatal(err)
   861  	}
   862  
   863  	// Block until the allowance has finished forming contracts.
   864  	err = build.Retry(50, time.Millisecond*250, func() error {
   865  		var rc RenterContracts
   866  		err = st.getAPI("/renter/contracts", &rc)
   867  		if err != nil {
   868  			return errors.New("couldn't get renter stats")
   869  		}
   870  		if len(rc.Contracts) != 1 {
   871  			return errors.New("no contracts")
   872  		}
   873  		return nil
   874  	})
   875  	if err != nil {
   876  		t.Fatal("allowance setting failed")
   877  	}
   878  
   879  	// Create a file.
   880  	path1 := filepath.Join(st.dir, "test1.dat")
   881  	if err = createRandFile(path1, 512); err != nil {
   882  		t.Fatal(err)
   883  	}
   884  
   885  	// Upload to host.
   886  	uploadValues := url.Values{}
   887  	uploadValues.Set("source", path1)
   888  	if err = st.stdPostAPI("/renter/upload/test1", uploadValues); err != nil {
   889  		t.Fatal(err)
   890  	}
   891  
   892  	// Try renaming to an empty string.
   893  	renameValues.Set("newsiapath", "")
   894  	err = st.stdPostAPI("/renter/rename/test1", renameValues)
   895  	if err == nil || err.Error() != renter.ErrEmptyFilename.Error() {
   896  		t.Fatalf("expected error to be %v; got %v", renter.ErrEmptyFilename, err)
   897  	}
   898  
   899  	// Rename the file.
   900  	renameValues.Set("newsiapath", "newtest1")
   901  	if err = st.stdPostAPI("/renter/rename/test1", renameValues); err != nil {
   902  		t.Fatal(err)
   903  	}
   904  
   905  	// Should be able to continue uploading and downloading using the new name.
   906  	var rf RenterFiles
   907  	for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10); i++ {
   908  		st.getAPI("/renter/files", &rf)
   909  		time.Sleep(100 * time.Millisecond)
   910  	}
   911  	if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10 {
   912  		t.Fatal("upload is not succeeding:", rf.Files[0])
   913  	}
   914  	err = st.stdGetAPI("/renter/download/newtest1?destination=" + filepath.Join(st.dir, "testdown2.dat"))
   915  	if err != nil {
   916  		t.Fatal(err)
   917  	}
   918  
   919  	// Create and upload another file.
   920  	path2 := filepath.Join(st.dir, "test2.dat")
   921  	if err = createRandFile(path2, 512); err != nil {
   922  		t.Fatal(err)
   923  	}
   924  	uploadValues.Set("source", path2)
   925  	if err = st.stdPostAPI("/renter/upload/test2", uploadValues); err != nil {
   926  		t.Fatal(err)
   927  	}
   928  	// Try renaming to a name that's already taken.
   929  	renameValues.Set("newsiapath", "newtest1")
   930  	err = st.stdPostAPI("/renter/rename/test2", renameValues)
   931  	if err == nil || err.Error() != renter.ErrPathOverload.Error() {
   932  		t.Errorf("expected error to be %v; got %v", renter.ErrPathOverload, err)
   933  	}
   934  }
   935  
   936  // TestRenterHandlerDelete checks that deleting a valid file from the renter
   937  // goes as planned and that attempting to delete a nonexistent file fails with
   938  // the appropriate error.
   939  func TestRenterHandlerDelete(t *testing.T) {
   940  	if testing.Short() {
   941  		t.SkipNow()
   942  	}
   943  	t.Parallel()
   944  	st, err := createServerTester(t.Name())
   945  	if err != nil {
   946  		t.Fatal(err)
   947  	}
   948  	defer st.server.panicClose()
   949  
   950  	// Anounce the host and start accepting contracts.
   951  	if err := st.announceHost(); err != nil {
   952  		t.Fatal(err)
   953  	}
   954  	if err = st.acceptContracts(); err != nil {
   955  		t.Fatal(err)
   956  	}
   957  	if err = st.setHostStorage(); err != nil {
   958  		t.Fatal(err)
   959  	}
   960  
   961  	// Set an allowance for the renter, allowing a contract to be formed.
   962  	allowanceValues := url.Values{}
   963  	allowanceValues.Set("funds", testFunds)
   964  	allowanceValues.Set("period", testPeriod)
   965  	allowanceValues.Set("renewwindow", testRenewWindow)
   966  	allowanceValues.Set("hosts", fmt.Sprint(recommendedHosts))
   967  	if err = st.stdPostAPI("/renter", allowanceValues); err != nil {
   968  		t.Fatal(err)
   969  	}
   970  
   971  	// Create a file.
   972  	path := filepath.Join(st.dir, "test.dat")
   973  	if err = createRandFile(path, 1024); err != nil {
   974  		t.Fatal(err)
   975  	}
   976  
   977  	// Upload to host.
   978  	uploadValues := url.Values{}
   979  	uploadValues.Set("source", path)
   980  	if err = st.stdPostAPI("/renter/upload/test", uploadValues); err != nil {
   981  		t.Fatal(err)
   982  	}
   983  
   984  	// Delete the file.
   985  	if err = st.stdPostAPI("/renter/delete/test", url.Values{}); err != nil {
   986  		t.Fatal(err)
   987  	}
   988  
   989  	// The renter's list of files should now be empty.
   990  	var files RenterFiles
   991  	if err = st.getAPI("/renter/files", &files); err != nil {
   992  		t.Fatal(err)
   993  	}
   994  	if len(files.Files) != 0 {
   995  		t.Fatalf("renter's list of files should be empty; got %v instead", files)
   996  	}
   997  
   998  	// Try deleting a nonexistent file.
   999  	err = st.stdPostAPI("/renter/delete/dne", url.Values{})
  1000  	if err == nil || err.Error() != renter.ErrUnknownPath.Error() {
  1001  		t.Errorf("expected error to be %v, got %v", renter.ErrUnknownPath, err)
  1002  	}
  1003  }
  1004  
  1005  // Tests that the /renter/upload call checks for relative paths.
  1006  func TestRenterRelativePathErrorUpload(t *testing.T) {
  1007  	if testing.Short() {
  1008  		t.SkipNow()
  1009  	}
  1010  	t.Parallel()
  1011  	st, err := createServerTester(t.Name())
  1012  	if err != nil {
  1013  		t.Fatal(err)
  1014  	}
  1015  	defer st.server.panicClose()
  1016  
  1017  	// Anounce the host and start accepting contracts.
  1018  	if err := st.announceHost(); err != nil {
  1019  		t.Fatal(err)
  1020  	}
  1021  	if err = st.acceptContracts(); err != nil {
  1022  		t.Fatal(err)
  1023  	}
  1024  	if err = st.setHostStorage(); err != nil {
  1025  		t.Fatal(err)
  1026  	}
  1027  
  1028  	// Set an allowance for the renter, allowing a contract to be formed.
  1029  	allowanceValues := url.Values{}
  1030  	allowanceValues.Set("funds", testFunds)
  1031  	allowanceValues.Set("period", testPeriod)
  1032  	allowanceValues.Set("renewwindow", testRenewWindow)
  1033  	allowanceValues.Set("hosts", fmt.Sprint(recommendedHosts))
  1034  	if err = st.stdPostAPI("/renter", allowanceValues); err != nil {
  1035  		t.Fatal(err)
  1036  	}
  1037  
  1038  	renterUploadAbsoluteError := "source must be an absolute path"
  1039  
  1040  	// Create a file.
  1041  	path := filepath.Join(st.dir, "test.dat")
  1042  	if err = createRandFile(path, 1024); err != nil {
  1043  		t.Fatal(err)
  1044  	}
  1045  
  1046  	// This should fail.
  1047  	uploadValues := url.Values{}
  1048  	uploadValues.Set("source", "test.dat")
  1049  	if err = st.stdPostAPI("/renter/upload/test", uploadValues); err.Error() != renterUploadAbsoluteError {
  1050  		t.Fatal(err)
  1051  	}
  1052  
  1053  	// As should this.
  1054  	uploadValues = url.Values{}
  1055  	uploadValues.Set("source", "../test.dat")
  1056  	if err = st.stdPostAPI("/renter/upload/test", uploadValues); err.Error() != renterUploadAbsoluteError {
  1057  		t.Fatal(err)
  1058  	}
  1059  
  1060  	// This should succeed.
  1061  	uploadValues = url.Values{}
  1062  	uploadValues.Set("source", path)
  1063  	if err = st.stdPostAPI("/renter/upload/test", uploadValues); err != nil {
  1064  		t.Fatal(err)
  1065  	}
  1066  }
  1067  
  1068  // Tests that the /renter/download call checks for relative paths.
  1069  func TestRenterRelativePathErrorDownload(t *testing.T) {
  1070  	if testing.Short() {
  1071  		t.SkipNow()
  1072  	}
  1073  	t.Parallel()
  1074  	st, err := createServerTester(t.Name())
  1075  	if err != nil {
  1076  		t.Fatal(err)
  1077  	}
  1078  	defer st.server.panicClose()
  1079  
  1080  	// Anounce the host and start accepting contracts.
  1081  	if err := st.announceHost(); err != nil {
  1082  		t.Fatal(err)
  1083  	}
  1084  	if err = st.acceptContracts(); err != nil {
  1085  		t.Fatal(err)
  1086  	}
  1087  	if err = st.setHostStorage(); err != nil {
  1088  		t.Fatal(err)
  1089  	}
  1090  
  1091  	// Set an allowance for the renter, allowing a contract to be formed.
  1092  	allowanceValues := url.Values{}
  1093  	allowanceValues.Set("funds", testFunds)
  1094  	allowanceValues.Set("period", testPeriod)
  1095  	allowanceValues.Set("renewwindow", testRenewWindow)
  1096  	allowanceValues.Set("hosts", fmt.Sprint(recommendedHosts))
  1097  	if err = st.stdPostAPI("/renter", allowanceValues); err != nil {
  1098  		t.Fatal(err)
  1099  	}
  1100  
  1101  	renterDownloadAbsoluteError := "download failed: destination must be an absolute path"
  1102  
  1103  	// Create a file, and upload it.
  1104  	path := filepath.Join(st.dir, "test.dat")
  1105  	if err = createRandFile(path, 1024); err != nil {
  1106  		t.Fatal(err)
  1107  	}
  1108  	uploadValues := url.Values{}
  1109  	uploadValues.Set("source", path)
  1110  	if err = st.stdPostAPI("/renter/upload/test", uploadValues); err != nil {
  1111  		t.Fatal(err)
  1112  	}
  1113  	var rf RenterFiles
  1114  	for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10); i++ {
  1115  		st.getAPI("/renter/files", &rf)
  1116  		time.Sleep(200 * time.Millisecond)
  1117  	}
  1118  	if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10 {
  1119  		t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0])
  1120  	}
  1121  
  1122  	// Use a relative destination, which should fail.
  1123  	downloadPath := "test1.dat"
  1124  	if err = st.stdGetAPI("/renter/download/test?destination=" + downloadPath); err.Error() != renterDownloadAbsoluteError {
  1125  		t.Fatal(err)
  1126  	}
  1127  
  1128  	// Relative destination stepping backwards should also fail.
  1129  	downloadPath = "../test1.dat"
  1130  	if err = st.stdGetAPI("/renter/download/test?destination=" + downloadPath); err.Error() != renterDownloadAbsoluteError {
  1131  		t.Fatal(err)
  1132  	}
  1133  
  1134  	// Long relative destination should also fail (just missing leading slash).
  1135  	downloadPath = filepath.Join(st.dir[1:], "test1.dat")
  1136  	err = st.stdGetAPI("/renter/download/test?destination=" + downloadPath)
  1137  	if err == nil {
  1138  		t.Fatal("expecting an error")
  1139  	}
  1140  
  1141  	// Full destination should succeed.
  1142  	downloadPath = filepath.Join(st.dir, "test1.dat")
  1143  	err = st.stdGetAPI("/renter/download/test?destination=" + downloadPath)
  1144  	if err != nil {
  1145  		t.Fatal("expecting an error")
  1146  	}
  1147  }
  1148  
  1149  // TestRenterPricesHandler checks that the prices command returns reasonable
  1150  // values given the settings of the hosts.
  1151  func TestRenterPricesHandler(t *testing.T) {
  1152  	if testing.Short() {
  1153  		t.SkipNow()
  1154  	}
  1155  	t.Parallel()
  1156  	st, err := createServerTester(t.Name())
  1157  	if err != nil {
  1158  		t.Fatal(err)
  1159  	}
  1160  	defer st.server.panicClose()
  1161  
  1162  	// Announce the host and then get the calculated prices for when there is a
  1163  	// single host.
  1164  	var rpeSingle modules.RenterPriceEstimation
  1165  	if err = st.announceHost(); err != nil {
  1166  		t.Fatal(err)
  1167  	}
  1168  	if err = st.getAPI("/renter/prices", &rpeSingle); err != nil {
  1169  		t.Fatal(err)
  1170  	}
  1171  
  1172  	// Create several more hosts all using the default settings.
  1173  	stHost1, err := blankServerTester(t.Name() + " - Host 1")
  1174  	if err != nil {
  1175  		t.Fatal(err)
  1176  	}
  1177  	defer stHost1.panicClose()
  1178  	stHost2, err := blankServerTester(t.Name() + " - Host 2")
  1179  	if err != nil {
  1180  		t.Fatal(err)
  1181  	}
  1182  	defer stHost2.panicClose()
  1183  
  1184  	// Connect all the nodes and announce all of the hosts.
  1185  	sts := []*serverTester{st, stHost1, stHost2}
  1186  	err = fullyConnectNodes(sts)
  1187  	if err != nil {
  1188  		t.Fatal(err)
  1189  	}
  1190  	err = fundAllNodes(sts)
  1191  	if err != nil {
  1192  		t.Fatal(err)
  1193  	}
  1194  	err = announceAllHosts(sts)
  1195  	if err != nil {
  1196  		t.Fatal(err)
  1197  	}
  1198  
  1199  	// Grab the price estimates for when there are a bunch of hosts with the
  1200  	// same stats.
  1201  	var rpeMulti modules.RenterPriceEstimation
  1202  	if err = st.getAPI("/renter/prices", &rpeMulti); err != nil {
  1203  		t.Fatal(err)
  1204  	}
  1205  
  1206  	// Verify that the aggregate is the same.
  1207  	if !rpeMulti.DownloadTerabyte.Equals(rpeSingle.DownloadTerabyte) {
  1208  		t.Log(rpeMulti.DownloadTerabyte)
  1209  		t.Log(rpeSingle.DownloadTerabyte)
  1210  		t.Error("price changed from single to multi")
  1211  	}
  1212  	if !rpeMulti.FormContracts.Equals(rpeSingle.FormContracts) {
  1213  		t.Error("price changed from single to multi")
  1214  	}
  1215  	if !rpeMulti.StorageTerabyteMonth.Equals(rpeSingle.StorageTerabyteMonth) {
  1216  		t.Error("price changed from single to multi")
  1217  	}
  1218  	if !rpeMulti.UploadTerabyte.Equals(rpeSingle.UploadTerabyte) {
  1219  		t.Error("price changed from single to multi")
  1220  	}
  1221  }
  1222  
  1223  // TestRenterPricesHandlerCheap checks that the prices command returns
  1224  // reasonable values given the settings of the hosts.
  1225  func TestRenterPricesHandlerCheap(t *testing.T) {
  1226  	if testing.Short() || !build.VLONG {
  1227  		t.SkipNow()
  1228  	}
  1229  	t.Parallel()
  1230  	st, err := createServerTester(t.Name())
  1231  	if err != nil {
  1232  		t.Fatal(err)
  1233  	}
  1234  	defer st.server.panicClose()
  1235  
  1236  	// Announce the host and then get the calculated prices for when there is a
  1237  	// single host.
  1238  	var rpeSingle modules.RenterPriceEstimation
  1239  	if err = st.announceHost(); err != nil {
  1240  		t.Fatal(err)
  1241  	}
  1242  	if err = st.getAPI("/renter/prices", &rpeSingle); err != nil {
  1243  		t.Fatal(err)
  1244  	}
  1245  
  1246  	// Create several more hosts all using the default settings.
  1247  	stHost1, err := blankServerTester(t.Name() + " - Host 1")
  1248  	if err != nil {
  1249  		t.Fatal(err)
  1250  	}
  1251  	defer stHost1.panicClose()
  1252  	stHost2, err := blankServerTester(t.Name() + " - Host 2")
  1253  	if err != nil {
  1254  		t.Fatal(err)
  1255  	}
  1256  	defer stHost2.panicClose()
  1257  
  1258  	var hg HostGET
  1259  	err = st.getAPI("/host", &hg)
  1260  	if err != nil {
  1261  		t.Fatal(err)
  1262  	}
  1263  	err = stHost1.getAPI("/host", &hg)
  1264  	if err != nil {
  1265  		t.Fatal(err)
  1266  	}
  1267  	err = stHost2.getAPI("/host", &hg)
  1268  	if err != nil {
  1269  		t.Fatal(err)
  1270  	}
  1271  
  1272  	// Set host 5 to be cheaper than the rest by a substantial amount. This
  1273  	// should result in a reduction for the price estimation.
  1274  	vals := url.Values{}
  1275  	vals.Set("mincontractprice", "1")
  1276  	vals.Set("mindownloadbandwidthprice", "1")
  1277  	vals.Set("minstorageprice", "1")
  1278  	vals.Set("minuploadbandwidthprice", "1")
  1279  	err = stHost2.stdPostAPI("/host", vals)
  1280  	if err != nil {
  1281  		t.Fatal(err)
  1282  	}
  1283  
  1284  	// Connect all the nodes and announce all of the hosts.
  1285  	sts := []*serverTester{st, stHost1, stHost2}
  1286  	err = fullyConnectNodes(sts)
  1287  	if err != nil {
  1288  		t.Fatal(err)
  1289  	}
  1290  	err = fundAllNodes(sts)
  1291  	if err != nil {
  1292  		t.Fatal(err)
  1293  	}
  1294  	err = announceAllHosts(sts)
  1295  	if err != nil {
  1296  		t.Fatal(err)
  1297  	}
  1298  
  1299  	// Grab the price estimates for when there are a bunch of hosts with the
  1300  	// same stats.
  1301  	var rpeMulti modules.RenterPriceEstimation
  1302  	if err = st.announceHost(); err != nil {
  1303  		t.Fatal(err)
  1304  	}
  1305  	if err = st.getAPI("/renter/prices", &rpeMulti); err != nil {
  1306  		t.Fatal(err)
  1307  	}
  1308  
  1309  	// Verify that the aggregate is the same.
  1310  	if !(rpeMulti.DownloadTerabyte.Cmp(rpeSingle.DownloadTerabyte) < 0) {
  1311  		t.Log(rpeMulti.DownloadTerabyte)
  1312  		t.Log(rpeSingle.DownloadTerabyte)
  1313  		t.Error("price did not drop from single to multi")
  1314  	}
  1315  	if !(rpeMulti.FormContracts.Cmp(rpeSingle.FormContracts) < 0) {
  1316  		t.Error("price did not drop from single to multi")
  1317  	}
  1318  	if !(rpeMulti.StorageTerabyteMonth.Cmp(rpeSingle.StorageTerabyteMonth) < 0) {
  1319  		t.Error("price did not drop from single to multi")
  1320  	}
  1321  	if !(rpeMulti.UploadTerabyte.Cmp(rpeSingle.UploadTerabyte) < 0) {
  1322  		t.Error("price did not drop from single to multi")
  1323  	}
  1324  }
  1325  
  1326  // TestRenterPricesHandlerIgnorePricey checks that the prices command returns
  1327  // reasonable values given the settings of the hosts.
  1328  func TestRenterPricesHandlerIgnorePricey(t *testing.T) {
  1329  	if testing.Short() || !build.VLONG {
  1330  		t.SkipNow()
  1331  	}
  1332  	t.Parallel()
  1333  	st, err := createServerTester(t.Name())
  1334  	if err != nil {
  1335  		t.Fatal(err)
  1336  	}
  1337  	defer st.server.panicClose()
  1338  
  1339  	// Announce the host and then get the calculated prices for when there is a
  1340  	// single host.
  1341  	var rpeSingle modules.RenterPriceEstimation
  1342  	if err = st.announceHost(); err != nil {
  1343  		t.Fatal(err)
  1344  	}
  1345  	if err = st.getAPI("/renter/prices", &rpeSingle); err != nil {
  1346  		t.Fatal(err)
  1347  	}
  1348  
  1349  	// Create several more hosts all using the default settings.
  1350  	stHost1, err := blankServerTester(t.Name() + " - Host 1")
  1351  	if err != nil {
  1352  		t.Fatal(err)
  1353  	}
  1354  	defer stHost1.panicClose()
  1355  	stHost2, err := blankServerTester(t.Name() + " - Host 2")
  1356  	if err != nil {
  1357  		t.Fatal(err)
  1358  	}
  1359  	defer stHost2.panicClose()
  1360  	stHost3, err := blankServerTester(t.Name() + " - Host 3")
  1361  	if err != nil {
  1362  		t.Fatal(err)
  1363  	}
  1364  	defer stHost3.panicClose()
  1365  	stHost4, err := blankServerTester(t.Name() + " - Host 4")
  1366  	if err != nil {
  1367  		t.Fatal(err)
  1368  	}
  1369  	defer stHost4.panicClose()
  1370  	stHost5, err := blankServerTester(t.Name() + " - Host 5")
  1371  	if err != nil {
  1372  		t.Fatal(err)
  1373  	}
  1374  	defer stHost5.panicClose()
  1375  
  1376  	// Set host 5 to be cheaper than the rest by a substantial amount. This
  1377  	// should result in a reduction for the price estimation.
  1378  	vals := url.Values{}
  1379  	vals.Set("mindownloadbandwidthprice", "100000000000000000000")
  1380  	vals.Set("mincontractprice", "1000000000000000000000000000")
  1381  	vals.Set("minstorageprice", "100000000000000000000")
  1382  	vals.Set("minuploadbandwidthprice", "100000000000000000000")
  1383  	err = stHost5.stdPostAPI("/host", vals)
  1384  	if err != nil {
  1385  		t.Fatal(err)
  1386  	}
  1387  
  1388  	// Connect all the nodes and announce all of the hosts.
  1389  	sts := []*serverTester{st, stHost1, stHost2, stHost3, stHost4, stHost5}
  1390  	err = fullyConnectNodes(sts)
  1391  	if err != nil {
  1392  		t.Fatal(err)
  1393  	}
  1394  	err = fundAllNodes(sts)
  1395  	if err != nil {
  1396  		t.Fatal(err)
  1397  	}
  1398  	err = announceAllHosts(sts)
  1399  	if err != nil {
  1400  		t.Fatal(err)
  1401  	}
  1402  
  1403  	// Grab the price estimates for when there are a bunch of hosts with the
  1404  	// same stats.
  1405  	var rpeMulti modules.RenterPriceEstimation
  1406  	if err = st.announceHost(); err != nil {
  1407  		t.Fatal(err)
  1408  	}
  1409  	if err = st.getAPI("/renter/prices", &rpeMulti); err != nil {
  1410  		t.Fatal(err)
  1411  	}
  1412  
  1413  	// Verify that the aggregate is the same - price should not have moved
  1414  	// because the expensive host will be ignored as there is only one.
  1415  	if !rpeMulti.DownloadTerabyte.Equals(rpeSingle.DownloadTerabyte) {
  1416  		t.Log(rpeMulti.DownloadTerabyte)
  1417  		t.Log(rpeSingle.DownloadTerabyte)
  1418  		t.Error("price changed from single to multi")
  1419  	}
  1420  	if !rpeMulti.FormContracts.Equals(rpeSingle.FormContracts) {
  1421  		t.Error("price changed from single to multi")
  1422  	}
  1423  	if !rpeMulti.StorageTerabyteMonth.Equals(rpeSingle.StorageTerabyteMonth) {
  1424  		t.Error("price changed from single to multi")
  1425  	}
  1426  	if !rpeMulti.UploadTerabyte.Equals(rpeSingle.UploadTerabyte) {
  1427  		t.Error("price changed from single to multi")
  1428  	}
  1429  }
  1430  
  1431  // TestRenterPricesHandlerPricey checks that the prices command returns
  1432  // reasonable values given the settings of the hosts.
  1433  func TestRenterPricesHandlerPricey(t *testing.T) {
  1434  	if testing.Short() {
  1435  		t.SkipNow()
  1436  	}
  1437  	t.Parallel()
  1438  	st, err := createServerTester(t.Name())
  1439  	if err != nil {
  1440  		t.Fatal(err)
  1441  	}
  1442  	defer st.server.panicClose()
  1443  
  1444  	// Announce the host and then get the calculated prices for when there is a
  1445  	// single host.
  1446  	var rpeSingle modules.RenterPriceEstimation
  1447  	if err = st.announceHost(); err != nil {
  1448  		t.Fatal(err)
  1449  	}
  1450  	if err = st.getAPI("/renter/prices", &rpeSingle); err != nil {
  1451  		t.Fatal(err)
  1452  	}
  1453  
  1454  	// Create several more hosts all using the default settings.
  1455  	stHost1, err := blankServerTester(t.Name() + " - Host 1")
  1456  	if err != nil {
  1457  		t.Fatal(err)
  1458  	}
  1459  	stHost2, err := blankServerTester(t.Name() + " - Host 2")
  1460  	if err != nil {
  1461  		t.Fatal(err)
  1462  	}
  1463  
  1464  	var hg HostGET
  1465  	err = st.getAPI("/host", &hg)
  1466  	if err != nil {
  1467  		t.Fatal(err)
  1468  	}
  1469  	err = stHost1.getAPI("/host", &hg)
  1470  	if err != nil {
  1471  		t.Fatal(err)
  1472  	}
  1473  	err = stHost2.getAPI("/host", &hg)
  1474  	if err != nil {
  1475  		t.Fatal(err)
  1476  	}
  1477  
  1478  	// Set host 5 to be cheaper than the rest by a substantial amount. This
  1479  	// should result in a reduction for the price estimation.
  1480  	vals := url.Values{}
  1481  	vals.Set("mindownloadbandwidthprice", "100000000000000000000")
  1482  	vals.Set("mincontractprice", "1000000000000000000000000000")
  1483  	vals.Set("minstorageprice", "100000000000000000000")
  1484  	vals.Set("minuploadbandwidthprice", "100000000000000000000")
  1485  	err = stHost2.stdPostAPI("/host", vals)
  1486  	if err != nil {
  1487  		t.Fatal(err)
  1488  	}
  1489  
  1490  	// Connect all the nodes and announce all of the hosts.
  1491  	sts := []*serverTester{st, stHost1, stHost2}
  1492  	err = fullyConnectNodes(sts)
  1493  	if err != nil {
  1494  		t.Fatal(err)
  1495  	}
  1496  	err = fundAllNodes(sts)
  1497  	if err != nil {
  1498  		t.Fatal(err)
  1499  	}
  1500  	err = announceAllHosts(sts)
  1501  	if err != nil {
  1502  		t.Fatal(err)
  1503  	}
  1504  
  1505  	// Grab the price estimates for when there are a bunch of hosts with the
  1506  	// same stats.
  1507  	var rpeMulti modules.RenterPriceEstimation
  1508  	if err = st.getAPI("/renter/prices", &rpeMulti); err != nil {
  1509  		t.Fatal(err)
  1510  	}
  1511  
  1512  	// Verify that the aggregate is the same.
  1513  	if !(rpeMulti.DownloadTerabyte.Cmp(rpeSingle.DownloadTerabyte) > 0) {
  1514  		t.Error("price did not drop from single to multi")
  1515  	}
  1516  	if !(rpeMulti.FormContracts.Cmp(rpeSingle.FormContracts) > 0) {
  1517  		t.Log(rpeMulti.FormContracts)
  1518  		t.Log(rpeSingle.FormContracts)
  1519  		t.Error("price did not drop from single to multi")
  1520  	}
  1521  	if !(rpeMulti.StorageTerabyteMonth.Cmp(rpeSingle.StorageTerabyteMonth) > 0) {
  1522  		t.Error("price did not drop from single to multi")
  1523  	}
  1524  	if !(rpeMulti.UploadTerabyte.Cmp(rpeSingle.UploadTerabyte) > 0) {
  1525  		t.Error("price did not drop from single to multi")
  1526  	}
  1527  }
  1528  
  1529  // TestContractorHostRemoval checks that the contractor properly migrates away
  1530  // from low quality hosts when there are higher quality hosts available.
  1531  func TestContractorHostRemoval(t *testing.T) {
  1532  	// Create a renter and 2 hosts. Connect to the hosts and start uploading.
  1533  	if testing.Short() || !build.VLONG {
  1534  		t.SkipNow()
  1535  	}
  1536  	st, err := createServerTester(t.Name() + "renter")
  1537  	if err != nil {
  1538  		t.Fatal(err)
  1539  	}
  1540  	defer st.server.panicClose()
  1541  	stH1, err := blankServerTester(t.Name() + " - Host 1")
  1542  	if err != nil {
  1543  		t.Fatal(err)
  1544  	}
  1545  	defer stH1.server.Close()
  1546  	testGroup := []*serverTester{st, stH1}
  1547  
  1548  	// Connect the testers to eachother so that they are all on the same
  1549  	// blockchain.
  1550  	err = fullyConnectNodes(testGroup)
  1551  	if err != nil {
  1552  		t.Fatal(err)
  1553  	}
  1554  	// Make sure that every wallet has money in it.
  1555  	err = fundAllNodes(testGroup)
  1556  	if err != nil {
  1557  		t.Fatal(err)
  1558  	}
  1559  
  1560  	// Add storage to every host.
  1561  	err = addStorageToAllHosts(testGroup)
  1562  	if err != nil {
  1563  		t.Fatal(err)
  1564  	}
  1565  	// Raise the prices significantly for the two hosts.
  1566  	raisedPrice := url.Values{}
  1567  	raisedPrice.Set("mincontractprice", "5000000000000000000000000000") // 5 KS
  1568  	raisedPrice.Set("period", testPeriod)
  1569  	err = st.stdPostAPI("/host", raisedPrice)
  1570  	if err != nil {
  1571  		t.Fatal(err)
  1572  	}
  1573  	err = stH1.stdPostAPI("/host", raisedPrice)
  1574  	if err != nil {
  1575  		t.Fatal(err)
  1576  	}
  1577  	// Anounce the hosts.
  1578  	err = announceAllHosts(testGroup)
  1579  	if err != nil {
  1580  		t.Fatal(err)
  1581  	}
  1582  
  1583  	// Set an allowance with two hosts.
  1584  	allowanceValues := url.Values{}
  1585  	allowanceValues.Set("funds", "500000000000000000000000000000") // 500k SC
  1586  	allowanceValues.Set("hosts", "2")
  1587  	allowanceValues.Set("period", "15")
  1588  	err = st.stdPostAPI("/renter", allowanceValues)
  1589  	if err != nil {
  1590  		t.Fatal(err)
  1591  	}
  1592  
  1593  	// Create a file to upload.
  1594  	filesize := int(100)
  1595  	path := filepath.Join(st.dir, "test.dat")
  1596  	err = createRandFile(path, filesize)
  1597  	if err != nil {
  1598  		t.Fatal(err)
  1599  	}
  1600  	origBytes, err := ioutil.ReadFile(path)
  1601  	if err != nil {
  1602  		t.Fatal(err)
  1603  	}
  1604  
  1605  	// upload the file
  1606  	uploadValues := url.Values{}
  1607  	uploadValues.Set("source", path)
  1608  	uploadValues.Set("datapieces", "1")
  1609  	uploadValues.Set("paritypieces", "1")
  1610  	err = st.stdPostAPI("/renter/upload/test", uploadValues)
  1611  	if err != nil {
  1612  		t.Fatal(err)
  1613  	}
  1614  
  1615  	// redundancy should reach 2
  1616  	var rf RenterFiles
  1617  	err = retry(120, 250*time.Millisecond, func() error {
  1618  		st.getAPI("/renter/files", &rf)
  1619  		if len(rf.Files) >= 1 && rf.Files[0].Redundancy == 2 {
  1620  			return nil
  1621  		}
  1622  		return errors.New("file not uploaded")
  1623  	})
  1624  	if err != nil {
  1625  		t.Fatal(err)
  1626  	}
  1627  
  1628  	// verify we can download
  1629  	downloadPath := filepath.Join(st.dir, "test-downloaded-verify.dat")
  1630  	err = st.stdGetAPI("/renter/download/test?destination=" + downloadPath)
  1631  	if err != nil {
  1632  		t.Fatal(err)
  1633  	}
  1634  	downloadBytes, err := ioutil.ReadFile(downloadPath)
  1635  	if err != nil {
  1636  		t.Fatal(err)
  1637  	}
  1638  	if !bytes.Equal(downloadBytes, origBytes) {
  1639  		t.Fatal("downloaded file and uploaded file do not match")
  1640  	}
  1641  
  1642  	// Get the values of the first and second contract.
  1643  	var rc RenterContracts
  1644  	err = st.getAPI("/renter/contracts", &rc)
  1645  	if err != nil {
  1646  		t.Fatal(err)
  1647  	}
  1648  	if len(rc.Contracts) != 2 {
  1649  		t.Fatal("wrong contract count")
  1650  	}
  1651  	rc1Host := rc.Contracts[0].HostPublicKey.String()
  1652  	rc2Host := rc.Contracts[1].HostPublicKey.String()
  1653  
  1654  	// Add 3 new hosts that will be competing with the expensive hosts.
  1655  	stH2, err := blankServerTester(t.Name() + " - Host 2")
  1656  	if err != nil {
  1657  		t.Fatal(err)
  1658  	}
  1659  	defer stH2.server.Close()
  1660  	stH3, err := blankServerTester(t.Name() + " - Host 3")
  1661  	if err != nil {
  1662  		t.Fatal(err)
  1663  	}
  1664  	defer stH3.server.Close()
  1665  	stH4, err := blankServerTester(t.Name() + " - Host 4")
  1666  	if err != nil {
  1667  		t.Fatal(err)
  1668  	}
  1669  	defer stH4.server.Close()
  1670  	testGroup = []*serverTester{st, stH1, stH2, stH3, stH4}
  1671  	// Connect the testers to eachother so that they are all on the same
  1672  	// blockchain.
  1673  	err = fullyConnectNodes(testGroup)
  1674  	if err != nil {
  1675  		t.Fatal(err)
  1676  	}
  1677  	// Make sure that every wallet has money in it.
  1678  	err = fundAllNodes(testGroup)
  1679  	if err != nil {
  1680  		t.Fatal(err)
  1681  	}
  1682  	// Add storage to every host.
  1683  	err = addStorageToAllHosts([]*serverTester{stH2, stH3, stH4})
  1684  	if err != nil {
  1685  		t.Fatal(err)
  1686  	}
  1687  	// Anounce the hosts.
  1688  	err = announceAllHosts(testGroup)
  1689  	if err != nil {
  1690  		t.Fatal(err)
  1691  	}
  1692  
  1693  	// Block until the hostdb reaches five hosts.
  1694  	err = build.Retry(150, time.Millisecond*250, func() error {
  1695  		var ah HostdbActiveGET
  1696  		err = st.getAPI("/hostdb/active", &ah)
  1697  		if err != nil {
  1698  			return err
  1699  		}
  1700  		if len(ah.Hosts) < 5 {
  1701  			return errors.New("new hosts never appeared in hostdb")
  1702  		}
  1703  		return nil
  1704  	})
  1705  	if err != nil {
  1706  		t.Fatal(err)
  1707  	}
  1708  
  1709  	// Mine a block to trigger a second run of threadedContractMaintenance.
  1710  	_, err = st.miner.AddBlock()
  1711  	if err != nil {
  1712  		t.Fatal(err)
  1713  	}
  1714  
  1715  	// Verify that st and stH1 are dropped in favor of the newer, better hosts.
  1716  	err = build.Retry(150, time.Millisecond*250, func() error {
  1717  		var newContracts int
  1718  		err = st.getAPI("/renter/contracts", &rc)
  1719  		if err != nil {
  1720  			return errors.New("couldn't get renter stats")
  1721  		}
  1722  		hostMap := make(map[string]struct{})
  1723  		hostMap[rc1Host] = struct{}{}
  1724  		hostMap[rc2Host] = struct{}{}
  1725  		for _, contract := range rc.Contracts {
  1726  			_, exists := hostMap[contract.HostPublicKey.String()]
  1727  			if !exists {
  1728  				newContracts++
  1729  				hostMap[contract.HostPublicKey.String()] = struct{}{}
  1730  			}
  1731  		}
  1732  		if newContracts != 2 {
  1733  			return fmt.Errorf("not the right number of new contracts: %v", newContracts)
  1734  		}
  1735  		return nil
  1736  	})
  1737  	if err != nil {
  1738  		t.Fatal(err)
  1739  	}
  1740  
  1741  	// Block until redundancy is restored to 2.
  1742  	err = retry(120, 250*time.Millisecond, func() error {
  1743  		st.getAPI("/renter/files", &rf)
  1744  		if len(rf.Files) == 1 && rf.Files[0].Redundancy == 2 {
  1745  			return nil
  1746  		}
  1747  		return errors.New("file not uploaded to full redundancy")
  1748  	})
  1749  	if err != nil {
  1750  		t.Fatal(err)
  1751  	}
  1752  
  1753  	// Grab the old contracts, then mine blocks to trigger a renew, and then
  1754  	// wait until the renew is complete.
  1755  	err = st.getAPI("/renter/contracts", &rc)
  1756  	if err != nil {
  1757  		t.Fatal(err)
  1758  	}
  1759  	// Check the amount of data in each contract.
  1760  	for _, contract := range rc.Contracts {
  1761  		if contract.Size != modules.SectorSize {
  1762  			t.Error("Each contrat should have 1 sector:", contract.Size, contract.ID)
  1763  		}
  1764  	}
  1765  	// Mine blocks to force a contract renewal.
  1766  	for i := 0; i < 11; i++ {
  1767  		_, err := st.miner.AddBlock()
  1768  		if err != nil {
  1769  			t.Fatal(err)
  1770  		}
  1771  		_, err = synchronizationCheck(testGroup)
  1772  		if err != nil {
  1773  			t.Fatal(err)
  1774  		}
  1775  		// Sleep to give the contractor some time to perform the renew.
  1776  		time.Sleep(time.Millisecond * 100)
  1777  	}
  1778  	// Give the renter time to renew. Two of the contracts should renew.
  1779  	var rc2 RenterContracts
  1780  	err = build.Retry(50, time.Millisecond*250, func() error {
  1781  		err = st.getAPI("/renter/contracts", &rc2)
  1782  		if err != nil {
  1783  			return errors.New("couldn't get renter stats")
  1784  		}
  1785  
  1786  		// Check that at least 2 contracts are different between rc and rc2.
  1787  		tracker := make(map[types.FileContractID]struct{})
  1788  		// Add all the contracts.
  1789  		for _, contract := range rc.Contracts {
  1790  			tracker[contract.ID] = struct{}{}
  1791  		}
  1792  		// Count the number of contracts that were not seen in the previous
  1793  		// batch of contracts, and check that the new contracts are not with the
  1794  		// expensive hosts.
  1795  		var unseen int
  1796  		for _, contract := range rc2.Contracts {
  1797  			_, exists := tracker[contract.ID]
  1798  			if !exists {
  1799  				unseen++
  1800  				tracker[contract.ID] = struct{}{}
  1801  				if contract.HostPublicKey.String() == rc1Host || contract.HostPublicKey.String() == rc2Host {
  1802  					return errors.New("the wrong contracts are being renewed")
  1803  				}
  1804  			}
  1805  		}
  1806  		if unseen != 2 {
  1807  			return fmt.Errorf("the wrong number of contracts seem to be getting renewed")
  1808  		}
  1809  		return nil
  1810  	})
  1811  	if err != nil {
  1812  		t.Fatal(err)
  1813  	}
  1814  	// The renewing process should not have resulted in additional data being
  1815  	// uploaded - it should be the same data in the contracts.
  1816  	for _, contract := range rc2.Contracts {
  1817  		if contract.Size != modules.SectorSize {
  1818  			t.Error("Contract has the wrong size:", contract.Size)
  1819  		}
  1820  	}
  1821  
  1822  	// Try again to download the file we uploaded. It should still be
  1823  	// retrievable.
  1824  	downloadPath2 := filepath.Join(st.dir, "test-downloaded-verify-2.dat")
  1825  	err = st.stdGetAPI("/renter/download/test?destination=" + downloadPath2)
  1826  	if err != nil {
  1827  		t.Fatal(err)
  1828  	}
  1829  	downloadBytes2, err := ioutil.ReadFile(downloadPath2)
  1830  	if err != nil {
  1831  		t.Fatal(err)
  1832  	}
  1833  	if !bytes.Equal(downloadBytes2, origBytes) {
  1834  		t.Fatal("downloaded file and uploaded file do not match")
  1835  	}
  1836  
  1837  	// Mine out another set of the blocks so that the bad contracts expire.
  1838  	for i := 0; i < 11; i++ {
  1839  		_, err := st.miner.AddBlock()
  1840  		if err != nil {
  1841  			t.Fatal(err)
  1842  		}
  1843  		_, err = synchronizationCheck(testGroup)
  1844  		if err != nil {
  1845  			t.Fatal(err)
  1846  		}
  1847  		time.Sleep(time.Millisecond * 100)
  1848  	}
  1849  
  1850  	// Should be back down to 2 contracts now, with the new hosts. Verify that
  1851  	// st and stH1 are dropped in favor of the newer, better hosts. The
  1852  	// contracts should also have data in them.
  1853  	err = build.Retry(50, time.Millisecond*250, func() error {
  1854  		err = st.getAPI("/renter/contracts", &rc)
  1855  		if err != nil {
  1856  			return errors.New("couldn't get renter stats")
  1857  		}
  1858  		if len(rc.Contracts) != 2 {
  1859  			return fmt.Errorf("renewing seems to have failed: %v", len(rc.Contracts))
  1860  		}
  1861  		return nil
  1862  	})
  1863  	if err != nil {
  1864  		t.Fatal(err)
  1865  	}
  1866  	if rc.Contracts[0].HostPublicKey.String() == rc1Host || rc.Contracts[0].HostPublicKey.String() == rc2Host {
  1867  		t.Error("renter is renewing the wrong contracts", rc.Contracts[0].HostPublicKey.String())
  1868  	}
  1869  	if rc.Contracts[1].HostPublicKey.String() == rc1Host || rc.Contracts[1].HostPublicKey.String() == rc2Host {
  1870  		t.Error("renter is renewing the wrong contracts", rc.Contracts[1].HostPublicKey.String())
  1871  	}
  1872  	// The renewing process should not have resulted in additional data being
  1873  	// uploaded - it should be the same data in the contracts.
  1874  	for _, contract := range rc.Contracts {
  1875  		if contract.Size != modules.SectorSize {
  1876  			t.Error("Contract has the wrong size:", contract.Size)
  1877  		}
  1878  	}
  1879  	// Redundancy should still be 2.
  1880  	err = retry(120, 250*time.Millisecond, func() error {
  1881  		st.getAPI("/renter/files", &rf)
  1882  		if len(rf.Files) >= 1 && rf.Files[0].Redundancy == 2 {
  1883  			return nil
  1884  		}
  1885  		return errors.New("file not uploaded to full redundancy")
  1886  	})
  1887  	if err != nil {
  1888  		t.Fatal(err, "::", rf.Files[0].Redundancy)
  1889  	}
  1890  
  1891  	// Try again to download the file we uploaded. It should still be
  1892  	// retrievable.
  1893  	downloadPath3 := filepath.Join(st.dir, "test-downloaded-verify-3.dat")
  1894  	err = st.stdGetAPI("/renter/download/test?destination=" + downloadPath3)
  1895  	if err != nil {
  1896  		t.Error("Final download has failed:", err)
  1897  	}
  1898  	downloadBytes3, err := ioutil.ReadFile(downloadPath3)
  1899  	if err != nil {
  1900  		t.Error(err)
  1901  	}
  1902  	if !bytes.Equal(downloadBytes3, origBytes) {
  1903  		t.Error("downloaded file and uploaded file do not match")
  1904  	}
  1905  }
  1906  
  1907  // TestExhaustedContracts verifies that the contractor renews contracts which
  1908  // run out of funds before the period elapses.
  1909  func TestExhaustedContracts(t *testing.T) {
  1910  	if testing.Short() || !build.VLONG {
  1911  		t.SkipNow()
  1912  	}
  1913  	t.Parallel()
  1914  	st, err := createServerTester(t.Name())
  1915  	if err != nil {
  1916  		t.Fatal(err)
  1917  	}
  1918  	defer st.server.panicClose()
  1919  
  1920  	// set a very high price for the host so we use up the entire funds of the
  1921  	// contract
  1922  	err = st.acceptContracts()
  1923  	if err != nil {
  1924  		t.Fatal(err)
  1925  	}
  1926  	err = st.setHostStorage()
  1927  	if err != nil {
  1928  		t.Fatal(err)
  1929  	}
  1930  	// Increase the storage and bandwidth prices to drain the allowance faster.
  1931  	settings := st.host.InternalSettings()
  1932  	settings.MinUploadBandwidthPrice = settings.MinUploadBandwidthPrice.Mul64(2)
  1933  	settings.MinStoragePrice = settings.MinUploadBandwidthPrice.Mul64(2)
  1934  	settings.MaxDuration = 1e6 // set a high max duration to allow an expensive storage price
  1935  	err = st.host.SetInternalSettings(settings)
  1936  	if err != nil {
  1937  		t.Fatal(err)
  1938  	}
  1939  	err = st.announceHost()
  1940  	if err != nil {
  1941  		t.Fatal(err)
  1942  	}
  1943  
  1944  	// Set an allowance for the renter, allowing a contract to be formed.
  1945  	allowanceValues := url.Values{}
  1946  	testPeriod := "950000" // large period to cause an expensive test, exhausting the allowance faster
  1947  	allowanceValues.Set("funds", types.SiacoinPrecision.Mul64(10).String())
  1948  	allowanceValues.Set("period", testPeriod)
  1949  	err = st.stdPostAPI("/renter", allowanceValues)
  1950  	if err != nil {
  1951  		t.Fatal(err)
  1952  	}
  1953  
  1954  	// wait until we have a contract
  1955  	err = build.Retry(500, time.Millisecond*50, func() error {
  1956  		if len(st.renter.Contracts()) >= 1 {
  1957  			return nil
  1958  		}
  1959  		return errors.New("no renter contracts")
  1960  	})
  1961  	if err != nil {
  1962  		t.Fatal(err)
  1963  	}
  1964  	initialContract := st.renter.Contracts()[0]
  1965  
  1966  	// upload a file. the high upload cost will cause the underlying contract to
  1967  	// require premature renewal. If premature renewal never happens, the upload
  1968  	// will never complete.
  1969  	path := filepath.Join(st.dir, "randUploadFile")
  1970  	size := int(modules.SectorSize * 75)
  1971  	err = createRandFile(path, size)
  1972  	if err != nil {
  1973  		t.Fatal(err)
  1974  	}
  1975  	uploadValues := url.Values{}
  1976  	uploadValues.Set("source", path)
  1977  	uploadValues.Set("renew", "true")
  1978  	uploadValues.Set("datapieces", "1")
  1979  	uploadValues.Set("paritypieces", "1")
  1980  	err = st.stdPostAPI("/renter/upload/"+filepath.Base(path), uploadValues)
  1981  	if err != nil {
  1982  		t.Fatal(err)
  1983  	}
  1984  	err = build.Retry(100, time.Millisecond*500, func() error {
  1985  		// mine blocks each iteration to trigger contract maintenance
  1986  		_, err = st.miner.AddBlock()
  1987  		if err != nil {
  1988  			t.Fatal(err)
  1989  		}
  1990  
  1991  		st.miner.AddBlock()
  1992  		if !st.renter.FileList()[0].Available {
  1993  			return errors.New("file did not complete uploading")
  1994  		}
  1995  		return nil
  1996  	})
  1997  	if err != nil {
  1998  		t.Fatal(err)
  1999  	}
  2000  
  2001  	// verify that the window did not change and the contract ID did change
  2002  	newContract := st.renter.Contracts()[0]
  2003  	endHeight := newContract.EndHeight
  2004  	if newContract.ID == initialContract.ID {
  2005  		t.Error("renew did not occur")
  2006  	}
  2007  	if endHeight != initialContract.EndHeight {
  2008  		t.Error("contract end height changed, wanted", initialContract.EndHeight, "got", endHeight)
  2009  	}
  2010  }
  2011  
  2012  // TestAdversarialPriceRenewal verifies that host cannot maliciously raise
  2013  // their storage price in order to trigger a premature file contract renewal.
  2014  func TestAdversarialPriceRenewal(t *testing.T) {
  2015  	if testing.Short() || !build.VLONG {
  2016  		t.SkipNow()
  2017  	}
  2018  	t.Parallel()
  2019  	st, err := createServerTester(t.Name())
  2020  	if err != nil {
  2021  		t.Fatal(err)
  2022  	}
  2023  	defer st.server.panicClose()
  2024  
  2025  	// announce our host
  2026  	err = st.acceptContracts()
  2027  	if err != nil {
  2028  		t.Fatal(err)
  2029  	}
  2030  	err = st.setHostStorage()
  2031  	if err != nil {
  2032  		t.Fatal(err)
  2033  	}
  2034  	err = st.announceHost()
  2035  	if err != nil {
  2036  		t.Fatal(err)
  2037  	}
  2038  
  2039  	// Set an allowance for the renter, allowing a contract to be formed.
  2040  	allowanceValues := url.Values{}
  2041  	testPeriod := "10000"
  2042  	allowanceValues.Set("funds", types.SiacoinPrecision.Mul64(10000).String())
  2043  	allowanceValues.Set("period", testPeriod)
  2044  	err = st.stdPostAPI("/renter", allowanceValues)
  2045  	if err != nil {
  2046  		t.Fatal(err)
  2047  	}
  2048  
  2049  	// wait until we have a contract
  2050  	err = build.Retry(500, time.Millisecond*50, func() error {
  2051  		if len(st.renter.Contracts()) >= 1 {
  2052  			return nil
  2053  		}
  2054  		return errors.New("no renter contracts")
  2055  	})
  2056  	if err != nil {
  2057  		t.Fatal(err)
  2058  	}
  2059  
  2060  	// upload a file
  2061  	path := filepath.Join(st.dir, "randUploadFile")
  2062  	size := int(modules.SectorSize * 50)
  2063  	err = createRandFile(path, size)
  2064  	if err != nil {
  2065  		t.Fatal(err)
  2066  	}
  2067  	uploadValues := url.Values{}
  2068  	uploadValues.Set("source", path)
  2069  	uploadValues.Set("renew", "true")
  2070  	uploadValues.Set("datapieces", "1")
  2071  	uploadValues.Set("paritypieces", "1")
  2072  	err = st.stdPostAPI("/renter/upload/"+filepath.Base(path), uploadValues)
  2073  	if err != nil {
  2074  		t.Fatal(err)
  2075  	}
  2076  	err = build.Retry(100, time.Millisecond*500, func() error {
  2077  		// mine blocks each iteration to trigger contract maintenance
  2078  		_, err = st.miner.AddBlock()
  2079  		if err != nil {
  2080  			t.Fatal(err)
  2081  		}
  2082  		if !st.renter.FileList()[0].Available {
  2083  			return errors.New("file did not complete uploading")
  2084  		}
  2085  		return nil
  2086  	})
  2087  	if err != nil {
  2088  		t.Fatal(err)
  2089  	}
  2090  	initialID := st.renter.Contracts()[0].ID
  2091  
  2092  	// jack up the host's storage price to try to trigger a renew
  2093  	settings := st.host.InternalSettings()
  2094  	settings.MinStoragePrice = settings.MinStoragePrice.Mul64(10800000000)
  2095  	err = st.host.SetInternalSettings(settings)
  2096  	if err != nil {
  2097  		t.Fatal(err)
  2098  	}
  2099  	err = st.announceHost()
  2100  	if err != nil {
  2101  		t.Fatal(err)
  2102  	}
  2103  
  2104  	for i := 0; i < 100; i++ {
  2105  		_, err = st.miner.AddBlock()
  2106  		if err != nil {
  2107  			t.Fatal(err)
  2108  		}
  2109  		if st.renter.Contracts()[0].ID != initialID {
  2110  			t.Fatal("changing host price caused renew")
  2111  		}
  2112  		time.Sleep(time.Millisecond * 100)
  2113  	}
  2114  }