github.com/Synthesix/Sia@v1.3.3-0.20180413141344-f863baeed3ca/modules/renter/renter_test.go (about) 1 package renter 2 3 import ( 4 "path/filepath" 5 "reflect" 6 "testing" 7 8 "github.com/Synthesix/Sia/build" 9 "github.com/Synthesix/Sia/crypto" 10 "github.com/Synthesix/Sia/modules" 11 "github.com/Synthesix/Sia/modules/consensus" 12 "github.com/Synthesix/Sia/modules/gateway" 13 "github.com/Synthesix/Sia/modules/miner" 14 "github.com/Synthesix/Sia/modules/renter/contractor" 15 "github.com/Synthesix/Sia/modules/transactionpool" 16 "github.com/Synthesix/Sia/modules/wallet" 17 "github.com/Synthesix/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 // stubHostDB is the minimal implementation of the hostDB interface. It can be 101 // embedded in other mock hostDB types, removing the need to reimplement all 102 // of the hostDB's methods on every mock. 103 type stubHostDB struct{} 104 105 func (stubHostDB) ActiveHosts() []modules.HostDBEntry { return nil } 106 func (stubHostDB) AllHosts() []modules.HostDBEntry { return nil } 107 func (stubHostDB) AverageContractPrice() types.Currency { return types.Currency{} } 108 func (stubHostDB) Close() error { return nil } 109 func (stubHostDB) IsOffline(modules.NetAddress) bool { return true } 110 func (stubHostDB) RandomHosts(int, []types.SiaPublicKey) []modules.HostDBEntry { 111 return []modules.HostDBEntry{} 112 } 113 func (stubHostDB) EstimateHostScore(modules.HostDBEntry) modules.HostScoreBreakdown { 114 return modules.HostScoreBreakdown{} 115 } 116 func (stubHostDB) Host(types.SiaPublicKey) (modules.HostDBEntry, bool) { 117 return modules.HostDBEntry{}, false 118 } 119 func (stubHostDB) ScoreBreakdown(modules.HostDBEntry) modules.HostScoreBreakdown { 120 return modules.HostScoreBreakdown{} 121 } 122 123 // stubContractor is the minimal implementation of the hostContractor 124 // interface. 125 type stubContractor struct{} 126 127 func (stubContractor) SetAllowance(modules.Allowance) error { return nil } 128 func (stubContractor) Allowance() modules.Allowance { return modules.Allowance{} } 129 func (stubContractor) Contract(modules.NetAddress) (modules.RenterContract, bool) { 130 return modules.RenterContract{}, false 131 } 132 func (stubContractor) Contracts() []modules.RenterContract { return nil } 133 func (stubContractor) CurrentPeriod() types.BlockHeight { return 0 } 134 func (stubContractor) IsOffline(modules.NetAddress) bool { return false } 135 func (stubContractor) Editor(types.FileContractID) (contractor.Editor, error) { return nil, nil } 136 func (stubContractor) Downloader(types.FileContractID) (contractor.Downloader, error) { 137 return nil, nil 138 } 139 140 type pricesStub struct { 141 stubHostDB 142 143 dbEntries []modules.HostDBEntry 144 } 145 146 func (ps pricesStub) RandomHosts(n int, exclude []types.SiaPublicKey) []modules.HostDBEntry { 147 return ps.dbEntries 148 } 149 150 // TestRenterPricesVolatility verifies that the renter caches its price 151 // estimation, and subsequent calls result in non-volatile results. 152 func TestRenterPricesVolatility(t *testing.T) { 153 if testing.Short() { 154 t.SkipNow() 155 } 156 rt, err := newRenterTester(t.Name()) 157 if err != nil { 158 t.Fatal(err) 159 } 160 defer rt.Close() 161 162 // create a stubbed hostdb, query it with one contract, add another, verify 163 // the price estimation remains constant until the timeout has passed. 164 hdb := &pricesStub{} 165 id := rt.renter.mu.Lock() 166 rt.renter.hostDB = hdb 167 rt.renter.mu.Unlock(id) 168 dbe := modules.HostDBEntry{} 169 dbe.ContractPrice = types.SiacoinPrecision 170 dbe.DownloadBandwidthPrice = types.SiacoinPrecision 171 dbe.StoragePrice = types.SiacoinPrecision 172 dbe.UploadBandwidthPrice = types.SiacoinPrecision 173 hdb.dbEntries = append(hdb.dbEntries, dbe) 174 initial := rt.renter.PriceEstimation() 175 dbe.ContractPrice = dbe.ContractPrice.Mul64(2) 176 hdb.dbEntries = append(hdb.dbEntries, dbe) 177 after := rt.renter.PriceEstimation() 178 if !reflect.DeepEqual(initial, after) { 179 t.Log(initial) 180 t.Log(after) 181 t.Fatal("expected renter price estimation to be constant") 182 } 183 _, err = rt.miner.AddBlock() 184 if err != nil { 185 t.Fatal(err) 186 } 187 after = rt.renter.PriceEstimation() 188 if reflect.DeepEqual(initial, after) { 189 t.Fatal("expected renter price estimation to change after mining a block") 190 } 191 } 192 193 // TestRenterSiapathValidate verifies that the validateSiapath function correctly validates SiaPaths. 194 func TestRenterSiapathValidate(t *testing.T) { 195 var pathtests = []struct { 196 in string 197 valid bool 198 }{ 199 {"valid/siapath", true}, 200 {"../../../directory/traversal", false}, 201 {"testpath", true}, 202 {"valid/siapath/../with/directory/traversal", false}, 203 {"validpath/test", true}, 204 {"..validpath/..test", true}, 205 {"./invalid/path", false}, 206 {".../path", true}, 207 {"valid./path", true}, 208 {"valid../path", true}, 209 {"valid/path./test", true}, 210 {"valid/path../test", true}, 211 {"test/path", true}, 212 {"/leading/slash", false}, 213 {"foo/./bar", false}, 214 {"", false}, 215 } 216 for _, pathtest := range pathtests { 217 err := validateSiapath(pathtest.in) 218 if err != nil && pathtest.valid { 219 t.Fatal("validateSiapath failed on valid path: ", pathtest.in) 220 } 221 if err == nil && !pathtest.valid { 222 t.Fatal("validateSiapath succeeded on invalid path: ", pathtest.in) 223 } 224 } 225 }