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