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  }