func TestAllowanceSpending(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	t.Parallel()
	h, c, m, err := newTestingTrio(t.Name())
	if err != nil {
		t.Fatal(err)
	}
	settings := h.InternalSettings()
	settings.MinUploadBandwidthPrice = types.SiacoinPrecision.Div64(10)
	err = h.SetInternalSettings(settings)
	if err != nil {
		t.Fatal(err)
	}
	err = h.Announce()
	if err != nil {
		t.Fatal(err)
	}
	_, err = m.AddBlock()
	if err != nil {
		t.Fatal(err)
	}
	err = build.Retry(50, 100*time.Millisecond, func() error {
		hosts, err := c.hdb.RandomHosts(1, nil)
		if err != nil {
			return err
		}
		if len(hosts) == 0 {
			return errors.New("host has not been scanned yet")
		}
		return nil
	})
	if err != nil {
		t.Fatal(err)
	}
	testAllowance := modules.Allowance{
		Funds:       types.SiacoinPrecision.Mul64(6000),
		RenewWindow: 100,
		Hosts:       1,
		Period:      200,
	}
	err = c.SetAllowance(testAllowance)
	if err != nil {
		t.Fatal(err)
	}
	err = build.Retry(50, 100*time.Millisecond, func() error {
		if len(c.Contracts()) != 1 {
			return errors.New("allowance forming seems to have failed")
		}
		return nil
	})
	if err != nil {
		t.Error(err)
	}
	for i := 0; i < 15; i++ {
		for _, contract := range c.Contracts() {
			ed, err := c.Editor(contract.HostPublicKey, nil)
			if err != nil {
				continue
			}
			for sec := 0; sec < 10; sec++ {
				ed.Upload(make([]byte, modules.SectorSize))
			}
			err = ed.Close()
			if err != nil {
				t.Fatal(err)
			}
		}
		_, err := m.AddBlock()
		if err != nil {
			t.Fatal(err)
		}
	}
	var minerRewards types.Currency
	w := c.wallet.(*WalletBridge).W.(modules.Wallet)
	txns, err := w.Transactions(0, 1000)
	if err != nil {
		t.Fatal(err)
	}
	for _, txn := range txns {
		for _, so := range txn.Outputs {
			if so.FundType == types.SpecifierMinerPayout {
				minerRewards = minerRewards.Add(so.Value)
			}
		}
	}
	balance, _, _, err := w.ConfirmedBalance()
	if err != nil {
		t.Fatal(err)
	}
	spent := minerRewards.Sub(balance)
	if spent.Cmp(testAllowance.Funds) > 0 {
		t.Fatal("contractor spent too much money: spent", spent.HumanString(), "allowance funds:", testAllowance.Funds.HumanString())
	}
	refreshCost := c.Contracts()[0].TotalCost.Mul64(2)
	expectedMinSpending := testAllowance.Funds.Sub(refreshCost)
	if spent.Cmp(expectedMinSpending) < 0 {
		t.Fatal("contractor spent to little money: spent", spent.HumanString(), "expected at least:", expectedMinSpending.HumanString())
	}
	reportedSpending := c.PeriodSpending()
	if reportedSpending.TotalAllocated.Cmp(spent) != 0 {
		t.Fatal("reported incorrect spending for this billing cycle: got", reportedSpending.TotalAllocated.HumanString(), "wanted", spent.HumanString())
	}
	if reportedSpending.ContractSpendingDeprecated.Cmp(reportedSpending.TotalAllocated) != 0 {
		t.Fatal("TotalAllocated should be equal to ContractSpending for compatibility")
	}
	var expectedFees types.Currency
	for _, contract := range c.Contracts() {
		expectedFees = expectedFees.Add(contract.TxnFee)
		expectedFees = expectedFees.Add(contract.SiafundFee)
		expectedFees = expectedFees.Add(contract.ContractFee)
	}
	if expectedFees.Cmp(reportedSpending.ContractFees) != 0 {
		t.Fatalf("expected %v reported fees but was %v",
			expectedFees.HumanString(), reportedSpending.ContractFees.HumanString())
	}
}
TestAllowanceSpending verifies that the contractor will not spend more or
less than the allowance if uploading causes repeated early renewal, and that
correct spending metrics are returned, even across renewals.
package contractor
import (
	"errors"
	"os"
	"testing"
	"time"
	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/types"
)
type newStub struct{}
func (newStub) ConsensusSetSubscribe(modules.ConsensusSetSubscriber, modules.ConsensusChangeID, <-chan struct{}) error {
	return nil
}
func (newStub) Synced() bool                               { return true }
func (newStub) Unsubscribe(modules.ConsensusSetSubscriber) { return }
func (newStub) NextAddress() (uc types.UnlockConditions, err error)          { return }
func (newStub) StartTransaction() (tb modules.TransactionBuilder, err error) { return }
func (newStub) AcceptTransactionSet([]types.Transaction) error      { return nil }
func (newStub) FeeEstimation() (a types.Currency, b types.Currency) { return }
func (newStub) AllHosts() []modules.HostDBEntry                                      { return nil }
func (newStub) ActiveHosts() []modules.HostDBEntry                                   { return nil }
func (newStub) Host(types.SiaPublicKey) (settings modules.HostDBEntry, ok bool)      { return }
func (newStub) IncrementSuccessfulInteractions(key types.SiaPublicKey)               { return }
func (newStub) IncrementFailedInteractions(key types.SiaPublicKey)                   { return }
func (newStub) RandomHosts(int, []types.SiaPublicKey) ([]modules.HostDBEntry, error) { return nil, nil }
func (newStub) ScoreBreakdown(modules.HostDBEntry) modules.HostScoreBreakdown {
	return modules.HostScoreBreakdown{}
}
func TestNew(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	var stub newStub
	dir := build.TempDir("contractor", t.Name())
	_, err := New(stub, stub, stub, stub, dir)
	if err != nil {
		t.Fatalf("expected nil, got %v", err)
	}
	_, err = New(nil, stub, stub, stub, dir)
	if err != errNilCS {
		t.Fatalf("expected %v, got %v", errNilCS, err)
	}
	_, err = New(stub, nil, stub, stub, dir)
	if err != errNilWallet {
		t.Fatalf("expected %v, got %v", errNilWallet, err)
	}
	_, err = New(stub, stub, nil, stub, dir)
	if err != errNilTpool {
		t.Fatalf("expected %v, got %v", errNilTpool, err)
	}
	_, err = New(stub, stub, stub, stub, "")
	if !os.IsNotExist(err) {
		t.Fatalf("expected invalid directory, got %v", err)
	}
}
func TestAllowance(t *testing.T) {
	c := &Contractor{
		allowance: modules.Allowance{
			Funds:  types.NewCurrency64(1),
			Period: 2,
			Hosts:  3,
		},
	}
	a := c.Allowance()
	if a.Funds.Cmp(c.allowance.Funds) != 0 ||
		a.Period != c.allowance.Period ||
		a.Hosts != c.allowance.Hosts {
		t.Fatal("Allowance did not return correct allowance:", a, c.allowance)
	}
}
type stubHostDB struct{}
func (stubHostDB) AllHosts() (hs []modules.HostDBEntry)                                      { return }
func (stubHostDB) ActiveHosts() (hs []modules.HostDBEntry)                                   { return }
func (stubHostDB) Host(types.SiaPublicKey) (h modules.HostDBEntry, ok bool)                  { return }
func (stubHostDB) IncrementSuccessfulInteractions(key types.SiaPublicKey)                    { return }
func (stubHostDB) IncrementFailedInteractions(key types.SiaPublicKey)                        { return }
func (stubHostDB) PublicKey() (spk types.SiaPublicKey)                                       { return }
func (stubHostDB) RandomHosts(int, []types.SiaPublicKey) (hs []modules.HostDBEntry, _ error) { return }
func (stubHostDB) ScoreBreakdown(modules.HostDBEntry) modules.HostScoreBreakdown {
	return modules.HostScoreBreakdown{}
}