gitlab.com/SiaPrime/SiaPrime@v1.4.1/node/api/renter_test.go (about)

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