gitlab.com/jokerrs1/Sia@v1.3.2/modules/renter/renter_test.go (about)

     1  package renter
     2  
     3  import (
     4  	"path/filepath"
     5  	"reflect"
     6  	"testing"
     7  
     8  	"github.com/NebulousLabs/Sia/build"
     9  	"github.com/NebulousLabs/Sia/crypto"
    10  	"github.com/NebulousLabs/Sia/modules"
    11  	"github.com/NebulousLabs/Sia/modules/consensus"
    12  	"github.com/NebulousLabs/Sia/modules/gateway"
    13  	"github.com/NebulousLabs/Sia/modules/miner"
    14  	"github.com/NebulousLabs/Sia/modules/renter/contractor"
    15  	"github.com/NebulousLabs/Sia/modules/transactionpool"
    16  	"github.com/NebulousLabs/Sia/modules/wallet"
    17  	"github.com/NebulousLabs/Sia/types"
    18  )
    19  
    20  // renterTester contains all of the modules that are used while testing the renter.
    21  type renterTester struct {
    22  	cs        modules.ConsensusSet
    23  	gateway   modules.Gateway
    24  	miner     modules.TestMiner
    25  	tpool     modules.TransactionPool
    26  	wallet    modules.Wallet
    27  	walletKey crypto.TwofishKey
    28  
    29  	renter *Renter
    30  }
    31  
    32  // Close shuts down the renter tester.
    33  func (rt *renterTester) Close() error {
    34  	rt.wallet.Lock()
    35  	rt.cs.Close()
    36  	rt.gateway.Close()
    37  	return nil
    38  }
    39  
    40  // newRenterTester creates a ready-to-use renter tester with money in the
    41  // wallet.
    42  func newRenterTester(name string) (*renterTester, error) {
    43  	// Create the modules.
    44  	testdir := build.TempDir("renter", name)
    45  	g, err := gateway.New("localhost:0", false, filepath.Join(testdir, modules.GatewayDir))
    46  	if err != nil {
    47  		return nil, err
    48  	}
    49  	cs, err := consensus.New(g, false, filepath.Join(testdir, modules.ConsensusDir))
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  	tp, err := transactionpool.New(cs, g, filepath.Join(testdir, modules.TransactionPoolDir))
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  	w, err := wallet.New(cs, tp, filepath.Join(testdir, modules.WalletDir))
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  	key := crypto.GenerateTwofishKey()
    62  	_, err = w.Encrypt(key)
    63  	if err != nil {
    64  		return nil, err
    65  	}
    66  	err = w.Unlock(key)
    67  	if err != nil {
    68  		return nil, err
    69  	}
    70  	r, err := New(g, cs, w, tp, filepath.Join(testdir, modules.RenterDir))
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  	m, err := miner.New(cs, tp, w, filepath.Join(testdir, modules.MinerDir))
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  
    79  	// Assemble all pieces into a renter tester.
    80  	rt := &renterTester{
    81  		cs:      cs,
    82  		gateway: g,
    83  		miner:   m,
    84  		tpool:   tp,
    85  		wallet:  w,
    86  
    87  		renter: r,
    88  	}
    89  
    90  	// Mine blocks until there is money in the wallet.
    91  	for i := types.BlockHeight(0); i <= types.MaturityDelay; i++ {
    92  		_, err := rt.miner.AddBlock()
    93  		if err != nil {
    94  			return nil, err
    95  		}
    96  	}
    97  	return rt, nil
    98  }
    99  
   100  // newContractorTester creates a renterTester, but with the supplied
   101  // hostContractor.
   102  func newContractorTester(name string, hdb hostDB, hc hostContractor) (*renterTester, error) {
   103  	// Create the modules.
   104  	testdir := build.TempDir("renter", name)
   105  	g, err := gateway.New("localhost:0", false, filepath.Join(testdir, modules.GatewayDir))
   106  	if err != nil {
   107  		return nil, err
   108  	}
   109  	cs, err := consensus.New(g, false, filepath.Join(testdir, modules.ConsensusDir))
   110  	if err != nil {
   111  		return nil, err
   112  	}
   113  	tp, err := transactionpool.New(cs, g, filepath.Join(testdir, modules.TransactionPoolDir))
   114  	if err != nil {
   115  		return nil, err
   116  	}
   117  	w, err := wallet.New(cs, tp, filepath.Join(testdir, modules.WalletDir))
   118  	if err != nil {
   119  		return nil, err
   120  	}
   121  	key := crypto.GenerateTwofishKey()
   122  	_, err = w.Encrypt(key)
   123  	if err != nil {
   124  		return nil, err
   125  	}
   126  	err = w.Unlock(key)
   127  	if err != nil {
   128  		return nil, err
   129  	}
   130  	r, err := newRenter(g, cs, tp, hdb, hc, filepath.Join(testdir, modules.RenterDir))
   131  	if err != nil {
   132  		return nil, err
   133  	}
   134  	m, err := miner.New(cs, tp, w, filepath.Join(testdir, modules.MinerDir))
   135  	if err != nil {
   136  		return nil, err
   137  	}
   138  
   139  	// Assemble all pieces into a renter tester.
   140  	rt := &renterTester{
   141  		cs:      cs,
   142  		gateway: g,
   143  		miner:   m,
   144  		tpool:   tp,
   145  		wallet:  w,
   146  
   147  		renter: r,
   148  	}
   149  
   150  	// Mine blocks until there is money in the wallet.
   151  	for i := types.BlockHeight(0); i <= types.MaturityDelay; i++ {
   152  		_, err := rt.miner.AddBlock()
   153  		if err != nil {
   154  			return nil, err
   155  		}
   156  	}
   157  	return rt, nil
   158  }
   159  
   160  // stubHostDB is the minimal implementation of the hostDB interface. It can be
   161  // embedded in other mock hostDB types, removing the need to reimplement all
   162  // of the hostDB's methods on every mock.
   163  type stubHostDB struct{}
   164  
   165  func (stubHostDB) ActiveHosts() []modules.HostDBEntry   { return nil }
   166  func (stubHostDB) AllHosts() []modules.HostDBEntry      { return nil }
   167  func (stubHostDB) AverageContractPrice() types.Currency { return types.Currency{} }
   168  func (stubHostDB) Close() error                         { return nil }
   169  func (stubHostDB) IsOffline(modules.NetAddress) bool    { return true }
   170  func (stubHostDB) RandomHosts(int, []types.SiaPublicKey) []modules.HostDBEntry {
   171  	return []modules.HostDBEntry{}
   172  }
   173  func (stubHostDB) EstimateHostScore(modules.HostDBEntry) modules.HostScoreBreakdown {
   174  	return modules.HostScoreBreakdown{}
   175  }
   176  func (stubHostDB) Host(types.SiaPublicKey) (modules.HostDBEntry, bool) {
   177  	return modules.HostDBEntry{}, false
   178  }
   179  func (stubHostDB) ScoreBreakdown(modules.HostDBEntry) modules.HostScoreBreakdown {
   180  	return modules.HostScoreBreakdown{}
   181  }
   182  
   183  // stubContractor is the minimal implementation of the hostContractor
   184  // interface.
   185  type stubContractor struct{}
   186  
   187  func (stubContractor) SetAllowance(modules.Allowance) error { return nil }
   188  func (stubContractor) Allowance() modules.Allowance         { return modules.Allowance{} }
   189  func (stubContractor) Contract(modules.NetAddress) (modules.RenterContract, bool) {
   190  	return modules.RenterContract{}, false
   191  }
   192  func (stubContractor) Contracts() []modules.RenterContract                    { return nil }
   193  func (stubContractor) CurrentPeriod() types.BlockHeight                       { return 0 }
   194  func (stubContractor) IsOffline(modules.NetAddress) bool                      { return false }
   195  func (stubContractor) Editor(types.FileContractID) (contractor.Editor, error) { return nil, nil }
   196  func (stubContractor) Downloader(types.FileContractID) (contractor.Downloader, error) {
   197  	return nil, nil
   198  }
   199  
   200  type pricesStub struct {
   201  	stubHostDB
   202  
   203  	dbEntries []modules.HostDBEntry
   204  }
   205  
   206  func (ps pricesStub) RandomHosts(n int, exclude []types.SiaPublicKey) []modules.HostDBEntry {
   207  	return ps.dbEntries
   208  }
   209  
   210  // TestRenterPricesVolatility verifies that the renter caches its price
   211  // estimation, and subsequent calls result in non-volatile results.
   212  func TestRenterPricesVolatility(t *testing.T) {
   213  	if testing.Short() {
   214  		t.SkipNow()
   215  	}
   216  	rt, err := newRenterTester(t.Name())
   217  	if err != nil {
   218  		t.Fatal(err)
   219  	}
   220  	defer rt.Close()
   221  
   222  	// create a stubbed hostdb, query it with one contract, add another, verify
   223  	// the price estimation remains constant until the timeout has passed.
   224  	hdb := &pricesStub{}
   225  	id := rt.renter.mu.Lock()
   226  	rt.renter.hostDB = hdb
   227  	rt.renter.mu.Unlock(id)
   228  	dbe := modules.HostDBEntry{}
   229  	dbe.ContractPrice = types.SiacoinPrecision
   230  	dbe.DownloadBandwidthPrice = types.SiacoinPrecision
   231  	dbe.StoragePrice = types.SiacoinPrecision
   232  	dbe.UploadBandwidthPrice = types.SiacoinPrecision
   233  	hdb.dbEntries = append(hdb.dbEntries, dbe)
   234  	initial := rt.renter.PriceEstimation()
   235  	dbe.ContractPrice = dbe.ContractPrice.Mul64(2)
   236  	hdb.dbEntries = append(hdb.dbEntries, dbe)
   237  	after := rt.renter.PriceEstimation()
   238  	if !reflect.DeepEqual(initial, after) {
   239  		t.Log(initial)
   240  		t.Log(after)
   241  		t.Fatal("expected renter price estimation to be constant")
   242  	}
   243  	_, err = rt.miner.AddBlock()
   244  	if err != nil {
   245  		t.Fatal(err)
   246  	}
   247  	after = rt.renter.PriceEstimation()
   248  	if reflect.DeepEqual(initial, after) {
   249  		t.Fatal("expected renter price estimation to change after mining a block")
   250  	}
   251  }