github.com/avahowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/modules/renter/contractor/contractor_test.go (about) 1 package contractor 2 3 import ( 4 "encoding/json" 5 "io/ioutil" 6 "os" 7 "path/filepath" 8 "testing" 9 10 "github.com/NebulousLabs/Sia/build" 11 "github.com/NebulousLabs/Sia/modules" 12 "github.com/NebulousLabs/Sia/types" 13 ) 14 15 // newStub is used to test the New function. It implements all of the contractor's 16 // dependencies. 17 type newStub struct{} 18 19 // consensus set stubs 20 func (newStub) ConsensusSetSubscribe(modules.ConsensusSetSubscriber, modules.ConsensusChangeID) error { 21 return nil 22 } 23 24 // wallet stubs 25 func (newStub) NextAddress() (uc types.UnlockConditions, err error) { return } 26 func (newStub) StartTransaction() modules.TransactionBuilder { return nil } 27 28 // transaction pool stubs 29 func (newStub) AcceptTransactionSet([]types.Transaction) error { return nil } 30 func (newStub) FeeEstimation() (a types.Currency, b types.Currency) { return } 31 32 // hdb stubs 33 func (newStub) Host(modules.NetAddress) (settings modules.HostDBEntry, ok bool) { return } 34 func (newStub) RandomHosts(int, []modules.NetAddress) []modules.HostDBEntry { return nil } 35 36 // TestNew tests the New function. 37 func TestNew(t *testing.T) { 38 // Using a stub implementation of the dependencies is fine, as long as its 39 // non-nil. 40 var stub newStub 41 dir := build.TempDir("contractor", "TestNew") 42 43 // Sane values. 44 _, err := New(stub, stub, stub, stub, dir) 45 if err != nil { 46 t.Fatalf("expected nil, got %v", err) 47 } 48 49 // Nil consensus set. 50 _, err = New(nil, stub, stub, stub, dir) 51 if err != errNilCS { 52 t.Fatalf("expected %v, got %v", errNilCS, err) 53 } 54 55 // Nil wallet. 56 _, err = New(stub, nil, stub, stub, dir) 57 if err != errNilWallet { 58 t.Fatalf("expected %v, got %v", errNilWallet, err) 59 } 60 61 // Nil transaction pool. 62 _, err = New(stub, stub, nil, stub, dir) 63 if err != errNilTpool { 64 t.Fatalf("expected %v, got %v", errNilTpool, err) 65 } 66 67 // Bad persistDir. 68 _, err = New(stub, stub, stub, stub, "") 69 if !os.IsNotExist(err) { 70 t.Fatalf("expected invalid directory, got %v", err) 71 } 72 73 // Corrupted persist file. 74 ioutil.WriteFile(filepath.Join(dir, "contractor.json"), []byte{1, 2, 3}, 0666) 75 _, err = New(stub, stub, stub, stub, dir) 76 if _, ok := err.(*json.SyntaxError); !ok { 77 t.Fatalf("expected invalid json, got %v", err) 78 } 79 80 // Corrupted logfile. 81 os.RemoveAll(filepath.Join(dir, "contractor.log")) 82 f, err := os.OpenFile(filepath.Join(dir, "contractor.log"), os.O_CREATE, 0000) 83 if err != nil { 84 t.Fatal(err) 85 } 86 defer f.Close() 87 _, err = New(stub, stub, stub, stub, dir) 88 if !os.IsPermission(err) { 89 t.Fatalf("expected permissions error, got %v", err) 90 } 91 } 92 93 // TestContracts tests the Contracts method. 94 func TestContracts(t *testing.T) { 95 c := &Contractor{ 96 contracts: map[types.FileContractID]modules.RenterContract{ 97 {1}: {ID: types.FileContractID{1}, NetAddress: "foo"}, 98 {2}: {ID: types.FileContractID{2}, NetAddress: "bar"}, 99 {3}: {ID: types.FileContractID{3}, NetAddress: "baz"}, 100 }, 101 } 102 for _, contract := range c.Contracts() { 103 if exp := c.contracts[contract.ID]; exp.NetAddress != contract.NetAddress { 104 t.Errorf("contract does not match: expected %v, got %v", exp.NetAddress, contract.NetAddress) 105 } 106 } 107 } 108 109 // TestAllowance tests the Allowance method. 110 func TestAllowance(t *testing.T) { 111 c := &Contractor{ 112 allowance: modules.Allowance{ 113 Funds: types.NewCurrency64(1), 114 Period: 2, 115 Hosts: 3, 116 }, 117 } 118 a := c.Allowance() 119 if a.Funds.Cmp(c.allowance.Funds) != 0 || 120 a.Period != c.allowance.Period || 121 a.Hosts != c.allowance.Hosts { 122 t.Fatal("Allowance did not return correct allowance:", a, c.allowance) 123 } 124 } 125 126 // stubHostDB mocks the hostDB dependency using zero-valued implementations of 127 // its methods. 128 type stubHostDB struct{} 129 130 func (stubHostDB) Host(modules.NetAddress) (h modules.HostDBEntry, ok bool) { return } 131 func (stubHostDB) RandomHosts(int, []modules.NetAddress) (hs []modules.HostDBEntry) { return } 132 133 // TestSetAllowance tests the SetAllowance method. 134 func TestSetAllowance(t *testing.T) { 135 c := &Contractor{ 136 // an empty hostDB ensures that calls to formContracts will always fail 137 hdb: stubHostDB{}, 138 } 139 140 // bad args 141 err := c.SetAllowance(modules.Allowance{Funds: types.NewCurrency64(1), Period: 0, Hosts: 3}) 142 if err == nil { 143 t.Error("expected error, got nil") 144 } 145 err = c.SetAllowance(modules.Allowance{Funds: types.NewCurrency64(1), Period: 2, Hosts: 0}) 146 if err == nil { 147 t.Error("expected error, got nil") 148 } 149 150 // formContracts should fail (no hosts) 151 err = c.SetAllowance(modules.Allowance{Funds: types.NewCurrency64(1), Period: 2, Hosts: 3}) 152 if err == nil { 153 t.Error("expected error, got nil") 154 } 155 } 156 157 // testWalletShim is used to test the walletBridge type. 158 type testWalletShim struct { 159 nextAddressCalled bool 160 startTxnCalled bool 161 } 162 163 // These stub implementations for the walletShim interface set their respective 164 // booleans to true, allowing tests to verify that they have been called. 165 func (ws *testWalletShim) NextAddress() (types.UnlockConditions, error) { 166 ws.nextAddressCalled = true 167 return types.UnlockConditions{}, nil 168 } 169 func (ws *testWalletShim) StartTransaction() modules.TransactionBuilder { 170 ws.startTxnCalled = true 171 return nil 172 } 173 174 // TestWalletBridge tests the walletBridge type. 175 func TestWalletBridge(t *testing.T) { 176 shim := new(testWalletShim) 177 bridge := walletBridge{shim} 178 bridge.NextAddress() 179 if !shim.nextAddressCalled { 180 t.Error("NextAddress was not called on the shim") 181 } 182 bridge.StartTransaction() 183 if !shim.startTxnCalled { 184 t.Error("StartTransaction was not called on the shim") 185 } 186 }