gitlab.com/SiaPrime/SiaPrime@v1.4.1/modules/host/contractmanager/persist_test.go (about)

     1  package contractmanager
     2  
     3  import (
     4  	"bytes"
     5  	"os"
     6  	"path/filepath"
     7  	"sync"
     8  	"testing"
     9  	"time"
    10  
    11  	"gitlab.com/SiaPrime/SiaPrime/crypto"
    12  	"gitlab.com/SiaPrime/SiaPrime/modules"
    13  )
    14  
    15  // dependencyNoRecheck prevents the recheck loop from running in the contract
    16  // manager.
    17  type dependencyNoRecheck struct {
    18  	modules.ProductionDependencies
    19  }
    20  
    21  // disrupt prevents the recheck loop from running in the contract manager.
    22  func (*dependencyNoRecheck) Disrupt(s string) bool {
    23  	if s == "noRecheck" {
    24  		return true
    25  	}
    26  	return false
    27  }
    28  
    29  // TestLoadMissingStorageFolder checks that loading a storage folder which is
    30  // missing doesn't result in a complete loss of the storage folder on subsequent
    31  // startups.
    32  func TestLoadMissingStorageFolder(t *testing.T) {
    33  	if testing.Short() {
    34  		t.SkipNow()
    35  	}
    36  	t.Parallel()
    37  	cmt, err := newContractManagerTester(t.Name())
    38  	if err != nil {
    39  		t.Fatal(err)
    40  	}
    41  	defer cmt.panicClose()
    42  
    43  	// Add a storage folder to the contract manager tester.
    44  	storageFolderDir := filepath.Join(cmt.persistDir, "storageFolderOne")
    45  	// Create the storage folder dir.
    46  	err = os.MkdirAll(storageFolderDir, 0700)
    47  	if err != nil {
    48  		t.Fatal(err)
    49  	}
    50  	err = cmt.cm.AddStorageFolder(storageFolderDir, modules.SectorSize*storageFolderGranularity*2)
    51  	if err != nil {
    52  		t.Fatal(err)
    53  	}
    54  
    55  	// Check that the storage folder has been added.
    56  	sfs := cmt.cm.StorageFolders()
    57  	if len(sfs) != 1 {
    58  		t.Fatal("There should be one storage folder reported")
    59  	}
    60  	// Check that the storage folder has the right path and size.
    61  	if sfs[0].Path != storageFolderDir {
    62  		t.Error("storage folder reported with wrong path")
    63  	}
    64  	if sfs[0].Capacity != modules.SectorSize*storageFolderGranularity*2 {
    65  		t.Error("storage folder reported with wrong sector size")
    66  	}
    67  
    68  	// Add a sector to the storage folder.
    69  	root, data := randSector()
    70  	err = cmt.cm.AddSector(root, data)
    71  	if err != nil {
    72  		t.Fatal(err)
    73  	}
    74  
    75  	// Check that the sector was successfully added.
    76  	sfs = cmt.cm.StorageFolders()
    77  	if len(sfs) != 1 {
    78  		t.Fatal("There should be one storage folder in the contract manager", len(sfs))
    79  	}
    80  	if sfs[0].Capacity != sfs[0].CapacityRemaining+modules.SectorSize {
    81  		t.Error("One sector's worth of capacity should be consumed:", sfs[0].Capacity, sfs[0].CapacityRemaining)
    82  	}
    83  	sfOneIndex := sfs[0].Index
    84  
    85  	// Try reloading the contract manager after the storage folder has been
    86  	// moved somewhere else.
    87  	err = cmt.cm.Close()
    88  	if err != nil {
    89  		t.Fatal(err)
    90  	}
    91  	// Move the storage folder directory to a new location - hiding it from the
    92  	// contract manager.
    93  	err = os.Rename(storageFolderDir, storageFolderDir+"-moved")
    94  	if err != nil {
    95  		t.Fatal(err)
    96  	}
    97  	// Re-open the contract manager.
    98  	d := new(dependencyNoRecheck)
    99  	cmt.cm, err = newContractManager(d, filepath.Join(cmt.persistDir, modules.ContractManagerDir))
   100  	if err != nil {
   101  		t.Fatal(err)
   102  	}
   103  	// The contract manager should still be reporting the storage folder, but
   104  	// with errors reported.
   105  	sfs = cmt.cm.StorageFolders()
   106  	if len(sfs) != 1 {
   107  		t.Fatal("wrong number of storage folders being reported")
   108  	}
   109  	if sfs[0].FailedReads < 100000000 {
   110  		t.Error("Not enough failures reported for absent storage folder")
   111  	}
   112  	if sfs[0].FailedWrites < 100000000 {
   113  		t.Error("Not enough failures reported for absent storage folder")
   114  	}
   115  	if sfs[0].Capacity != sfs[0].CapacityRemaining+modules.SectorSize {
   116  		t.Error("One sector's worth of capacity should be consumed:", sfs[0].Capacity, sfs[0].CapacityRemaining)
   117  	}
   118  
   119  	// Reload the contract manager and make sure the storage folder is still
   120  	// there.
   121  	err = cmt.cm.Close()
   122  	if err != nil {
   123  		t.Fatal(err)
   124  	}
   125  	// Re-open the contract manager.
   126  	cmt.cm, err = newContractManager(d, filepath.Join(cmt.persistDir, modules.ContractManagerDir))
   127  	if err != nil {
   128  		t.Fatal(err)
   129  	}
   130  	// The contract manager should still be reporting the storage folder with
   131  	// errors.
   132  	sfs = cmt.cm.StorageFolders()
   133  	if len(sfs) != 1 {
   134  		t.Fatal("wrong number of storage folders being reported")
   135  	}
   136  	if sfs[0].FailedReads < 100000000 {
   137  		t.Error("Not enough failures reported for absent storage folder")
   138  	}
   139  	if sfs[0].FailedWrites < 100000000 {
   140  		t.Error("Not enough failures reported for absent storage folder")
   141  	}
   142  
   143  	// Try reading the sector from the missing storage folder.
   144  	_, err = cmt.cm.ReadSector(root)
   145  	if err == nil {
   146  		t.Fatal("Expecting error when reading missing sector.")
   147  	}
   148  
   149  	// Try adding a sector to the contract manager - no folder can receive it.
   150  	rootF, dataF := randSector()
   151  	err = cmt.cm.AddSector(rootF, dataF)
   152  	if err == nil {
   153  		t.Error("should not be able to add sector")
   154  	}
   155  
   156  	// Check that you can add folders, add sectors while the contract manager
   157  	// correctly works around the missing storage folder.
   158  	storageFolderTwo := filepath.Join(cmt.persistDir, "storageFolderTwo")
   159  	err = os.MkdirAll(storageFolderTwo, 0700)
   160  	if err != nil {
   161  		t.Fatal(err)
   162  	}
   163  	err = cmt.cm.AddStorageFolder(storageFolderTwo, modules.SectorSize*storageFolderGranularity*2)
   164  	if err != nil {
   165  		t.Fatal(err)
   166  	}
   167  	// Add a sector to the storage folder.
   168  	root2, data2 := randSector()
   169  	err = cmt.cm.AddSector(root2, data2)
   170  	if err != nil {
   171  		t.Fatal(err)
   172  	}
   173  	// Check that the sector was successfully added.
   174  	sfs = cmt.cm.StorageFolders()
   175  	if len(sfs) != 2 {
   176  		t.Fatal("There should be one storage folder in the contract manager", len(sfs))
   177  	}
   178  	for i := range sfs {
   179  		if sfs[i].Capacity != sfs[i].CapacityRemaining+modules.SectorSize {
   180  			t.Error("One sector's worth of capacity should be consumed:", sfs[i].Capacity, sfs[i].CapacityRemaining, sfs[i].Path)
   181  		}
   182  	}
   183  	var sfTwoIndex uint16
   184  	if sfs[0].Index == sfOneIndex {
   185  		sfTwoIndex = sfs[1].Index
   186  	} else {
   187  		sfTwoIndex = sfs[0].Index
   188  	}
   189  
   190  	// Add two more sectors.
   191  	root3, data3 := randSector()
   192  	err = cmt.cm.AddSector(root3, data3)
   193  	if err != nil {
   194  		t.Fatal(err)
   195  	}
   196  	root4, data4 := randSector()
   197  	err = cmt.cm.AddSector(root4, data4)
   198  	if err != nil {
   199  		t.Fatal(err)
   200  	}
   201  	// Check that the sector was successfully added.
   202  	sfs = cmt.cm.StorageFolders()
   203  	if len(sfs) != 2 {
   204  		t.Fatal("There should be one storage folder in the contract manager", len(sfs))
   205  	}
   206  	if sfs[0].Capacity != sfs[0].CapacityRemaining+modules.SectorSize*3 && sfs[1].Capacity != sfs[1].CapacityRemaining+modules.SectorSize*3 {
   207  		t.Error("One sector's worth of capacity should be consumed")
   208  	}
   209  
   210  	// Try to shrink the missing storage folder.
   211  	err = cmt.cm.ResizeStorageFolder(sfOneIndex, modules.SectorSize*storageFolderGranularity, false)
   212  	if err == nil {
   213  		t.Fatal("should not be able to resize a missing storage folder")
   214  	}
   215  	err = cmt.cm.ResizeStorageFolder(sfOneIndex, modules.SectorSize*storageFolderGranularity, true)
   216  	if err == nil {
   217  		t.Fatal("should not be able to resize a missing storage folder")
   218  	}
   219  
   220  	// Check that the storage folder is still the original size.
   221  	sfs = cmt.cm.StorageFolders()
   222  	if len(sfs) != 2 {
   223  		t.Fatal("wrong storage folder count")
   224  	}
   225  	if sfs[0].Index == sfOneIndex && sfs[0].Capacity != modules.SectorSize*storageFolderGranularity*2 {
   226  		t.Error("Storage folder has wrong size after failing to resize")
   227  	}
   228  	if sfs[1].Index == sfOneIndex && sfs[1].Capacity != modules.SectorSize*storageFolderGranularity*2 {
   229  		t.Error("Storage folder has wrong size after failing to resize")
   230  	}
   231  
   232  	// Try to grow the missing storage folder.
   233  	err = cmt.cm.ResizeStorageFolder(sfOneIndex, modules.SectorSize*storageFolderGranularity*4, false)
   234  	if err == nil {
   235  		t.Fatal("should not be able to resize a missing storage folder")
   236  	}
   237  	err = cmt.cm.ResizeStorageFolder(sfOneIndex, modules.SectorSize*storageFolderGranularity*4, true)
   238  	if err == nil {
   239  		t.Fatal("should not be able to resize a missing storage folder")
   240  	}
   241  
   242  	// Check that the storage folder is still the original size.
   243  	sfs = cmt.cm.StorageFolders()
   244  	if len(sfs) != 2 {
   245  		t.Fatal("wrong storage folder count")
   246  	}
   247  	if sfs[0].Index == sfOneIndex && sfs[0].Capacity != modules.SectorSize*storageFolderGranularity*2 {
   248  		t.Error("Storage folder has wrong size after failing to resize")
   249  	}
   250  	if sfs[1].Index == sfOneIndex && sfs[1].Capacity != modules.SectorSize*storageFolderGranularity*2 {
   251  		t.Error("Storage folder has wrong size after failing to resize")
   252  	}
   253  
   254  	// Check that you can delete sectors and have the contract manager work
   255  	// correctly around the missing storage folder.
   256  	err = cmt.cm.DeleteSector(root2)
   257  	if err != nil {
   258  		t.Fatal(err)
   259  	}
   260  	err = cmt.cm.DeleteSector(root3)
   261  	if err != nil {
   262  		t.Fatal(err)
   263  	}
   264  	err = cmt.cm.DeleteSector(root4)
   265  	if err != nil {
   266  		t.Fatal(err)
   267  	}
   268  	// Check that the sectors are no longer reported.
   269  	sfs = cmt.cm.StorageFolders()
   270  	if len(sfs) != 2 {
   271  		t.Fatal("There should be one storage folder in the contract manager", len(sfs))
   272  	}
   273  	if sfs[0].Capacity != sfs[0].CapacityRemaining && sfs[1].Capacity != sfs[1].CapacityRemaining {
   274  		t.Error("Deleted sector does not seem to have been deleted correctly.")
   275  	}
   276  	// Try reading the deleted sector.
   277  	_, err = cmt.cm.ReadSector(root2)
   278  	if err == nil {
   279  		t.Fatal("should get an error when reading a deleted sector")
   280  	}
   281  
   282  	// Check that it's okay to shrink a storage folder while missing a storage
   283  	// folder.
   284  	//
   285  	// Start by resizing the second storage folder so it can hold a lot of
   286  	// sectors.
   287  	err = cmt.cm.ResizeStorageFolder(sfTwoIndex, modules.SectorSize*storageFolderGranularity*4, false)
   288  	if err != nil {
   289  		t.Fatal(err)
   290  	}
   291  	// Add enough sectors to the storage folder that doing a shrink operation
   292  	// causes sectors to be moved around.
   293  	num := int(storageFolderGranularity*3 + 2)
   294  	roots := make([]crypto.Hash, num)
   295  	datas := make([][]byte, num)
   296  	var wg sync.WaitGroup // Add in parallel to get massive performance boost.
   297  	for i := 0; i < num; i++ {
   298  		wg.Add(1)
   299  		go func(i int) {
   300  			defer wg.Done()
   301  			rootI, dataI := randSector()
   302  			roots[i] = rootI
   303  			datas[i] = dataI
   304  			err := cmt.cm.AddSector(rootI, dataI)
   305  			if err != nil {
   306  				t.Fatal(err)
   307  			}
   308  		}(i)
   309  	}
   310  	wg.Wait()
   311  	// Make a new storage folder so the sectors have somewhere to go.
   312  	storageFolderThree := filepath.Join(cmt.persistDir, "storageFolderThree")
   313  	err = os.MkdirAll(storageFolderThree, 0700)
   314  	if err != nil {
   315  		t.Fatal(err)
   316  	}
   317  	err = cmt.cm.AddStorageFolder(storageFolderThree, modules.SectorSize*storageFolderGranularity)
   318  	if err != nil {
   319  		t.Fatal(err)
   320  	}
   321  	// Shrink the second storage folder such that some of the sectors are forced
   322  	// to move.
   323  	err = cmt.cm.ResizeStorageFolder(sfTwoIndex, modules.SectorSize*storageFolderGranularity*3, false)
   324  	if err != nil {
   325  		t.Fatal(err)
   326  	}
   327  	// Check that all of the sectors are still recoverable.
   328  	for i := range roots {
   329  		data, err := cmt.cm.ReadSector(roots[i])
   330  		if err != nil {
   331  			t.Fatal(err)
   332  		}
   333  		if !bytes.Equal(data, datas[i]) {
   334  			t.Error("read sector does not have the same data that was inserted")
   335  		}
   336  	}
   337  
   338  	// Shrink the second storage folder again, such that there is not enough
   339  	// room in the available storage folders to accept the data.
   340  	err = cmt.cm.ResizeStorageFolder(sfTwoIndex, modules.SectorSize*storageFolderGranularity*2, false)
   341  	if err == nil {
   342  		t.Fatal("expected an error")
   343  	}
   344  	// Check that all of the sectors are still recoverable.
   345  	for i := range roots {
   346  		data, err := cmt.cm.ReadSector(roots[i])
   347  		if err != nil {
   348  			t.Fatal(err)
   349  		}
   350  		if !bytes.Equal(data, datas[i]) {
   351  			t.Error("read sector does not have the same data that was inserted")
   352  		}
   353  	}
   354  
   355  	// Shrink the second storage folder again, such that there is not enough
   356  	// room in the available storage folders to accept the data.
   357  	err = cmt.cm.ResizeStorageFolder(sfTwoIndex, modules.SectorSize*storageFolderGranularity, true)
   358  	if err != nil {
   359  		t.Fatal(err)
   360  	}
   361  	// There is now data loss.
   362  
   363  	// Try deleting the second storage folder, which again will cause data loss.
   364  	err = cmt.cm.RemoveStorageFolder(sfTwoIndex, false)
   365  	if err == nil {
   366  		t.Fatal("should have gotten an error when trying to remove the storage folder.")
   367  	}
   368  	err = cmt.cm.RemoveStorageFolder(sfTwoIndex, true)
   369  	if err != nil {
   370  		t.Fatal(err)
   371  	}
   372  
   373  	// Try to recover the missing storage folder by closing and moving the
   374  	// storage folder to the right place.
   375  	err = cmt.cm.Close()
   376  	if err != nil {
   377  		t.Fatal(err)
   378  	}
   379  	err = os.Rename(storageFolderDir+"-moved", storageFolderDir)
   380  	if err != nil {
   381  		t.Fatal(err)
   382  	}
   383  	// Re-open the contract manager.
   384  	cmt.cm, err = newContractManager(d, filepath.Join(cmt.persistDir, modules.ContractManagerDir))
   385  	if err != nil {
   386  		t.Fatal(err)
   387  	}
   388  	// The contract manager should still be reporting the storage folder, but
   389  	// with errors reported.
   390  	sfs = cmt.cm.StorageFolders()
   391  	if len(sfs) != 2 {
   392  		t.Fatal("wrong number of storage folders being reported")
   393  	}
   394  	var sfOne modules.StorageFolderMetadata
   395  	for _, sf := range sfs {
   396  		if sf.Index == sfOneIndex {
   397  			sfOne = sf
   398  		}
   399  	}
   400  	if sfOne.FailedReads > 0 {
   401  		t.Error("folder should be visible again")
   402  	}
   403  	if sfOne.FailedWrites > 0 {
   404  		t.Error("folder should be visible again")
   405  	}
   406  	if sfOne.Capacity != sfOne.CapacityRemaining+modules.SectorSize {
   407  		cmt.cm.wal.mu.Lock()
   408  		t.Log("Usage len:", len(cmt.cm.storageFolders[sfOne.Index].usage))
   409  		t.Log("Reported Sectors:", cmt.cm.storageFolders[sfOne.Index].sectors)
   410  		t.Log("Avail:", len(cmt.cm.storageFolders[sfOne.Index].availableSectors))
   411  		cmt.cm.wal.mu.Unlock()
   412  		t.Error("One sector's worth of capacity should be consumed:", sfOne.Capacity, sfOne.CapacityRemaining)
   413  	}
   414  
   415  	// See if the sector is still available.
   416  	recoveredData, err := cmt.cm.ReadSector(root)
   417  	if err != nil {
   418  		t.Fatal(err)
   419  	}
   420  	if !bytes.Equal(recoveredData, data) {
   421  		t.Error("recovered data is not equal to original data")
   422  	}
   423  
   424  	// Redo the storage folder move, so we can test deleting a missing storage
   425  	// folder.
   426  	err = cmt.cm.Close()
   427  	if err != nil {
   428  		t.Fatal(err)
   429  	}
   430  	// Move the storage folder directory to a new location - hiding it from the
   431  	// contract manager.
   432  	err = os.Rename(storageFolderDir, storageFolderDir+"-moved")
   433  	if err != nil {
   434  		t.Fatal(err)
   435  	}
   436  	// Re-open the contract manager.
   437  	cmt.cm, err = newContractManager(d, filepath.Join(cmt.persistDir, modules.ContractManagerDir))
   438  	if err != nil {
   439  		t.Fatal(err)
   440  	}
   441  
   442  	// Try removing the storage folder without the --force option. It should
   443  	// fail.
   444  	err = cmt.cm.RemoveStorageFolder(sfOneIndex, false)
   445  	if err == nil {
   446  		t.Fatal("should have gotten an error")
   447  	}
   448  	sfs = cmt.cm.StorageFolders()
   449  	if len(sfs) != 2 {
   450  		t.Error("there should be two storage folders after a removal failed.")
   451  	}
   452  	err = cmt.cm.RemoveStorageFolder(sfOneIndex, true)
   453  	if err != nil {
   454  		t.Fatal(err)
   455  	}
   456  	sfs = cmt.cm.StorageFolders()
   457  	if len(sfs) != 1 {
   458  		t.Error("there should be only one storage folder remaining")
   459  	}
   460  
   461  	// Close and re-open the contract maanger, storage folder should still be
   462  	// missing.
   463  	err = cmt.cm.Close()
   464  	if err != nil {
   465  		t.Fatal(err)
   466  	}
   467  	// Re-open the contract manager.
   468  	cmt.cm, err = newContractManager(d, filepath.Join(cmt.persistDir, modules.ContractManagerDir))
   469  	if err != nil {
   470  		t.Fatal(err)
   471  	}
   472  	sfs = cmt.cm.StorageFolders()
   473  	if len(sfs) != 1 {
   474  		t.Error("there should be only one storage folder remaining")
   475  	}
   476  }
   477  
   478  // TestFolderRechecker verifies that the folder rechecker is able to discover
   479  // when a storage folder has become available again.
   480  func TestFolderRechecker(t *testing.T) {
   481  	if testing.Short() {
   482  		t.SkipNow()
   483  	}
   484  	t.Parallel()
   485  	cmt, err := newContractManagerTester(t.Name())
   486  	if err != nil {
   487  		t.Fatal(err)
   488  	}
   489  	defer cmt.panicClose()
   490  
   491  	// Add a storage folder to the contract manager tester.
   492  	storageFolderDir := filepath.Join(cmt.persistDir, "storageFolderOne")
   493  	// Create the storage folder dir.
   494  	err = os.MkdirAll(storageFolderDir, 0700)
   495  	if err != nil {
   496  		t.Fatal(err)
   497  	}
   498  	err = cmt.cm.AddStorageFolder(storageFolderDir, modules.SectorSize*storageFolderGranularity*2)
   499  	if err != nil {
   500  		t.Fatal(err)
   501  	}
   502  
   503  	// Check that the storage folder has been added.
   504  	sfs := cmt.cm.StorageFolders()
   505  	if len(sfs) != 1 {
   506  		t.Fatal("There should be one storage folder reported")
   507  	}
   508  	// Check that the storage folder has the right path and size.
   509  	if sfs[0].Path != storageFolderDir {
   510  		t.Error("storage folder reported with wrong path")
   511  	}
   512  	if sfs[0].Capacity != modules.SectorSize*storageFolderGranularity*2 {
   513  		t.Error("storage folder reported with wrong sector size")
   514  	}
   515  
   516  	// Add a sector to the storage folder.
   517  	root, data := randSector()
   518  	err = cmt.cm.AddSector(root, data)
   519  	if err != nil {
   520  		t.Fatal(err)
   521  	}
   522  
   523  	// Check that the sector was successfully added.
   524  	sfs = cmt.cm.StorageFolders()
   525  	if len(sfs) != 1 {
   526  		t.Fatal("There should be one storage folder in the contract manager", len(sfs))
   527  	}
   528  	if sfs[0].Capacity != sfs[0].CapacityRemaining+modules.SectorSize {
   529  		t.Error("One sector's worth of capacity should be consumed:", sfs[0].Capacity, sfs[0].CapacityRemaining)
   530  	}
   531  
   532  	// Try reloading the contract manager after the storage folder has been
   533  	// moved somewhere else.
   534  	err = cmt.cm.Close()
   535  	if err != nil {
   536  		t.Fatal(err)
   537  	}
   538  	// Move the storage folder directory to a new location - hiding it from the
   539  	// contract manager.
   540  	err = os.Rename(storageFolderDir, storageFolderDir+"-moved")
   541  	if err != nil {
   542  		t.Fatal(err)
   543  	}
   544  	// Re-open the contract manager.
   545  	cmt.cm, err = New(filepath.Join(cmt.persistDir, modules.ContractManagerDir))
   546  	if err != nil {
   547  		t.Fatal(err)
   548  	}
   549  	// The contract manager should still be reporting the storage folder, but
   550  	// with errors reported.
   551  	sfs = cmt.cm.StorageFolders()
   552  	if len(sfs) != 1 {
   553  		t.Fatal("wrong number of storage folders being reported")
   554  	}
   555  	if sfs[0].FailedReads < 100000000 {
   556  		t.Error("Not enough failures reported for absent storage folder")
   557  	}
   558  	if sfs[0].FailedWrites < 100000000 {
   559  		t.Error("Not enough failures reported for absent storage folder")
   560  	}
   561  	if sfs[0].Capacity != sfs[0].CapacityRemaining+modules.SectorSize {
   562  		t.Error("One sector's worth of capacity should be consumed:", sfs[0].Capacity, sfs[0].CapacityRemaining)
   563  	}
   564  
   565  	// Move the storage folder back to where the contract manager can see it.
   566  	err = os.Rename(storageFolderDir+"-moved", storageFolderDir)
   567  	if err != nil {
   568  		t.Fatal(err)
   569  	}
   570  
   571  	// Sleep until the rechecker can find the storage folder.
   572  	time.Sleep(maxFolderRecheckInterval)
   573  
   574  	// Check that the storage folder has been found by the rechecker.
   575  	sfs = cmt.cm.StorageFolders()
   576  	if len(sfs) != 1 {
   577  		t.Fatal("wrong number of storage folders being reported")
   578  	}
   579  	if sfs[0].FailedReads != 0 {
   580  		t.Error("Not enough failures reported for absent storage folder")
   581  	}
   582  	if sfs[0].FailedWrites != 0 {
   583  		t.Error("Not enough failures reported for absent storage folder")
   584  	}
   585  	if sfs[0].Capacity != sfs[0].CapacityRemaining+modules.SectorSize {
   586  		t.Error("One sector's worth of capacity should be consumed:", sfs[0].Capacity, sfs[0].CapacityRemaining)
   587  	}
   588  
   589  	// Check that the sector is once again available.
   590  	recoveredData, err := cmt.cm.ReadSector(root)
   591  	if err != nil {
   592  		t.Fatal(err)
   593  	}
   594  	if !bytes.Equal(recoveredData, data) {
   595  		t.Error("recovered data does not equal original data")
   596  	}
   597  
   598  	// Try adding a sector to the contract manager - no folder can receive it.
   599  	root2, data2 := randSector()
   600  	err = cmt.cm.AddSector(root2, data2)
   601  	if err != nil {
   602  		t.Error("should not be able to add sector")
   603  	}
   604  	recoveredData, err = cmt.cm.ReadSector(root2)
   605  	if err != nil {
   606  		t.Fatal(err)
   607  	}
   608  	if !bytes.Equal(recoveredData, data2) {
   609  		t.Error("recovered data does not equal original data")
   610  	}
   611  
   612  	// Grow the storage folder.
   613  	err = cmt.cm.ResizeStorageFolder(sfs[0].Index, modules.SectorSize*storageFolderGranularity*4, false)
   614  	if err != nil {
   615  		t.Fatal(err)
   616  	}
   617  	sfs = cmt.cm.StorageFolders()
   618  	if len(sfs) != 1 {
   619  		t.Fatal("wrong number of storage folders being reported")
   620  	}
   621  	if sfs[0].Capacity != sfs[0].CapacityRemaining+modules.SectorSize*2 {
   622  		t.Error("One sector's worth of capacity should be consumed:", sfs[0].Capacity, sfs[0].CapacityRemaining)
   623  	}
   624  	if sfs[0].Capacity != modules.SectorSize*storageFolderGranularity*4 {
   625  		t.Error("the storage folder growth does not seem to have worked")
   626  	}
   627  
   628  	// Restart the client. Sector should still be readable, storage folder
   629  	// should still be grown.
   630  	err = cmt.cm.Close()
   631  	if err != nil {
   632  		t.Fatal(err)
   633  	}
   634  	cmt.cm, err = New(filepath.Join(cmt.persistDir, modules.ContractManagerDir))
   635  	if err != nil {
   636  		t.Fatal(err)
   637  	}
   638  	// Check that the sector is once again available.
   639  	recoveredData, err = cmt.cm.ReadSector(root)
   640  	if err != nil {
   641  		t.Fatal(err)
   642  	}
   643  	if !bytes.Equal(recoveredData, data) {
   644  		t.Error("recovered data does not equal original data")
   645  	}
   646  	sfs = cmt.cm.StorageFolders()
   647  	if len(sfs) != 1 {
   648  		t.Fatal("wrong number of storage folders being reported")
   649  	}
   650  	if sfs[0].Capacity != sfs[0].CapacityRemaining+modules.SectorSize*2 {
   651  		t.Error("One sector's worth of capacity should be consumed:", sfs[0].Capacity, sfs[0].CapacityRemaining)
   652  	}
   653  	if sfs[0].Capacity != modules.SectorSize*storageFolderGranularity*4 {
   654  		t.Error("the storage folder growth does not seem to have worked")
   655  	}
   656  }