<commit_before>package contractor

import (
	"errors"
	"os"
	"testing"
	"time"

	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/types"
)

// newStub is used to test the New function. It implements all of the contractor's
// dependencies.
type newStub struct{}

// consensus set stubs
func (newStub) ConsensusSetSubscribe(modules.ConsensusSetSubscriber, modules.ConsensusChangeID) error {
	return nil
}
func (newStub) Synced() bool                               { return true }
func (newStub) Unsubscribe(modules.ConsensusSetSubscriber) { return }

// wallet stubs
func (newStub) NextAddress() (uc types.UnlockConditions, err error) { return }
func (newStub) StartTransaction() modules.TransactionBuilder        { return nil }

// transaction pool stubs
func (newStub) AcceptTransactionSet([]types.Transaction) error      { return nil }
func (newStub) FeeEstimation() (a types.Currency, b types.Currency) { return }

// hdb stubs
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     { return nil }
func (newStub) ScoreBreakdown(modules.HostDBEntry) modules.HostScoreBreakdown {
	return modules.HostScoreBreakdown{}
}

// TestNew tests the New function.
func TestNew(t *testing.T) {
	// Using a stub implementation of the dependencies is fine, as long as its
	// non-nil.
	var stub newStub
	dir := build.TempDir("contractor", t.Name())

	// Sane values.
	_, err := New(stub, stub, stub, stub, dir)
	if err != nil {
		t.Fatalf("expected nil, got %v", err)
	}

	// Nil consensus set.
	_, err = New(nil, stub, stub, stub, dir)
	if err != errNilCS {
		t.Fatalf("expected %v, got %v", errNilCS, err)
	}

	// Nil wallet.
	_, err = New(stub, nil, stub, stub, dir)
	if err != errNilWallet {
		t.Fatalf("expected %v, got %v", errNilWallet, err)
	}

	// Nil transaction pool.
	_, err = New(stub, stub, nil, stub, dir)
	if err != errNilTpool {
		t.Fatalf("expected %v, got %v", errNilTpool, err)
	}

	// Bad persistDir.
	_, err = New(stub, stub, stub, stub, "")
	if !os.IsNotExist(err) {
		t.Fatalf("expected invalid directory, got %v", err)
	}
}

// TestContract tests the Contract method.
func TestContract(t *testing.T) {
	c := &Contractor{
		contracts: map[types.FileContractID]modules.RenterContract{
			{1}: {ID: types.FileContractID{1}, NetAddress: "foo"},
			{2}: {ID: types.FileContractID{2}, NetAddress: "bar"},
			{3}: {ID: types.FileContractID{3}, NetAddress: "baz"},
		},
	}
	tests := []struct {
		addr       modules.NetAddress
		exists     bool
		contractID types.FileContractID
	}{
		{"foo", true, types.FileContractID{1}},
		{"bar", true, types.FileContractID{2}},
		{"baz", true, types.FileContractID{3}},
		{"quux", false, types.FileContractID{}},
		{"nope", false, types.FileContractID{}},
	}
	for _, test := range tests {
		contract, ok := c.Contract(test.addr)
		if ok != test.exists {
			t.Errorf("%v: expected %v, got %v", test.addr, test.exists, ok)
		} else if contract.ID != test.contractID {
			t.Errorf("%v: expected %v, got %v", test.addr, test.contractID, contract.ID)
		}
	}

	// delete all contracts
	c.contracts = map[types.FileContractID]modules.RenterContract{}
	for _, test := range tests {
		_, ok := c.Contract(test.addr)
		if ok {
			t.Error("no contracts should remain")
		}
	}
}

// TestContracts tests the Contracts method.
func TestContracts(t *testing.T) {
	var stub newStub
	dir := build.TempDir("contractor", t.Name())
	c, err := New(stub, stub, stub, stub, dir)
	if err != nil {
		t.Fatalf("expected nil, got %v", err)
	}
	c.contracts = map[types.FileContractID]modules.RenterContract{
		{1}: {ID: types.FileContractID{1}, NetAddress: "foo"},
		{2}: {ID: types.FileContractID{2}, NetAddress: "bar"},
		{3}: {ID: types.FileContractID{3}, NetAddress: "baz"},
	}
	for _, contract := range c.Contracts() {
		if exp := c.contracts[contract.ID]; exp.NetAddress != contract.NetAddress {
			t.Errorf("contract does not match: expected %v, got %v", exp.NetAddress, contract.NetAddress)
		}
	}
}

// TestResolveID tests the ResolveID method.
func TestResolveID(t *testing.T) {
	c := &Contractor{
		renewedIDs: map[types.FileContractID]types.FileContractID{
			{1}: {2},
			{2}: {3},
			{3}: {4},
			{5}: {6},
		},
	}
	tests := []struct {
		id       types.FileContractID
		resolved types.FileContractID
	}{
		{types.FileContractID{0}, types.FileContractID{0}},
		{types.FileContractID{1}, types.FileContractID{4}},
		{types.FileContractID{2}, types.FileContractID{4}},
		{types.FileContractID{3}, types.FileContractID{4}},
		{types.FileContractID{4}, types.FileContractID{4}},
		{types.FileContractID{5}, types.FileContractID{6}},
	}
	for _, test := range tests {
		if r := c.ResolveID(test.id); r != test.resolved {
			t.Errorf("expected %v -> %v, got %v", test.id, test.resolved, r)
		}
	}
}

// TestAllowance tests the Allowance method.
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)
	}
}

// stubHostDB mocks the hostDB dependency using zero-valued implementations of
// its methods.
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) { return }
func (stubHostDB) ScoreBreakdown(modules.HostDBEntry) modules.HostScoreBreakdown {
	return modules.HostScoreBreakdown{}
}

// TestIntegrationSetAllowance tests the SetAllowance method.
func TestIntegrationSetAllowance(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	// create testing trio
	_, c, m, err := newTestingTrio(t.Name())
	if err != nil {
		t.Fatal(err)
	}

	// this test requires two hosts: create another one
	h, err := newTestingHost(build.TempDir("hostdata", ""), c.cs.(modules.ConsensusSet), c.tpool.(modules.TransactionPool))
	if err != nil {
		t.Fatal(err)
	}

	// announce the extra host
	err = h.Announce()
	if err != nil {
		t.Fatal(err)
	}

	// mine a block, processing the announcement
	m.AddBlock()

	// wait for hostdb to scan host
	for i := 0; i < 100 && len(c.hdb.RandomHosts(1, nil)) == 0; i++ {
		time.Sleep(time.Millisecond * 50)
	}

	// cancel allowance
	var a modules.Allowance
	err = c.SetAllowance(a)
	if err != nil {
		t.Fatal(err)
	}

	// bad args
	a.Hosts = 1
	err = c.SetAllowance(a)
	if err != errAllowanceZeroPeriod {
		t.Errorf("expected %q, got %q", errAllowanceZeroPeriod, err)
	}
	a.Period = 20
	err = c.SetAllowance(a)
	if err != ErrAllowanceZeroWindow {
		t.Errorf("expected %q, got %q", ErrAllowanceZeroWindow, err)
	}
	a.RenewWindow = 20
	err = c.SetAllowance(a)
	if err != errAllowanceWindowSize {
		t.Errorf("expected %q, got %q", errAllowanceWindowSize, err)
	}

	// reasonable values; should succeed
	a.Funds = types.SiacoinPrecision.Mul64(100)
	a.RenewWindow = 10
	err = c.SetAllowance(a)
	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)
	}

	// set same allowance; should no-op
	err = c.SetAllowance(a)
	if err != nil {
		t.Fatal(err)
	}
	c.mu.Lock()
	clen := len(c.contracts)
	c.mu.Unlock()
	if clen != 1 {
		t.Fatal("expected 1 contract, got", len(c.contracts))
	}

	m.AddBlock()

	// set allowance with Hosts = 2; should only form one new contract
	a.Hosts = 2
	err = c.SetAllowance(a)
	if err != nil {
		t.Fatal(err)
	}
	err = build.Retry(50, 100*time.Millisecond, func() error {
		if len(c.Contracts()) != 2 {
			return errors.New("allowance forming seems to have failed")
		}
		return nil
	})
	if err != nil {
		t.Fatal(err)
	}

	// set allowance with Funds*2; should trigger renewal of both contracts
	a.Funds = a.Funds.Mul64(2)
	err = c.SetAllowance(a)
	if err != nil {
		t.Fatal(err)
	}
	err = build.Retry(50, 100*time.Millisecond, func() error {
		if len(c.Contracts()) != 2 {
			return errors.New("allowance forming seems to have failed")
		}
		return nil
	})
	if err != nil {
		t.Error(err)
	}

	// delete one of the contracts and set allowance with Funds*2; should
	// trigger 1 renewal and 1 new contract
	c.mu.Lock()
	for id := range c.contracts {
		delete(c.contracts, id)
		break
	}

	c.mu.Unlock()
	a.Funds = a.Funds.Mul64(2)
	err = c.SetAllowance(a)
	if err != nil {
		t.Fatal(err)
	}
	err = build.Retry(50, 100*time.Millisecond, func() error {
		if len(c.Contracts()) != 2 {
			return errors.New("allowance forming seems to have failed")
		}
		return nil
	})
	if err != nil {
		t.Fatal(err)
	}

	// make one of the contracts un-renewable and set allowance with Funds*2; should
	// trigger 1 renewal failure and 2 new contracts
	c.mu.Lock()
	for id, contract := range c.contracts {
		contract.NetAddress = "foo"
		c.contracts[id] = contract
		break
	}
	c.mu.Unlock()
	a.Funds = a.Funds.Mul64(2)
	err = c.SetAllowance(a)
	if err != nil {
		t.Fatal(err)
	}
	c.mu.Lock()
	clen := len(c.contracts)
	c.mu.Unlock()
	if clen != 2 {
		t.Fatal("expected 2 contracts, got", len(c.contracts))
	}
}

// testWalletShim is used to test the walletBridge type.
type testWalletShim struct {
	nextAddressCalled bool
	startTxnCalled    bool
}

// These stub implementations for the walletShim interface set their respective
// booleans to true, allowing tests to verify that they have been called.
func (ws *testWalletShim) NextAddress() (types.UnlockConditions, error) {
	ws.nextAddressCalled = true
	return types.UnlockConditions{}, nil
}
func (ws *testWalletShim) StartTransaction() modules.TransactionBuilder {
	ws.startTxnCalled = true
	return nil
}

// TestWalletBridge tests the walletBridge type.
func TestWalletBridge(t *testing.T) {
	shim := new(testWalletShim)
	bridge := walletBridge{shim}
	bridge.NextAddress()
	if !shim.nextAddressCalled {
		t.Error("NextAddress was not called on the shim")
	}
	bridge.StartTransaction()
	if !shim.startTxnCalled {
		t.Error("StartTransaction was not called on the shim")
	}
}
<commit_msg>fix contractor test race condition<commit_after>package contractor

import (
	"errors"
	"os"
	"testing"
	"time"

	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/types"
)

// newStub is used to test the New function. It implements all of the contractor's
// dependencies.
type newStub struct{}

// consensus set stubs
func (newStub) ConsensusSetSubscribe(modules.ConsensusSetSubscriber, modules.ConsensusChangeID) error {
	return nil
}
func (newStub) Synced() bool                               { return true }
func (newStub) Unsubscribe(modules.ConsensusSetSubscriber) { return }

// wallet stubs
func (newStub) NextAddress() (uc types.UnlockConditions, err error) { return }
func (newStub) StartTransaction() modules.TransactionBuilder        { return nil }

// transaction pool stubs
func (newStub) AcceptTransactionSet([]types.Transaction) error      { return nil }
func (newStub) FeeEstimation() (a types.Currency, b types.Currency) { return }

// hdb stubs
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     { return nil }
func (newStub) ScoreBreakdown(modules.HostDBEntry) modules.HostScoreBreakdown {
	return modules.HostScoreBreakdown{}
}

// TestNew tests the New function.
func TestNew(t *testing.T) {
	// Using a stub implementation of the dependencies is fine, as long as its
	// non-nil.
	var stub newStub
	dir := build.TempDir("contractor", t.Name())

	// Sane values.
	_, err := New(stub, stub, stub, stub, dir)
	if err != nil {
		t.Fatalf("expected nil, got %v", err)
	}

	// Nil consensus set.
	_, err = New(nil, stub, stub, stub, dir)
	if err != errNilCS {
		t.Fatalf("expected %v, got %v", errNilCS, err)
	}

	// Nil wallet.
	_, err = New(stub, nil, stub, stub, dir)
	if err != errNilWallet {
		t.Fatalf("expected %v, got %v", errNilWallet, err)
	}

	// Nil transaction pool.
	_, err = New(stub, stub, nil, stub, dir)
	if err != errNilTpool {
		t.Fatalf("expected %v, got %v", errNilTpool, err)
	}

	// Bad persistDir.
	_, err = New(stub, stub, stub, stub, "")
	if !os.IsNotExist(err) {
		t.Fatalf("expected invalid directory, got %v", err)
	}
}

// TestContract tests the Contract method.
func TestContract(t *testing.T) {
	c := &Contractor{
		contracts: map[types.FileContractID]modules.RenterContract{
			{1}: {ID: types.FileContractID{1}, NetAddress: "foo"},
			{2}: {ID: types.FileContractID{2}, NetAddress: "bar"},
			{3}: {ID: types.FileContractID{3}, NetAddress: "baz"},
		},
	}
	tests := []struct {
		addr       modules.NetAddress
		exists     bool
		contractID types.FileContractID
	}{
		{"foo", true, types.FileContractID{1}},
		{"bar", true, types.FileContractID{2}},
		{"baz", true, types.FileContractID{3}},
		{"quux", false, types.FileContractID{}},
		{"nope", false, types.FileContractID{}},
	}
	for _, test := range tests {
		contract, ok := c.Contract(test.addr)
		if ok != test.exists {
			t.Errorf("%v: expected %v, got %v", test.addr, test.exists, ok)
		} else if contract.ID != test.contractID {
			t.Errorf("%v: expected %v, got %v", test.addr, test.contractID, contract.ID)
		}
	}

	// delete all contracts
	c.contracts = map[types.FileContractID]modules.RenterContract{}
	for _, test := range tests {
		_, ok := c.Contract(test.addr)
		if ok {
			t.Error("no contracts should remain")
		}
	}
}

// TestContracts tests the Contracts method.
func TestContracts(t *testing.T) {
	var stub newStub
	dir := build.TempDir("contractor", t.Name())
	c, err := New(stub, stub, stub, stub, dir)
	if err != nil {
		t.Fatalf("expected nil, got %v", err)
	}
	c.contracts = map[types.FileContractID]modules.RenterContract{
		{1}: {ID: types.FileContractID{1}, NetAddress: "foo"},
		{2}: {ID: types.FileContractID{2}, NetAddress: "bar"},
		{3}: {ID: types.FileContractID{3}, NetAddress: "baz"},
	}
	for _, contract := range c.Contracts() {
		if exp := c.contracts[contract.ID]; exp.NetAddress != contract.NetAddress {
			t.Errorf("contract does not match: expected %v, got %v", exp.NetAddress, contract.NetAddress)
		}
	}
}

// TestResolveID tests the ResolveID method.
func TestResolveID(t *testing.T) {
	c := &Contractor{
		renewedIDs: map[types.FileContractID]types.FileContractID{
			{1}: {2},
			{2}: {3},
			{3}: {4},
			{5}: {6},
		},
	}
	tests := []struct {
		id       types.FileContractID
		resolved types.FileContractID
	}{
		{types.FileContractID{0}, types.FileContractID{0}},
		{types.FileContractID{1}, types.FileContractID{4}},
		{types.FileContractID{2}, types.FileContractID{4}},
		{types.FileContractID{3}, types.FileContractID{4}},
		{types.FileContractID{4}, types.FileContractID{4}},
		{types.FileContractID{5}, types.FileContractID{6}},
	}
	for _, test := range tests {
		if r := c.ResolveID(test.id); r != test.resolved {
			t.Errorf("expected %v -> %v, got %v", test.id, test.resolved, r)
		}
	}
}

// TestAllowance tests the Allowance method.
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)
	}
}

// stubHostDB mocks the hostDB dependency using zero-valued implementations of
// its methods.
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) { return }
func (stubHostDB) ScoreBreakdown(modules.HostDBEntry) modules.HostScoreBreakdown {
	return modules.HostScoreBreakdown{}
}

// TestIntegrationSetAllowance tests the SetAllowance method.
func TestIntegrationSetAllowance(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	// create testing trio
	_, c, m, err := newTestingTrio(t.Name())
	if err != nil {
		t.Fatal(err)
	}

	// this test requires two hosts: create another one
	h, err := newTestingHost(build.TempDir("hostdata", ""), c.cs.(modules.ConsensusSet), c.tpool.(modules.TransactionPool))
	if err != nil {
		t.Fatal(err)
	}

	// announce the extra host
	err = h.Announce()
	if err != nil {
		t.Fatal(err)
	}

	// mine a block, processing the announcement
	m.AddBlock()

	// wait for hostdb to scan host
	for i := 0; i < 100 && len(c.hdb.RandomHosts(1, nil)) == 0; i++ {
		time.Sleep(time.Millisecond * 50)
	}

	// cancel allowance
	var a modules.Allowance
	err = c.SetAllowance(a)
	if err != nil {
		t.Fatal(err)
	}

	// bad args
	a.Hosts = 1
	err = c.SetAllowance(a)
	if err != errAllowanceZeroPeriod {
		t.Errorf("expected %q, got %q", errAllowanceZeroPeriod, err)
	}
	a.Period = 20
	err = c.SetAllowance(a)
	if err != ErrAllowanceZeroWindow {
		t.Errorf("expected %q, got %q", ErrAllowanceZeroWindow, err)
	}
	a.RenewWindow = 20
	err = c.SetAllowance(a)
	if err != errAllowanceWindowSize {
		t.Errorf("expected %q, got %q", errAllowanceWindowSize, err)
	}

	// reasonable values; should succeed
	a.Funds = types.SiacoinPrecision.Mul64(100)
	a.RenewWindow = 10
	err = c.SetAllowance(a)
	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)
	}

	// set same allowance; should no-op
	err = c.SetAllowance(a)
	if err != nil {
		t.Fatal(err)
	}
	c.mu.Lock()
	clen := len(c.contracts)
	c.mu.Unlock()
	if clen != 1 {
		t.Fatal("expected 1 contract, got", len(c.contracts))
	}

	m.AddBlock()

	// set allowance with Hosts = 2; should only form one new contract
	a.Hosts = 2
	err = c.SetAllowance(a)
	if err != nil {
		t.Fatal(err)
	}
	err = build.Retry(50, 100*time.Millisecond, func() error {
		if len(c.Contracts()) != 2 {
			return errors.New("allowance forming seems to have failed")
		}
		return nil
	})
	if err != nil {
		t.Fatal(err)
	}

	// set allowance with Funds*2; should trigger renewal of both contracts
	a.Funds = a.Funds.Mul64(2)
	err = c.SetAllowance(a)
	if err != nil {
		t.Fatal(err)
	}
	err = build.Retry(50, 100*time.Millisecond, func() error {
		if len(c.Contracts()) != 2 {
			return errors.New("allowance forming seems to have failed")
		}
		return nil
	})
	if err != nil {
		t.Error(err)
	}

	// delete one of the contracts and set allowance with Funds*2; should
	// trigger 1 renewal and 1 new contract
	c.mu.Lock()
	for id := range c.contracts {
		delete(c.contracts, id)
		break
	}

	c.mu.Unlock()
	a.Funds = a.Funds.Mul64(2)
	err = c.SetAllowance(a)
	if err != nil {
		t.Fatal(err)
	}
	err = build.Retry(50, 100*time.Millisecond, func() error {
		if len(c.Contracts()) != 2 {
			return errors.New("allowance forming seems to have failed")
		}
		return nil
	})
	if err != nil {
		t.Fatal(err)
	}

	// make one of the contracts un-renewable and set allowance with Funds*2; should
	// trigger 1 renewal failure and 2 new contracts
	c.mu.Lock()
	for id, contract := range c.contracts {
		contract.NetAddress = "foo"
		c.contracts[id] = contract
		break
	}
	c.mu.Unlock()
	a.Funds = a.Funds.Mul64(2)
	err = c.SetAllowance(a)
	if err != nil {
		t.Fatal(err)
	}
	c.mu.Lock()
	clen = len(c.contracts)
	c.mu.Unlock()
	if clen != 2 {
		t.Fatal("expected 2 contracts, got", len(c.contracts))
	}
}

// testWalletShim is used to test the walletBridge type.
type testWalletShim struct {
	nextAddressCalled bool
	startTxnCalled    bool
}

// These stub implementations for the walletShim interface set their respective
// booleans to true, allowing tests to verify that they have been called.
func (ws *testWalletShim) NextAddress() (types.UnlockConditions, error) {
	ws.nextAddressCalled = true
	return types.UnlockConditions{}, nil
}
func (ws *testWalletShim) StartTransaction() modules.TransactionBuilder {
	ws.startTxnCalled = true
	return nil
}

// TestWalletBridge tests the walletBridge type.
func TestWalletBridge(t *testing.T) {
	shim := new(testWalletShim)
	bridge := walletBridge{shim}
	bridge.NextAddress()
	if !shim.nextAddressCalled {
		t.Error("NextAddress was not called on the shim")
	}
	bridge.StartTransaction()
	if !shim.startTxnCalled {
		t.Error("StartTransaction was not called on the shim")
	}
}
<|endoftext|>


<commit_before>// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package modfile

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"reflect"
	"strings"
	"testing"

	"cmd/internal/diff"
)

// exists reports whether the named file exists.
func exists(name string) bool {
	_, err := os.Stat(name)
	return err == nil
}

// Test that reading and then writing the golden files
// does not change their output.
func TestPrintGolden(t *testing.T) {
	outs, err := filepath.Glob("testdata/*.golden")
	if err != nil {
		t.Fatal(err)
	}
	for _, out := range outs {
		testPrint(t, out, out)
	}
}

// testPrint is a helper for testing the printer.
// It reads the file named in, reformats it, and compares
// the result to the file named out.
func testPrint(t *testing.T, in, out string) {
	data, err := ioutil.ReadFile(in)
	if err != nil {
		t.Error(err)
		return
	}

	golden, err := ioutil.ReadFile(out)
	if err != nil {
		t.Error(err)
		return
	}

	base := "testdata/" + filepath.Base(in)
	f, err := parse(in, data)
	if err != nil {
		t.Error(err)
		return
	}

	ndata := Format(f)

	if !bytes.Equal(ndata, golden) {
		t.Errorf("formatted %s incorrectly: diff shows -golden, +ours", base)
		tdiff(t, string(golden), string(ndata))
		return
	}
}

func TestParseLax(t *testing.T) {
	badFile := []byte(`module m
		surprise attack
		x y (
			z
		)
		exclude v1.2.3
		replace <-!!!
	`)
	_, err := ParseLax("file", badFile, nil)
	if err != nil {
		t.Fatalf("ParseLax did not ignore irrelevant errors: %v", err)
	}
}

// Test that when files in the testdata directory are parsed
// and printed and parsed again, we get the same parse tree
// both times.
func TestPrintParse(t *testing.T) {
	outs, err := filepath.Glob("testdata/*")
	if err != nil {
		t.Fatal(err)
	}
	for _, out := range outs {
		data, err := ioutil.ReadFile(out)
		if err != nil {
			t.Error(err)
			continue
		}

		base := "testdata/" + filepath.Base(out)
		f, err := parse(base, data)
		if err != nil {
			t.Errorf("parsing original: %v", err)
			continue
		}

		ndata := Format(f)
		f2, err := parse(base, ndata)
		if err != nil {
			t.Errorf("parsing reformatted: %v", err)
			continue
		}

		eq := eqchecker{file: base}
		if err := eq.check(f, f2); err != nil {
			t.Errorf("not equal (parse/Format/parse): %v", err)
		}

		pf1, err := Parse(base, data, nil)
		if err != nil {
			switch base {
			case "testdata/replace2.in", "testdata/gopkg.in.golden":
				t.Errorf("should parse %v: %v", base, err)
			}
		}
		if err == nil {
			pf2, err := Parse(base, ndata, nil)
			if err != nil {
				t.Errorf("Parsing reformatted: %v", err)
				continue
			}
			eq := eqchecker{file: base}
			if err := eq.check(pf1, pf2); err != nil {
				t.Errorf("not equal (parse/Format/Parse): %v", err)
			}

			ndata2, err := pf1.Format()
			if err != nil {
				t.Errorf("reformat: %v", err)
			}
			pf3, err := Parse(base, ndata2, nil)
			if err != nil {
				t.Errorf("Parsing reformatted2: %v", err)
				continue
			}
			eq = eqchecker{file: base}
			if err := eq.check(pf1, pf3); err != nil {
				t.Errorf("not equal (Parse/Format/Parse): %v", err)
			}
			ndata = ndata2
		}

		if strings.HasSuffix(out, ".in") {
			golden, err := ioutil.ReadFile(strings.TrimSuffix(out, ".in") + ".golden")
			if err != nil {
				t.Error(err)
				continue
			}
			if !bytes.Equal(ndata, golden) {
				t.Errorf("formatted %s incorrectly: diff shows -golden, +ours", base)
				tdiff(t, string(golden), string(ndata))
				return
			}
		}
	}
}

// An eqchecker holds state for checking the equality of two parse trees.
type eqchecker struct {
	file string
	pos  Position
}

// errorf returns an error described by the printf-style format and arguments,
// inserting the current file position before the error text.
func (eq *eqchecker) errorf(format string, args ...interface{}) error {
	return fmt.Errorf("%s:%d: %s", eq.file, eq.pos.Line,
		fmt.Sprintf(format, args...))
}

// check checks that v and w represent the same parse tree.
// If not, it returns an error describing the first difference.
func (eq *eqchecker) check(v, w interface{}) error {
	return eq.checkValue(reflect.ValueOf(v), reflect.ValueOf(w))
}

var (
	posType      = reflect.TypeOf(Position{})
	commentsType = reflect.TypeOf(Comments{})
)

// checkValue checks that v and w represent the same parse tree.
// If not, it returns an error describing the first difference.
func (eq *eqchecker) checkValue(v, w reflect.Value) error {
	// inner returns the innermost expression for v.
	// if v is a non-nil interface value, it returns the concrete
	// value in the interface.
	inner := func(v reflect.Value) reflect.Value {
		for {
			if v.Kind() == reflect.Interface && !v.IsNil() {
				v = v.Elem()
				continue
			}
			break
		}
		return v
	}

	v = inner(v)
	w = inner(w)
	if v.Kind() == reflect.Invalid && w.Kind() == reflect.Invalid {
		return nil
	}
	if v.Kind() == reflect.Invalid {
		return eq.errorf("nil interface became %s", w.Type())
	}
	if w.Kind() == reflect.Invalid {
		return eq.errorf("%s became nil interface", v.Type())
	}

	if v.Type() != w.Type() {
		return eq.errorf("%s became %s", v.Type(), w.Type())
	}

	if p, ok := v.Interface().(Expr); ok {
		eq.pos, _ = p.Span()
	}

	switch v.Kind() {
	default:
		return eq.errorf("unexpected type %s", v.Type())

	case reflect.Bool, reflect.Int, reflect.String:
		vi := v.Interface()
		wi := w.Interface()
		if vi != wi {
			return eq.errorf("%v became %v", vi, wi)
		}

	case reflect.Slice:
		vl := v.Len()
		wl := w.Len()
		for i := 0; i < vl || i < wl; i++ {
			if i >= vl {
				return eq.errorf("unexpected %s", w.Index(i).Type())
			}
			if i >= wl {
				return eq.errorf("missing %s", v.Index(i).Type())
			}
			if err := eq.checkValue(v.Index(i), w.Index(i)); err != nil {
				return err
			}
		}

	case reflect.Struct:
		// Fields in struct must match.
		t := v.Type()
		n := t.NumField()
		for i := 0; i < n; i++ {
			tf := t.Field(i)
			switch {
			default:
				if err := eq.checkValue(v.Field(i), w.Field(i)); err != nil {
					return err
				}

			case tf.Type == posType: // ignore positions
			case tf.Type == commentsType: // ignore comment assignment
			}
		}

	case reflect.Ptr, reflect.Interface:
		if v.IsNil() != w.IsNil() {
			if v.IsNil() {
				return eq.errorf("unexpected %s", w.Elem().Type())
			}
			return eq.errorf("missing %s", v.Elem().Type())
		}
		if err := eq.checkValue(v.Elem(), w.Elem()); err != nil {
			return err
		}
	}
	return nil
}

// tdiff logs the diff output to t.Error.
func tdiff(t *testing.T, a, b string) {
	data, err := diff.Diff("modfile-test", []byte(a), []byte(b))
	if err != nil {
		t.Error(err)
		return
	}
	t.Error(string(data))
}

var modulePathTests = []struct {
	input    []byte
	expected string
}{
	{input: []byte("module \"github.com/rsc/vgotest\""), expected: "github.com/rsc/vgotest"},
	{input: []byte("module github.com/rsc/vgotest"), expected: "github.com/rsc/vgotest"},
	{input: []byte("module  \"github.com/rsc/vgotest\""), expected: "github.com/rsc/vgotest"},
	{input: []byte("module  github.com/rsc/vgotest"), expected: "github.com/rsc/vgotest"},
	{input: []byte("module `github.com/rsc/vgotest`"), expected: "github.com/rsc/vgotest"},
	{input: []byte("module \"github.com/rsc/vgotest/v2\""), expected: "github.com/rsc/vgotest/v2"},
	{input: []byte("module github.com/rsc/vgotest/v2"), expected: "github.com/rsc/vgotest/v2"},
	{input: []byte("module \"gopkg.in/yaml.v2\""), expected: "gopkg.in/yaml.v2"},
	{input: []byte("module gopkg.in/yaml.v2"), expected: "gopkg.in/yaml.v2"},
	{input: []byte("module \"gopkg.in/check.v1\"\n"), expected: "gopkg.in/check.v1"},
	{input: []byte("module \"gopkg.in/check.v1\n\""), expected: ""},
	{input: []byte("module gopkg.in/check.v1\n"), expected: "gopkg.in/check.v1"},
	{input: []byte("module \"gopkg.in/check.v1\"\r\n"), expected: "gopkg.in/check.v1"},
	{input: []byte("module gopkg.in/check.v1\r\n"), expected: "gopkg.in/check.v1"},
	{input: []byte("module \"gopkg.in/check.v1\"\n\n"), expected: "gopkg.in/check.v1"},
	{input: []byte("module gopkg.in/check.v1\n\n"), expected: "gopkg.in/check.v1"},
	{input: []byte("module \n\"gopkg.in/check.v1\"\n\n"), expected: ""},
	{input: []byte("module \ngopkg.in/check.v1\n\n"), expected: ""},
	{input: []byte("module \"gopkg.in/check.v1\"asd"), expected: ""},
	{input: []byte("module \n\"gopkg.in/check.v1\"\n\n"), expected: ""},
	{input: []byte("module \ngopkg.in/check.v1\n\n"), expected: ""},
	{input: []byte("module \"gopkg.in/check.v1\"asd"), expected: ""},
	{input: []byte("module  \nmodule a/b/c "), expected: "a/b/c"},
	{input: []byte("module \"   \""), expected: "   "},
	{input: []byte("module   "), expected: ""},
	{input: []byte("module \"  a/b/c  \""), expected: "  a/b/c  "},
	{input: []byte("module \"github.com/rsc/vgotest1\" // with a comment"), expected: "github.com/rsc/vgotest1"},
}

func TestModulePath(t *testing.T) {
	for _, test := range modulePathTests {
		t.Run(string(test.input), func(t *testing.T) {
			result := ModulePath(test.input)
			if result != test.expected {
				t.Fatalf("ModulePath(%q): %s, want %s", string(test.input), result, test.expected)
			}
		})
	}
}

func TestGoVersion(t *testing.T) {
	for _, test := range []struct {
		desc, input string
		ok          bool
	}{
		{desc: "empty", input: "module m\ngo \n", ok: false},
		{desc: "one", input: "module m\ngo 1\n", ok: false},
		{desc: "two", input: "module m\ngo 1.22\n", ok: true},
		{desc: "three", input: "module m\ngo 1.22.333", ok: false},
		{desc: "before", input: "module m\ngo v1.2\n", ok: false},
		{desc: "after", input: "module m\ngo 1.2rc1\n", ok: false},
		{desc: "space", input: "module m\ngo 1.2 3.4\n", ok: false},
	} {
		t.Run(test.desc, func(t *testing.T) {
			if _, err := Parse("go.mod", []byte(test.input), nil); err == nil && !test.ok {
				t.Error("unexpected success")
			} else if err != nil && test.ok {
				t.Errorf("unexpected error: %v", err)
			}
		})
	}
}
<commit_msg>cmd/go/internal/modfile: don't use cmd/internal/diff<commit_after>// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package modfile

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"reflect"
	"strings"
	"testing"
)

// exists reports whether the named file exists.
func exists(name string) bool {
	_, err := os.Stat(name)
	return err == nil
}

// Test that reading and then writing the golden files
// does not change their output.
func TestPrintGolden(t *testing.T) {
	outs, err := filepath.Glob("testdata/*.golden")
	if err != nil {
		t.Fatal(err)
	}
	for _, out := range outs {
		testPrint(t, out, out)
	}
}

// testPrint is a helper for testing the printer.
// It reads the file named in, reformats it, and compares
// the result to the file named out.
func testPrint(t *testing.T, in, out string) {
	data, err := ioutil.ReadFile(in)
	if err != nil {
		t.Error(err)
		return
	}

	golden, err := ioutil.ReadFile(out)
	if err != nil {
		t.Error(err)
		return
	}

	base := "testdata/" + filepath.Base(in)
	f, err := parse(in, data)
	if err != nil {
		t.Error(err)
		return
	}

	ndata := Format(f)

	if !bytes.Equal(ndata, golden) {
		t.Errorf("formatted %s incorrectly: diff shows -golden, +ours", base)
		tdiff(t, string(golden), string(ndata))
		return
	}
}

func TestParseLax(t *testing.T) {
	badFile := []byte(`module m
		surprise attack
		x y (
			z
		)
		exclude v1.2.3
		replace <-!!!
	`)
	_, err := ParseLax("file", badFile, nil)
	if err != nil {
		t.Fatalf("ParseLax did not ignore irrelevant errors: %v", err)
	}
}

// Test that when files in the testdata directory are parsed
// and printed and parsed again, we get the same parse tree
// both times.
func TestPrintParse(t *testing.T) {
	outs, err := filepath.Glob("testdata/*")
	if err != nil {
		t.Fatal(err)
	}
	for _, out := range outs {
		data, err := ioutil.ReadFile(out)
		if err != nil {
			t.Error(err)
			continue
		}

		base := "testdata/" + filepath.Base(out)
		f, err := parse(base, data)
		if err != nil {
			t.Errorf("parsing original: %v", err)
			continue
		}

		ndata := Format(f)
		f2, err := parse(base, ndata)
		if err != nil {
			t.Errorf("parsing reformatted: %v", err)
			continue
		}

		eq := eqchecker{file: base}
		if err := eq.check(f, f2); err != nil {
			t.Errorf("not equal (parse/Format/parse): %v", err)
		}

		pf1, err := Parse(base, data, nil)
		if err != nil {
			switch base {
			case "testdata/replace2.in", "testdata/gopkg.in.golden":
				t.Errorf("should parse %v: %v", base, err)
			}
		}
		if err == nil {
			pf2, err := Parse(base, ndata, nil)
			if err != nil {
				t.Errorf("Parsing reformatted: %v", err)
				continue
			}
			eq := eqchecker{file: base}
			if err := eq.check(pf1, pf2); err != nil {
				t.Errorf("not equal (parse/Format/Parse): %v", err)
			}

			ndata2, err := pf1.Format()
			if err != nil {
				t.Errorf("reformat: %v", err)
			}
			pf3, err := Parse(base, ndata2, nil)
			if err != nil {
				t.Errorf("Parsing reformatted2: %v", err)
				continue
			}
			eq = eqchecker{file: base}
			if err := eq.check(pf1, pf3); err != nil {
				t.Errorf("not equal (Parse/Format/Parse): %v", err)
			}
			ndata = ndata2
		}

		if strings.HasSuffix(out, ".in") {
			golden, err := ioutil.ReadFile(strings.TrimSuffix(out, ".in") + ".golden")
			if err != nil {
				t.Error(err)
				continue
			}
			if !bytes.Equal(ndata, golden) {
				t.Errorf("formatted %s incorrectly: diff shows -golden, +ours", base)
				tdiff(t, string(golden), string(ndata))
				return
			}
		}
	}
}

// An eqchecker holds state for checking the equality of two parse trees.
type eqchecker struct {
	file string
	pos  Position
}

// errorf returns an error described by the printf-style format and arguments,
// inserting the current file position before the error text.
func (eq *eqchecker) errorf(format string, args ...interface{}) error {
	return fmt.Errorf("%s:%d: %s", eq.file, eq.pos.Line,
		fmt.Sprintf(format, args...))
}

// check checks that v and w represent the same parse tree.
// If not, it returns an error describing the first difference.
func (eq *eqchecker) check(v, w interface{}) error {
	return eq.checkValue(reflect.ValueOf(v), reflect.ValueOf(w))
}

var (
	posType      = reflect.TypeOf(Position{})
	commentsType = reflect.TypeOf(Comments{})
)

// checkValue checks that v and w represent the same parse tree.
// If not, it returns an error describing the first difference.
func (eq *eqchecker) checkValue(v, w reflect.Value) error {
	// inner returns the innermost expression for v.
	// if v is a non-nil interface value, it returns the concrete
	// value in the interface.
	inner := func(v reflect.Value) reflect.Value {
		for {
			if v.Kind() == reflect.Interface && !v.IsNil() {
				v = v.Elem()
				continue
			}
			break
		}
		return v
	}

	v = inner(v)
	w = inner(w)
	if v.Kind() == reflect.Invalid && w.Kind() == reflect.Invalid {
		return nil
	}
	if v.Kind() == reflect.Invalid {
		return eq.errorf("nil interface became %s", w.Type())
	}
	if w.Kind() == reflect.Invalid {
		return eq.errorf("%s became nil interface", v.Type())
	}

	if v.Type() != w.Type() {
		return eq.errorf("%s became %s", v.Type(), w.Type())
	}

	if p, ok := v.Interface().(Expr); ok {
		eq.pos, _ = p.Span()
	}

	switch v.Kind() {
	default:
		return eq.errorf("unexpected type %s", v.Type())

	case reflect.Bool, reflect.Int, reflect.String:
		vi := v.Interface()
		wi := w.Interface()
		if vi != wi {
			return eq.errorf("%v became %v", vi, wi)
		}

	case reflect.Slice:
		vl := v.Len()
		wl := w.Len()
		for i := 0; i < vl || i < wl; i++ {
			if i >= vl {
				return eq.errorf("unexpected %s", w.Index(i).Type())
			}
			if i >= wl {
				return eq.errorf("missing %s", v.Index(i).Type())
			}
			if err := eq.checkValue(v.Index(i), w.Index(i)); err != nil {
				return err
			}
		}

	case reflect.Struct:
		// Fields in struct must match.
		t := v.Type()
		n := t.NumField()
		for i := 0; i < n; i++ {
			tf := t.Field(i)
			switch {
			default:
				if err := eq.checkValue(v.Field(i), w.Field(i)); err != nil {
					return err
				}

			case tf.Type == posType: // ignore positions
			case tf.Type == commentsType: // ignore comment assignment
			}
		}

	case reflect.Ptr, reflect.Interface:
		if v.IsNil() != w.IsNil() {
			if v.IsNil() {
				return eq.errorf("unexpected %s", w.Elem().Type())
			}
			return eq.errorf("missing %s", v.Elem().Type())
		}
		if err := eq.checkValue(v.Elem(), w.Elem()); err != nil {
			return err
		}
	}
	return nil
}

// diff returns the output of running diff on b1 and b2.
func diff(b1, b2 []byte) (data []byte, err error) {
	f1, err := ioutil.TempFile("", "testdiff")
	if err != nil {
		return nil, err
	}
	defer os.Remove(f1.Name())
	defer f1.Close()

	f2, err := ioutil.TempFile("", "testdiff")
	if err != nil {
		return nil, err
	}
	defer os.Remove(f2.Name())
	defer f2.Close()

	f1.Write(b1)
	f2.Write(b2)

	data, err = exec.Command("diff", "-u", f1.Name(), f2.Name()).CombinedOutput()
	if len(data) > 0 {
		// diff exits with a non-zero status when the files don't match.
		// Ignore that failure as long as we get output.
		err = nil
	}
	return
}

// tdiff logs the diff output to t.Error.
func tdiff(t *testing.T, a, b string) {
	data, err := diff([]byte(a), []byte(b))
	if err != nil {
		t.Error(err)
		return
	}
	t.Error(string(data))
}

var modulePathTests = []struct {
	input    []byte
	expected string
}{
	{input: []byte("module \"github.com/rsc/vgotest\""), expected: "github.com/rsc/vgotest"},
	{input: []byte("module github.com/rsc/vgotest"), expected: "github.com/rsc/vgotest"},
	{input: []byte("module  \"github.com/rsc/vgotest\""), expected: "github.com/rsc/vgotest"},
	{input: []byte("module  github.com/rsc/vgotest"), expected: "github.com/rsc/vgotest"},
	{input: []byte("module `github.com/rsc/vgotest`"), expected: "github.com/rsc/vgotest"},
	{input: []byte("module \"github.com/rsc/vgotest/v2\""), expected: "github.com/rsc/vgotest/v2"},
	{input: []byte("module github.com/rsc/vgotest/v2"), expected: "github.com/rsc/vgotest/v2"},
	{input: []byte("module \"gopkg.in/yaml.v2\""), expected: "gopkg.in/yaml.v2"},
	{input: []byte("module gopkg.in/yaml.v2"), expected: "gopkg.in/yaml.v2"},
	{input: []byte("module \"gopkg.in/check.v1\"\n"), expected: "gopkg.in/check.v1"},
	{input: []byte("module \"gopkg.in/check.v1\n\""), expected: ""},
	{input: []byte("module gopkg.in/check.v1\n"), expected: "gopkg.in/check.v1"},
	{input: []byte("module \"gopkg.in/check.v1\"\r\n"), expected: "gopkg.in/check.v1"},
	{input: []byte("module gopkg.in/check.v1\r\n"), expected: "gopkg.in/check.v1"},
	{input: []byte("module \"gopkg.in/check.v1\"\n\n"), expected: "gopkg.in/check.v1"},
	{input: []byte("module gopkg.in/check.v1\n\n"), expected: "gopkg.in/check.v1"},
	{input: []byte("module \n\"gopkg.in/check.v1\"\n\n"), expected: ""},
	{input: []byte("module \ngopkg.in/check.v1\n\n"), expected: ""},
	{input: []byte("module \"gopkg.in/check.v1\"asd"), expected: ""},
	{input: []byte("module \n\"gopkg.in/check.v1\"\n\n"), expected: ""},
	{input: []byte("module \ngopkg.in/check.v1\n\n"), expected: ""},
	{input: []byte("module \"gopkg.in/check.v1\"asd"), expected: ""},
	{input: []byte("module  \nmodule a/b/c "), expected: "a/b/c"},
	{input: []byte("module \"   \""), expected: "   "},
	{input: []byte("module   "), expected: ""},
	{input: []byte("module \"  a/b/c  \""), expected: "  a/b/c  "},
	{input: []byte("module \"github.com/rsc/vgotest1\" // with a comment"), expected: "github.com/rsc/vgotest1"},
}

func TestModulePath(t *testing.T) {
	for _, test := range modulePathTests {
		t.Run(string(test.input), func(t *testing.T) {
			result := ModulePath(test.input)
			if result != test.expected {
				t.Fatalf("ModulePath(%q): %s, want %s", string(test.input), result, test.expected)
			}
		})
	}
}

func TestGoVersion(t *testing.T) {
	for _, test := range []struct {
		desc, input string
		ok          bool
	}{
		{desc: "empty", input: "module m\ngo \n", ok: false},
		{desc: "one", input: "module m\ngo 1\n", ok: false},
		{desc: "two", input: "module m\ngo 1.22\n", ok: true},
		{desc: "three", input: "module m\ngo 1.22.333", ok: false},
		{desc: "before", input: "module m\ngo v1.2\n", ok: false},
		{desc: "after", input: "module m\ngo 1.2rc1\n", ok: false},
		{desc: "space", input: "module m\ngo 1.2 3.4\n", ok: false},
	} {
		t.Run(test.desc, func(t *testing.T) {
			if _, err := Parse("go.mod", []byte(test.input), nil); err == nil && !test.ok {
				t.Error("unexpected success")
			} else if err != nil && test.ok {
				t.Errorf("unexpected error: %v", err)
			}
		})
	}
}
<|endoftext|>


<commit_before>package config

import (
	"io/ioutil"
	"os"
	"strings"
	"testing"

	"github.com/stretchr/testify/assert"
)

func init() {
	configDirectoryPath = "./tmp"
}

func TestDefaultDatabasePathIsSetWhenConfigIsEmpty(t *testing.T) {
	rmdirConfig()
	config, err := ReadConfig()
	if err != nil {
		t.Fatal(err)
	}
	assert.NotEmpty(t, config.DatabasePath)
}

func TestDefaultIndexPathIsSetWhenConfigIsEmpty(t *testing.T) {
	rmdirConfig()
	config, err := ReadConfig()
	if err != nil {
		t.Fatal(err)
	}
	assert.NotEmpty(t, config.IndexPath)
}

func TestCanSetDatabasePath(t *testing.T) {
	rmdirConfig()
	config, err := ReadConfig()
	if err != nil {
		t.Fatal(err)
	}
	config.DatabasePath = "database-path-foo"
	err = config.WriteConfig()
	if err != nil {
		t.Fatal(err)
	}
	contents, err := ioutil.ReadFile(configFilePath())
	if err != nil {
		t.Fatal(err)
	}
	rmdirConfig()
	assert.True(t, strings.IndexAny(string(contents), "database-path-foo") >= 0)
}

func TestCanSetIndexPath(t *testing.T) {
	rmdirConfig()
	config, err := ReadConfig()
	if err != nil {
		t.Fatal(err)
	}
	config.IndexPath = "index-path-foo"
	err = config.WriteConfig()
	if err != nil {
		t.Fatal(err)
	}
	contents, err := ioutil.ReadFile(configFilePath())
	if err != nil {
		t.Fatal(err)
	}
	rmdirConfig()
	assert.True(t, strings.IndexAny(string(contents), "index-path-foo") >= 0)
}

func TestGetServiceReturnsEmptyWhenServiceDoesNotExist(t *testing.T) {
	rmdirConfig()
	config, err := ReadConfig()
	if err != nil {
		t.Fatal(err)
	}

	svcCfg := config.GetService("foo")
	assert.Equal(t, "", svcCfg.Token)
}

func mkdirConfig() {
	if err := os.MkdirAll(configDirectoryPath, 0700); err != nil {
		panic(err)
	}
}

func rmdirConfig() {
	if err := os.RemoveAll(configDirectoryPath); err != nil {
		panic(err)
	}
}
<commit_msg>Add test for ReadConfig that reads actual file<commit_after>package config

import (
	"io/ioutil"
	"os"
	"strings"
	"testing"

	"github.com/stretchr/testify/assert"
)

func init() {
	configDirectoryPath = "./tmp"
}

func TestDefaultDatabasePathIsSetWhenConfigIsEmpty(t *testing.T) {
	rmdirConfig()
	config, err := ReadConfig()
	if err != nil {
		t.Fatal(err)
	}
	assert.NotEmpty(t, config.DatabasePath)
}

func TestDefaultIndexPathIsSetWhenConfigIsEmpty(t *testing.T) {
	rmdirConfig()
	config, err := ReadConfig()
	if err != nil {
		t.Fatal(err)
	}
	assert.NotEmpty(t, config.IndexPath)
}

func TestCanSetDatabasePath(t *testing.T) {
	rmdirConfig()
	config, err := ReadConfig()
	if err != nil {
		t.Fatal(err)
	}
	config.DatabasePath = "database-path-foo"
	err = config.WriteConfig()
	if err != nil {
		t.Fatal(err)
	}
	contents, err := ioutil.ReadFile(configFilePath())
	if err != nil {
		t.Fatal(err)
	}
	rmdirConfig()
	assert.True(t, strings.IndexAny(string(contents), "database-path-foo") >= 0)
}

func TestCanSetIndexPath(t *testing.T) {
	rmdirConfig()
	config, err := ReadConfig()
	if err != nil {
		t.Fatal(err)
	}
	config.IndexPath = "index-path-foo"
	err = config.WriteConfig()
	if err != nil {
		t.Fatal(err)
	}
	contents, err := ioutil.ReadFile(configFilePath())
	if err != nil {
		t.Fatal(err)
	}
	rmdirConfig()
	assert.True(t, strings.IndexAny(string(contents), "index-path-foo") >= 0)
}

func TestGetServiceReturnsEmptyWhenServiceDoesNotExist(t *testing.T) {
	rmdirConfig()
	config, err := ReadConfig()
	if err != nil {
		t.Fatal(err)
	}

	svcCfg := config.GetService("foo")
	assert.Equal(t, "", svcCfg.Token)
}

func TestReadConfigFileReadsFileWhenExists(t *testing.T) {
	rmdirConfig()

	config, err := ReadConfig()
	if err != nil {
		t.Fatal(err)
	}

	config.DatabasePath = "foo"
	err = config.WriteConfig()
	if err != nil {
		t.Fatal(err)
	}

	cfg2, err := ReadConfig()
	if err != nil {
		t.Fatal(err)
	}
	assert.Equal(t, "foo", cfg2.DatabasePath)

	rmdirConfig()
}

func mkdirConfig() {
	if err := os.MkdirAll(configDirectoryPath, 0700); err != nil {
		panic(err)
	}
}

func rmdirConfig() {
	if err := os.RemoveAll(configDirectoryPath); err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package config

import (
	. "gopkg.in/check.v1"
	"gopkg.in/src-d/go-git.v4/plumbing"
)

type ConfigSuite struct{}

var _ = Suite(&ConfigSuite{})

func (s *ConfigSuite) TestUnmarshall(c *C) {
	input := []byte(`[core]
        bare = true
		worktree = foo
		commentchar = bar
[pack]
		window = 20
[remote "origin"]
        url = git@github.com:mcuadros/go-git.git
        fetch = +refs/heads/*:refs/remotes/origin/*
[remote "alt"]
		url = git@github.com:mcuadros/go-git.git
		url = git@github.com:src-d/go-git.git
		fetch = +refs/heads/*:refs/remotes/origin/*
		fetch = +refs/pull/*:refs/remotes/origin/pull/*
[submodule "qux"]
        path = qux
        url = https://github.com/foo/qux.git
		branch = bar
[branch "master"]
        remote = origin
        merge = refs/heads/master
`)

	cfg := NewConfig()
	err := cfg.Unmarshal(input)
	c.Assert(err, IsNil)

	c.Assert(cfg.Core.IsBare, Equals, true)
	c.Assert(cfg.Core.Worktree, Equals, "foo")
	c.Assert(cfg.Core.CommentChar, Equals, "bar")
	c.Assert(cfg.Pack.Window, Equals, uint(20))
	c.Assert(cfg.Remotes, HasLen, 2)
	c.Assert(cfg.Remotes["origin"].Name, Equals, "origin")
	c.Assert(cfg.Remotes["origin"].URLs, DeepEquals, []string{"git@github.com:mcuadros/go-git.git"})
	c.Assert(cfg.Remotes["origin"].Fetch, DeepEquals, []RefSpec{"+refs/heads/*:refs/remotes/origin/*"})
	c.Assert(cfg.Remotes["alt"].Name, Equals, "alt")
	c.Assert(cfg.Remotes["alt"].URLs, DeepEquals, []string{"git@github.com:mcuadros/go-git.git", "git@github.com:src-d/go-git.git"})
	c.Assert(cfg.Remotes["alt"].Fetch, DeepEquals, []RefSpec{"+refs/heads/*:refs/remotes/origin/*", "+refs/pull/*:refs/remotes/origin/pull/*"})
	c.Assert(cfg.Submodules, HasLen, 1)
	c.Assert(cfg.Submodules["qux"].Name, Equals, "qux")
	c.Assert(cfg.Submodules["qux"].URL, Equals, "https://github.com/foo/qux.git")
	c.Assert(cfg.Submodules["qux"].Branch, Equals, "bar")
	c.Assert(cfg.Branches["master"].Remote, Equals, "origin")
	c.Assert(cfg.Branches["master"].Merge, Equals, plumbing.ReferenceName("refs/heads/master"))
}

func (s *ConfigSuite) TestMarshall(c *C) {
	output := []byte(`[core]
	bare = true
	worktree = bar
[pack]
	window = 20
[remote "alt"]
	url = git@github.com:mcuadros/go-git.git
	url = git@github.com:src-d/go-git.git
	fetch = +refs/heads/*:refs/remotes/origin/*
	fetch = +refs/pull/*:refs/remotes/origin/pull/*
[remote "origin"]
	url = git@github.com:mcuadros/go-git.git
[submodule "qux"]
	url = https://github.com/foo/qux.git
[branch "master"]
	remote = origin
	merge = refs/heads/master
`)

	cfg := NewConfig()
	cfg.Core.IsBare = true
	cfg.Core.Worktree = "bar"
	cfg.Pack.Window = 20
	cfg.Remotes["origin"] = &RemoteConfig{
		Name: "origin",
		URLs: []string{"git@github.com:mcuadros/go-git.git"},
	}

	cfg.Remotes["alt"] = &RemoteConfig{
		Name:  "alt",
		URLs:  []string{"git@github.com:mcuadros/go-git.git", "git@github.com:src-d/go-git.git"},
		Fetch: []RefSpec{"+refs/heads/*:refs/remotes/origin/*", "+refs/pull/*:refs/remotes/origin/pull/*"},
	}

	cfg.Submodules["qux"] = &Submodule{
		Name: "qux",
		URL:  "https://github.com/foo/qux.git",
	}

	cfg.Branches["master"] = &Branch{
		Name:   "master",
		Remote: "origin",
		Merge:  "refs/heads/master",
	}

	b, err := cfg.Marshal()
	c.Assert(err, IsNil)

	c.Assert(string(b), Equals, string(output))
}

func (s *ConfigSuite) TestUnmarshallMarshall(c *C) {
	input := []byte(`[core]
	bare = true
	worktree = foo
	custom = ignored
[pack]
	window = 20
[remote "origin"]
	url = git@github.com:mcuadros/go-git.git
	fetch = +refs/heads/*:refs/remotes/origin/*
	mirror = true
[branch "master"]
	remote = origin
	merge = refs/heads/master
`)

	cfg := NewConfig()
	err := cfg.Unmarshal(input)
	c.Assert(err, IsNil)

	output, err := cfg.Marshal()
	c.Assert(err, IsNil)
	c.Assert(string(output), DeepEquals, string(input))
}

func (s *ConfigSuite) TestValidateConfig(c *C) {
	config := &Config{
		Remotes: map[string]*RemoteConfig{
			"bar": {
				Name: "bar",
				URLs: []string{"http://foo/bar"},
			},
		},
		Branches: map[string]*Branch{
			"bar": {
				Name: "bar",
			},
			"foo": {
				Name:   "foo",
				Remote: "origin",
				Merge:  plumbing.ReferenceName("refs/heads/foo"),
			},
		},
	}

	c.Assert(config.Validate(), IsNil)
}

func (s *ConfigSuite) TestValidateInvalidRemote(c *C) {
	config := &Config{
		Remotes: map[string]*RemoteConfig{
			"foo": {Name: "foo"},
		},
	}

	c.Assert(config.Validate(), Equals, ErrRemoteConfigEmptyURL)
}

func (s *ConfigSuite) TestValidateInvalidRemoteKey(c *C) {
	config := &Config{
		Remotes: map[string]*RemoteConfig{
			"bar": {Name: "foo"},
		},
	}

	c.Assert(config.Validate(), Equals, ErrInvalid)
}

func (s *ConfigSuite) TestRemoteConfigValidateMissingURL(c *C) {
	config := &RemoteConfig{Name: "foo"}
	c.Assert(config.Validate(), Equals, ErrRemoteConfigEmptyURL)
}

func (s *ConfigSuite) TestRemoteConfigValidateMissingName(c *C) {
	config := &RemoteConfig{}
	c.Assert(config.Validate(), Equals, ErrRemoteConfigEmptyName)
}

func (s *ConfigSuite) TestRemoteConfigValidateDefault(c *C) {
	config := &RemoteConfig{Name: "foo", URLs: []string{"http://foo/bar"}}
	c.Assert(config.Validate(), IsNil)

	fetch := config.Fetch
	c.Assert(fetch, HasLen, 1)
	c.Assert(fetch[0].String(), Equals, "+refs/heads/*:refs/remotes/foo/*")
}

func (s *ConfigSuite) TestValidateInvalidBranchKey(c *C) {
	config := &Config{
		Branches: map[string]*Branch{
			"foo": {
				Name:   "bar",
				Remote: "origin",
				Merge:  plumbing.ReferenceName("refs/heads/bar"),
			},
		},
	}

	c.Assert(config.Validate(), Equals, ErrInvalid)
}

func (s *ConfigSuite) TestValidateInvalidBranch(c *C) {
	config := &Config{
		Branches: map[string]*Branch{
			"bar": {
				Name:   "bar",
				Remote: "origin",
				Merge:  plumbing.ReferenceName("refs/heads/bar"),
			},
			"foo": {
				Name:   "foo",
				Remote: "origin",
				Merge:  plumbing.ReferenceName("baz"),
			},
		},
	}

	c.Assert(config.Validate(), Equals, errBranchInvalidMerge)
}

func (s *ConfigSuite) TestRemoteConfigDefaultValues(c *C) {
	config := NewConfig()

	c.Assert(config.Remotes, HasLen, 0)
	c.Assert(config.Branches, HasLen, 0)
	c.Assert(config.Submodules, HasLen, 0)
	c.Assert(config.Raw, NotNil)
	c.Assert(config.Pack.Window, Equals, DefaultPackWindow)
}
<commit_msg>Add test for Windows local paths.<commit_after>package config

import (
	. "gopkg.in/check.v1"
	"gopkg.in/src-d/go-git.v4/plumbing"
)

type ConfigSuite struct{}

var _ = Suite(&ConfigSuite{})

func (s *ConfigSuite) TestUnmarshall(c *C) {
	input := []byte(`[core]
        bare = true
		worktree = foo
		commentchar = bar
[pack]
		window = 20
[remote "origin"]
        url = git@github.com:mcuadros/go-git.git
        fetch = +refs/heads/*:refs/remotes/origin/*
[remote "alt"]
		url = git@github.com:mcuadros/go-git.git
		url = git@github.com:src-d/go-git.git
		fetch = +refs/heads/*:refs/remotes/origin/*
		fetch = +refs/pull/*:refs/remotes/origin/pull/*
[remote "win-local"]
		url = X:\\Git\\
[submodule "qux"]
        path = qux
        url = https://github.com/foo/qux.git
		branch = bar
[branch "master"]
        remote = origin
        merge = refs/heads/master
`)

	cfg := NewConfig()
	err := cfg.Unmarshal(input)
	c.Assert(err, IsNil)

	c.Assert(cfg.Core.IsBare, Equals, true)
	c.Assert(cfg.Core.Worktree, Equals, "foo")
	c.Assert(cfg.Core.CommentChar, Equals, "bar")
	c.Assert(cfg.Pack.Window, Equals, uint(20))
	c.Assert(cfg.Remotes, HasLen, 3)
	c.Assert(cfg.Remotes["origin"].Name, Equals, "origin")
	c.Assert(cfg.Remotes["origin"].URLs, DeepEquals, []string{"git@github.com:mcuadros/go-git.git"})
	c.Assert(cfg.Remotes["origin"].Fetch, DeepEquals, []RefSpec{"+refs/heads/*:refs/remotes/origin/*"})
	c.Assert(cfg.Remotes["alt"].Name, Equals, "alt")
	c.Assert(cfg.Remotes["alt"].URLs, DeepEquals, []string{"git@github.com:mcuadros/go-git.git", "git@github.com:src-d/go-git.git"})
	c.Assert(cfg.Remotes["alt"].Fetch, DeepEquals, []RefSpec{"+refs/heads/*:refs/remotes/origin/*", "+refs/pull/*:refs/remotes/origin/pull/*"})
	c.Assert(cfg.Remotes["win-local"].Name, Equals, "win-local")
	c.Assert(cfg.Remotes["win-local"].URLs, DeepEquals, []string{"X:\\Git\\"})
	c.Assert(cfg.Submodules, HasLen, 1)
	c.Assert(cfg.Submodules["qux"].Name, Equals, "qux")
	c.Assert(cfg.Submodules["qux"].URL, Equals, "https://github.com/foo/qux.git")
	c.Assert(cfg.Submodules["qux"].Branch, Equals, "bar")
	c.Assert(cfg.Branches["master"].Remote, Equals, "origin")
	c.Assert(cfg.Branches["master"].Merge, Equals, plumbing.ReferenceName("refs/heads/master"))
}

func (s *ConfigSuite) TestMarshall(c *C) {
	output := []byte(`[core]
	bare = true
	worktree = bar
[pack]
	window = 20
[remote "alt"]
	url = git@github.com:mcuadros/go-git.git
	url = git@github.com:src-d/go-git.git
	fetch = +refs/heads/*:refs/remotes/origin/*
	fetch = +refs/pull/*:refs/remotes/origin/pull/*
[remote "origin"]
	url = git@github.com:mcuadros/go-git.git
[remote "win-local"]
	url = "X:\\Git\\"
[submodule "qux"]
	url = https://github.com/foo/qux.git
[branch "master"]
	remote = origin
	merge = refs/heads/master
`)

	cfg := NewConfig()
	cfg.Core.IsBare = true
	cfg.Core.Worktree = "bar"
	cfg.Pack.Window = 20
	cfg.Remotes["origin"] = &RemoteConfig{
		Name: "origin",
		URLs: []string{"git@github.com:mcuadros/go-git.git"},
	}

	cfg.Remotes["alt"] = &RemoteConfig{
		Name:  "alt",
		URLs:  []string{"git@github.com:mcuadros/go-git.git", "git@github.com:src-d/go-git.git"},
		Fetch: []RefSpec{"+refs/heads/*:refs/remotes/origin/*", "+refs/pull/*:refs/remotes/origin/pull/*"},
	}

	cfg.Remotes["win-local"] = &RemoteConfig{
		Name: "win-local",
		URLs: []string{"X:\\Git\\"},
	}

	cfg.Submodules["qux"] = &Submodule{
		Name: "qux",
		URL:  "https://github.com/foo/qux.git",
	}

	cfg.Branches["master"] = &Branch{
		Name:   "master",
		Remote: "origin",
		Merge:  "refs/heads/master",
	}

	b, err := cfg.Marshal()
	c.Assert(err, IsNil)

	c.Assert(string(b), Equals, string(output))
}

func (s *ConfigSuite) TestUnmarshallMarshall(c *C) {
	input := []byte(`[core]
	bare = true
	worktree = foo
	custom = ignored
[pack]
	window = 20
[remote "origin"]
	url = git@github.com:mcuadros/go-git.git
	fetch = +refs/heads/*:refs/remotes/origin/*
	mirror = true
[remote "win-local"]
	url = "X:\\Git\\"
[branch "master"]
	remote = origin
	merge = refs/heads/master
`)

	cfg := NewConfig()
	err := cfg.Unmarshal(input)
	c.Assert(err, IsNil)

	output, err := cfg.Marshal()
	c.Assert(err, IsNil)
	c.Assert(string(output), DeepEquals, string(input))
}

func (s *ConfigSuite) TestValidateConfig(c *C) {
	config := &Config{
		Remotes: map[string]*RemoteConfig{
			"bar": {
				Name: "bar",
				URLs: []string{"http://foo/bar"},
			},
		},
		Branches: map[string]*Branch{
			"bar": {
				Name: "bar",
			},
			"foo": {
				Name:   "foo",
				Remote: "origin",
				Merge:  plumbing.ReferenceName("refs/heads/foo"),
			},
		},
	}

	c.Assert(config.Validate(), IsNil)
}

func (s *ConfigSuite) TestValidateInvalidRemote(c *C) {
	config := &Config{
		Remotes: map[string]*RemoteConfig{
			"foo": {Name: "foo"},
		},
	}

	c.Assert(config.Validate(), Equals, ErrRemoteConfigEmptyURL)
}

func (s *ConfigSuite) TestValidateInvalidRemoteKey(c *C) {
	config := &Config{
		Remotes: map[string]*RemoteConfig{
			"bar": {Name: "foo"},
		},
	}

	c.Assert(config.Validate(), Equals, ErrInvalid)
}

func (s *ConfigSuite) TestRemoteConfigValidateMissingURL(c *C) {
	config := &RemoteConfig{Name: "foo"}
	c.Assert(config.Validate(), Equals, ErrRemoteConfigEmptyURL)
}

func (s *ConfigSuite) TestRemoteConfigValidateMissingName(c *C) {
	config := &RemoteConfig{}
	c.Assert(config.Validate(), Equals, ErrRemoteConfigEmptyName)
}

func (s *ConfigSuite) TestRemoteConfigValidateDefault(c *C) {
	config := &RemoteConfig{Name: "foo", URLs: []string{"http://foo/bar"}}
	c.Assert(config.Validate(), IsNil)

	fetch := config.Fetch
	c.Assert(fetch, HasLen, 1)
	c.Assert(fetch[0].String(), Equals, "+refs/heads/*:refs/remotes/foo/*")
}

func (s *ConfigSuite) TestValidateInvalidBranchKey(c *C) {
	config := &Config{
		Branches: map[string]*Branch{
			"foo": {
				Name:   "bar",
				Remote: "origin",
				Merge:  plumbing.ReferenceName("refs/heads/bar"),
			},
		},
	}

	c.Assert(config.Validate(), Equals, ErrInvalid)
}

func (s *ConfigSuite) TestValidateInvalidBranch(c *C) {
	config := &Config{
		Branches: map[string]*Branch{
			"bar": {
				Name:   "bar",
				Remote: "origin",
				Merge:  plumbing.ReferenceName("refs/heads/bar"),
			},
			"foo": {
				Name:   "foo",
				Remote: "origin",
				Merge:  plumbing.ReferenceName("baz"),
			},
		},
	}

	c.Assert(config.Validate(), Equals, errBranchInvalidMerge)
}

func (s *ConfigSuite) TestRemoteConfigDefaultValues(c *C) {
	config := NewConfig()

	c.Assert(config.Remotes, HasLen, 0)
	c.Assert(config.Branches, HasLen, 0)
	c.Assert(config.Submodules, HasLen, 0)
	c.Assert(config.Raw, NotNil)
	c.Assert(config.Pack.Window, Equals, DefaultPackWindow)
}
<|endoftext|>


<commit_before>package config

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"github.com/9corp/9volt/dal/dalfakes"
)

var _ = Describe("config", func() {
	var (
		fakeDalClient *dalfakes.FakeIDal
		cfg           *Config

		testMemberID      = "testMemberID"
		testListenAddress = "0.0.0.0:8080"
		testEtcdPrefix    = "9volt"
		testEtcdMembers   = []string{"http://127.0.0.1:2379", "http://127.0.0.2:2379"}
		testTags          = []string{"tag1", "tag2"}
		testVersion       = "12345"
		testSemver        = "0.0.1"
	)

	BeforeEach(func() {
		fakeDalClient = &dalfakes.FakeIDal{}
		cfg = New(testMemberID, testListenAddress, testEtcdPrefix, testEtcdMembers,
			testTags, fakeDalClient, nil, testVersion, testSemver)

		Expect(cfg).ToNot(BeNil())
	})

	Context("ValidateDirs", func() {
		PIt("should return empty string slice on no errors")
		PIt("should error if dal runs into an error during key existance check")
		PIt("should error if required key does not exist")
		PIt("should error if required key is not a dir")
		PIt("should return a slice of errors (if errors are hit)")
	})

	Context("Load", func() {
		PIt("should load server config")
		PIt("should error if dal runs into error on initial config fetch")
		PIt("should error if config does not exist")
		PIt("should error if config is a dir (and not a key)")
		PIt("should error if dal get errors")
		PIt("should error if returned value map does not contain config")
		PIt("should error if load() returns an error")
	})

	Context("load", func() {
		PIt("should load server config")
		PIt("should error if config can't be unmarshalled onto serverConfig struct")
		PIt("should error if validate() fails")
	})

	Context("validate", func() {
		PIt("should return nil on happy path")
		PIt("should error on invalid HeartbeatInterval")
		PIt("should error on invalid HeartbeatTimeout")
		PIt("should error on invalid StateDumpInterval")
	})
})
<commit_msg>Fix config test<commit_after>package config

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"github.com/9corp/9volt/dal/dalfakes"
)

var _ = Describe("config", func() {
	var (
		fakeDalClient *dalfakes.FakeIDal
		cfg           *Config

		testMemberID      = "testMemberID"
		testListenAddress = "0.0.0.0:8080"
		testEtcdPrefix    = "9volt"
		testEtcdUserPass  = ""
		testEtcdMembers   = []string{"http://127.0.0.1:2379", "http://127.0.0.2:2379"}
		testTags          = []string{"tag1", "tag2"}
		testVersion       = "12345"
		testSemver        = "0.0.1"
	)

	BeforeEach(func() {
		fakeDalClient = &dalfakes.FakeIDal{}
		cfg = New(testMemberID, testListenAddress, testEtcdPrefix, testEtcdUserPass, testEtcdMembers,
			testTags, fakeDalClient, nil, testVersion, testSemver)

		Expect(cfg).ToNot(BeNil())
	})

	Context("ValidateDirs", func() {
		PIt("should return empty string slice on no errors")
		PIt("should error if dal runs into an error during key existance check")
		PIt("should error if required key does not exist")
		PIt("should error if required key is not a dir")
		PIt("should return a slice of errors (if errors are hit)")
	})

	Context("Load", func() {
		PIt("should load server config")
		PIt("should error if dal runs into error on initial config fetch")
		PIt("should error if config does not exist")
		PIt("should error if config is a dir (and not a key)")
		PIt("should error if dal get errors")
		PIt("should error if returned value map does not contain config")
		PIt("should error if load() returns an error")
	})

	Context("load", func() {
		PIt("should load server config")
		PIt("should error if config can't be unmarshalled onto serverConfig struct")
		PIt("should error if validate() fails")
	})

	Context("validate", func() {
		PIt("should return nil on happy path")
		PIt("should error on invalid HeartbeatInterval")
		PIt("should error on invalid HeartbeatTimeout")
		PIt("should error on invalid StateDumpInterval")
	})
})
<|endoftext|>


<commit_before>package gojenkins

import (
	"fmt"
	"github.com/stretchr/testify/assert"
	"io/ioutil"
	"math/rand"
	"testing"
	"time"
)

var (
	jenkins *Jenkins
)

func TestInit(t *testing.T) {
	jenkins = CreateJenkins("http://localhost:8080", "admin", "admin")
	_, err := jenkins.Init()
	assert.Nil(t, err, "Jenkins Initialization should not fail")
}

func TestCreateJobs(t *testing.T) {
	job1ID := "Job1_test"
	job2ID := "Job2_test"
	job_data := getFileAsString("job.xml")

	job1, err := jenkins.CreateJob(job_data, job1ID)
	if err != nil {
		fmt.Print(err)
	}
	assert.Equal(t, "Some Job Description", job1.GetDescription())
	assert.Equal(t, job1ID, job1.GetName())

	job2, _ := jenkins.CreateJob(job_data, job2ID)
	assert.Equal(t, "Some Job Description", job2.GetDescription())
	assert.Equal(t, job2ID, job2.GetName())
}

func TestCreateNodes(t *testing.T) {

	id1 := "node1_test"
	id2 := "node2_test"

	node1, _ := jenkins.CreateNode(id1, 1, "Node 1 Description", "/var/lib/jenkins")
	assert.Equal(t, id1, node1.GetName())

	node2, _ := jenkins.CreateNode(id2, 1, "Node 2 Description", "/var/lib/jenkins")
	assert.Equal(t, id2, node2.GetName())
}

func TestCreateBuilds(t *testing.T) {
	jobs, _ := jenkins.GetAllJobs()
	for _, item := range jobs {
		item.InvokeSimple(map[string]string{"param1": "param1"})
		item.Poll()
		isQueued, _ := item.IsQueued()
		assert.Equal(t, true, isQueued)

		time.Sleep(10 * time.Second)
		builds, _ := item.GetAllBuildIds()

		assert.True(t, (len(builds) > 0))

	}
}

func TestCreateViews(t *testing.T) {
	list_view, err := jenkins.CreateView("test_list_view", LIST_VIEW)
	assert.Nil(t, err)
	assert.Equal(t, "test_list_view", list_view.GetName())
	assert.Equal(t, "", list_view.GetDescription())
	assert.Equal(t, 0, len(list_view.GetJobs()))

	my_view, err := jenkins.CreateView("test_my_view", MY_VIEW)
	assert.Nil(t, err)
	assert.Equal(t, "test_my_view", my_view.GetName())
	assert.Equal(t, "", my_view.GetDescription())
	assert.Equal(t, 2, len(my_view.GetJobs()))

}

func TestGetAllJobs(t *testing.T) {
	jobs, _ := jenkins.GetAllJobs()
	assert.Equal(t, 2, len(jobs))
	assert.Equal(t, jobs[0].Raw.Color, "blue")
}

func TestGetAllNodes(t *testing.T) {
	nodes, _ := jenkins.GetAllNodes()
	assert.Equal(t, 3, len(nodes))
	assert.Equal(t, nodes[0].GetName(), "master")
}

func TestGetAllBuilds(t *testing.T) {
	builds, _ := jenkins.GetAllBuildIds("Job1_test")
	for _, b := range builds {
		build, _ := jenkins.GetBuild("Job1_test", b.Number)
		assert.Equal(t, "SUCCESS", build.GetResult())
	}
	assert.Equal(t, 1, len(builds))
}

func TestBuildMethods(t *testing.T) {
	job, _ := jenkins.GetJob("Job1_test")
	build, _ := job.GetLastBuild()
	params := build.GetParameters()
	assert.Equal(t, "params1", params[0].Name)
}

func TestGetSingleJob(t *testing.T) {
	job, _ := jenkins.GetJob("Job1_test")
	isRunning, _ := job.IsRunning()
	config, _ := job.GetConfig()
	assert.Equal(t, false, isRunning)
	assert.Contains(t, config, "<project>")
}

func TestEnableDisableJob(t *testing.T) {
	job, _ := jenkins.GetJob("Job1_test")
	result, _ := job.Disable()
	assert.Equal(t, true, result)
	result, _ = job.Enable()
	assert.Equal(t, true, result)
}

func TestCopyDeleteJob(t *testing.T) {
	job, _ := jenkins.GetJob("Job1_test")
	jobCopy, _ := job.Copy("Job1_test_copy")
	assert.Equal(t, jobCopy.GetName(), "Job1_test_copy")
	jobDelete, _ := job.Delete()
	assert.Equal(t, true, jobDelete)
}

func TestGetPlugins(t *testing.T) {
	plugins, _ := jenkins.GetPlugins(3)
	assert.Equal(t, 19, plugins.Count())
}

func TestGetViews(t *testing.T) {
	views, _ := jenkins.GetAllViews()
	assert.Equal(t, len(views), 3)
	assert.Equal(t, len(views[0].Raw.Jobs), 2)
}

func TestGetSingleView(t *testing.T) {
	view, _ := jenkins.GetView("All")
	view2, _ := jenkins.GetView("test_list_view")
	assert.Equal(t, len(view.Raw.Jobs), 2)
	assert.Equal(t, len(view2.Raw.Jobs), 0)
	assert.Equal(t, view2.Raw.Name, "test_list_view")
}

func getFileAsString(path string) string {
	buf, err := ioutil.ReadFile("_tests/" + path)
	if err != nil {
		panic(err)
	}

	return string(buf)
}

func getRandomString(n int) string {
	rand.Seed(time.Now().UnixNano())
	letters := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

	b := make([]rune, n)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}
<commit_msg>change create node test case<commit_after>package gojenkins

import (
	"fmt"
	"github.com/stretchr/testify/assert"
	"io/ioutil"
	"math/rand"
	"testing"
	"time"
)

var (
	jenkins *Jenkins
)

func TestInit(t *testing.T) {
	jenkins = CreateJenkins("http://localhost:8080", "admin", "admin")
	_, err := jenkins.Init()
	assert.Nil(t, err, "Jenkins Initialization should not fail")
}

func TestCreateJobs(t *testing.T) {
	job1ID := "Job1_test"
	job2ID := "Job2_test"
	job_data := getFileAsString("job.xml")

	job1, err := jenkins.CreateJob(job_data, job1ID)
	if err != nil {
		fmt.Print(err)
	}
	assert.Equal(t, "Some Job Description", job1.GetDescription())
	assert.Equal(t, job1ID, job1.GetName())

	job2, _ := jenkins.CreateJob(job_data, job2ID)
	assert.Equal(t, "Some Job Description", job2.GetDescription())
	assert.Equal(t, job2ID, job2.GetName())
}

func TestCreateNodes(t *testing.T) {

	id1 := "node1_test"
	id2 := "node2_test"

	jnlp := map[string]string{"method": "JNLPLauncher"}
	ssh := map[string]string{"method": "SSHLaucher"}

	node1, _ := jenkins.CreateNode(id1, 1, "Node 1 Description", "/var/lib/jenkins", jnlp)
	assert.Equal(t, id1, node1.GetName())

	node2, _ := jenkins.CreateNode(id2, 1, "Node 2 Description", "/var/lib/jenkins", ssh)
	assert.Equal(t, id2, node2.GetName())
}

func TestCreateBuilds(t *testing.T) {
	jobs, _ := jenkins.GetAllJobs()
	for _, item := range jobs {
		item.InvokeSimple(map[string]string{"param1": "param1"})
		item.Poll()
		isQueued, _ := item.IsQueued()
		assert.Equal(t, true, isQueued)

		time.Sleep(10 * time.Second)
		builds, _ := item.GetAllBuildIds()

		assert.True(t, (len(builds) > 0))

	}
}

func TestCreateViews(t *testing.T) {
	list_view, err := jenkins.CreateView("test_list_view", LIST_VIEW)
	assert.Nil(t, err)
	assert.Equal(t, "test_list_view", list_view.GetName())
	assert.Equal(t, "", list_view.GetDescription())
	assert.Equal(t, 0, len(list_view.GetJobs()))

	my_view, err := jenkins.CreateView("test_my_view", MY_VIEW)
	assert.Nil(t, err)
	assert.Equal(t, "test_my_view", my_view.GetName())
	assert.Equal(t, "", my_view.GetDescription())
	assert.Equal(t, 2, len(my_view.GetJobs()))

}

func TestGetAllJobs(t *testing.T) {
	jobs, _ := jenkins.GetAllJobs()
	assert.Equal(t, 2, len(jobs))
	assert.Equal(t, jobs[0].Raw.Color, "blue")
}

func TestGetAllNodes(t *testing.T) {
	nodes, _ := jenkins.GetAllNodes()
	assert.Equal(t, 3, len(nodes))
	assert.Equal(t, nodes[0].GetName(), "master")
}

func TestGetAllBuilds(t *testing.T) {
	builds, _ := jenkins.GetAllBuildIds("Job1_test")
	for _, b := range builds {
		build, _ := jenkins.GetBuild("Job1_test", b.Number)
		assert.Equal(t, "SUCCESS", build.GetResult())
	}
	assert.Equal(t, 1, len(builds))
}

func TestBuildMethods(t *testing.T) {
	job, _ := jenkins.GetJob("Job1_test")
	build, _ := job.GetLastBuild()
	params := build.GetParameters()
	assert.Equal(t, "params1", params[0].Name)
}

func TestGetSingleJob(t *testing.T) {
	job, _ := jenkins.GetJob("Job1_test")
	isRunning, _ := job.IsRunning()
	config, _ := job.GetConfig()
	assert.Equal(t, false, isRunning)
	assert.Contains(t, config, "<project>")
}

func TestEnableDisableJob(t *testing.T) {
	job, _ := jenkins.GetJob("Job1_test")
	result, _ := job.Disable()
	assert.Equal(t, true, result)
	result, _ = job.Enable()
	assert.Equal(t, true, result)
}

func TestCopyDeleteJob(t *testing.T) {
	job, _ := jenkins.GetJob("Job1_test")
	jobCopy, _ := job.Copy("Job1_test_copy")
	assert.Equal(t, jobCopy.GetName(), "Job1_test_copy")
	jobDelete, _ := job.Delete()
	assert.Equal(t, true, jobDelete)
}

func TestGetPlugins(t *testing.T) {
	plugins, _ := jenkins.GetPlugins(3)
	assert.Equal(t, 19, plugins.Count())
}

func TestGetViews(t *testing.T) {
	views, _ := jenkins.GetAllViews()
	assert.Equal(t, len(views), 3)
	assert.Equal(t, len(views[0].Raw.Jobs), 2)
}

func TestGetSingleView(t *testing.T) {
	view, _ := jenkins.GetView("All")
	view2, _ := jenkins.GetView("test_list_view")
	assert.Equal(t, len(view.Raw.Jobs), 2)
	assert.Equal(t, len(view2.Raw.Jobs), 0)
	assert.Equal(t, view2.Raw.Name, "test_list_view")
}

func getFileAsString(path string) string {
	buf, err := ioutil.ReadFile("_tests/" + path)
	if err != nil {
		panic(err)
	}

	return string(buf)
}

func getRandomString(n int) string {
	rand.Seed(time.Now().UnixNano())
	letters := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

	b := make([]rune, n)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}
<|endoftext|>


<commit_before>package expect

import (
	"flag"
	"fmt"
	"github.com/wsxiaoys/terminal/color"
	"os"
	"reflect"
	"regexp"
	"runtime"
	"strings"
	"testing"
	"time"
)

var (
	showStdout = flag.Bool("vv", false, "Regular expression selecting which tests to run")
	matchFlag  = flag.String("m", "", "Regular expression selecting which tests to run")
	pattern    *regexp.Regexp
	runner     *Runner
	stdout     = os.Stdout
	silentOut  *os.File
	beforeEach = make([]func(), 0, 2)
)

func init() {
	flag.Parse()
	pattern = regexp.MustCompile("(?i)" + *matchFlag)
	if *showStdout == true {
		silentOut = stdout
	}
	os.Stdout = silentOut
}

func Expectify(suite interface{}, t *testing.T) {
	var name string
	var res *result
	defer func() {
		if err := recover(); err != nil {
			os.Stdout = stdout
			if res != nil {
				res.Report()
			}
			color.Printf("@R 💣  %-75s\n", name)
			panic(err)
		}
	}()

	tp := reflect.TypeOf(suite)
	sv := reflect.ValueOf(suite)
	count := tp.NumMethod()

	runner = &Runner{
		results: make([]*result, 0, 10),
	}

	each, _ := tp.MethodByName("Each")
	if each.Func.IsValid() && each.Type.NumIn() != 2 {
		each = reflect.Method{}
	}

	announced := false
	for i := 0; i < count; i++ {
		method := tp.Method(i)
		// this method is not exported
		if len(method.PkgPath) != 0 {
			continue
		}
		name = method.Name
		if pattern.MatchString(name) == false || method.Type.NumIn() != 1 {
			continue
		}
		os.Stdout = stdout
		res = runner.Start(name)
		var f = func() {
			method.Func.Call([]reflect.Value{sv})
			if runner.End() == false || testing.Verbose() {
				if announced == false {
					color.Printf("\n@!%s@|\n", sv.Elem().Type().String())
					announced = true
				}
				res.Report()
			}
		}
		for i := 0; i < len(beforeEach); i++ {
			beforeEach[i]()
		}
		if each.Func.IsValid() {
			each.Func.Call([]reflect.Value{sv, reflect.ValueOf(f)})
		} else {
			f()
		}
		os.Stdout = silentOut
	}
	if runner.Passed() == false {
		os.Stdout = stdout
		fmt.Println("")
		os.Stdout = silentOut
		t.Fail()
	}
}

func BeforeEach(f func()) {
	beforeEach = append(beforeEach, f)
}

type Runner struct {
	results []*result
	current *result
}

func (r *Runner) Start(name string) *result {
	r.current = &result{
		method:   name,
		start:    time.Now(),
		failures: make([]*Failure, 0, 3),
	}
	r.results = append(r.results, r.current)
	return r.current
}

func (r *Runner) End() bool {
	r.current.end = time.Now()
	passed := r.current.Passed()
	r.current = nil
	return passed
}

func (r *Runner) Passed() bool {
	for _, result := range r.results {
		if result.Passed() == false {
			return false
		}
	}
	return true
}

func (r *Runner) Skip(format string, args ...interface{}) {
	if r.current != nil {
		r.current.Skip(format, args...)
	}
}

func (r *Runner) Errorf(format string, args ...interface{}) {
	file := "???"
	line := 1
	ok := false
	for i := 3; i < 10; i++ {
		_, file, line, ok = runtime.Caller(i)
		if ok == false || strings.HasSuffix(file, "_test.go") {
			break
		}
	}

	if ok {
		if index := strings.LastIndex(file, "/"); index >= 0 {
			file = file[index+1:]
		} else if index = strings.LastIndex(file, "\\"); index >= 0 {
			file = file[index+1:]
		}
	}

	failure := &Failure{
		message:  fmt.Sprintf(format, args...),
		location: fmt.Sprintf("%s:%d", file, line),
	}
	r.current.failures = append(r.current.failures, failure)
}

func (r *Runner) ErrorMessage(format string, args ...interface{}) {
	if r.current != nil {
		r.current.ErrorMessage(format, args...)
	}
}

type result struct {
	method      string
	failures    []*Failure
	start       time.Time
	end         time.Time
	skipMessage string
	skip        bool
}

type Failure struct {
	message  string
	location string
}

func (r *result) Skip(format string, args ...interface{}) {
	r.skip = true
	r.skipMessage = fmt.Sprintf(format, args...)
}

func (r *result) Passed() bool {
	return r.skip || len(r.failures) == 0
}

func (r *result) ErrorMessage(format string, args ...interface{}) {
	l := len(r.failures)
	if l > 0 {
		r.failures[l-1].message = fmt.Sprintf(format, args...)
	}
}

func (r *result) Report() {
	if r.end.IsZero() {
		r.end = time.Now()
	}
	info := fmt.Sprintf(" %-70s%dms", r.method, r.end.Sub(r.start).Nanoseconds()/1000000)
	if r.skip {
		color.Println(" @y⸚" + info)
		color.Println("   @." + r.skipMessage)
	} else if r.Passed() {
		color.Println(" @g✓" + info)
	} else {
		color.Println(" @r×" + info)
		for _, failure := range r.failures {
			color.Printf("   @.%-40s%s\n", failure.location, failure.message)
		}
	}
}
<commit_msg>failure summary<commit_after>package expect

import (
	"flag"
	"fmt"
	"github.com/wsxiaoys/terminal/color"
	"os"
	"reflect"
	"regexp"
	"runtime"
	"strings"
	"testing"
	"time"
)

var (
	showStdout = flag.Bool("vv", false, "Regular expression selecting which tests to run")
	matchFlag  = flag.String("m", "", "Regular expression selecting which tests to run")
	pattern    *regexp.Regexp
	runner     *Runner
	stdout     = os.Stdout
	silentOut  *os.File
	beforeEach = make([]func(), 0, 2)
)

func init() {
	flag.Parse()
	pattern = regexp.MustCompile("(?i)" + *matchFlag)
	if *showStdout == true {
		silentOut = stdout
	}
	os.Stdout = silentOut
}

func Expectify(suite interface{}, t *testing.T) {
	var name string
	var res *result
	defer func() {
		if err := recover(); err != nil {
			os.Stdout = stdout
			if res != nil {
				res.Report()
			}
			color.Printf("@R 💣  %-75s\n", name)
			panic(err)
		}
	}()

	tp := reflect.TypeOf(suite)
	sv := reflect.ValueOf(suite)
	count := tp.NumMethod()

	runner = &Runner{
		results: make([]*result, 0, 10),
	}

	each, _ := tp.MethodByName("Each")
	if each.Func.IsValid() && each.Type.NumIn() != 2 {
		each = reflect.Method{}
	}

	announced := false
	for i := 0; i < count; i++ {
		method := tp.Method(i)
		// this method is not exported
		if len(method.PkgPath) != 0 {
			continue
		}
		name = method.Name
		if pattern.MatchString(name) == false || method.Type.NumIn() != 1 {
			continue
		}
		os.Stdout = stdout
		typeName := sv.Elem().Type().String()
		res = runner.Start(name, typeName)
		var f = func() {
			method.Func.Call([]reflect.Value{sv})
			if runner.End() == false || testing.Verbose() {
				if announced == false {
					color.Printf("\n@!%s@|\n", typeName)
					announced = true
				}
				res.Report()
			}
		}
		for i := 0; i < len(beforeEach); i++ {
			beforeEach[i]()
		}
		if each.Func.IsValid() {
			each.Func.Call([]reflect.Value{sv, reflect.ValueOf(f)})
		} else {
			f()
		}
		os.Stdout = silentOut
	}
	if runner.Passed() == false {
		os.Stdout = stdout
		fmt.Println("\nFailure summary")
		for _, r := range runner.results {
			if r.Passed() == false {
				r.Summary()
			}
		}
		fmt.Println()
		os.Stdout = silentOut
		t.Fail()
	}
}

func BeforeEach(f func()) {
	beforeEach = append(beforeEach, f)
}

type Runner struct {
	results []*result
	current *result
}

func (r *Runner) Start(name string, typeName string) *result {
	r.current = &result{
		method:   name,
		typeName: typeName,
		start:    time.Now(),
		failures: make([]*Failure, 0, 3),
	}
	r.results = append(r.results, r.current)
	return r.current
}

func (r *Runner) End() bool {
	r.current.end = time.Now()
	passed := r.current.Passed()
	r.current = nil
	return passed
}

func (r *Runner) Passed() bool {
	for _, result := range r.results {
		if result.Passed() == false {
			return false
		}
	}
	return true
}

func (r *Runner) Skip(format string, args ...interface{}) {
	if r.current != nil {
		r.current.Skip(format, args...)
	}
}

func (r *Runner) Errorf(format string, args ...interface{}) {
	file := "???"
	line := 1
	ok := false
	for i := 3; i < 10; i++ {
		_, file, line, ok = runtime.Caller(i)
		if ok == false || strings.HasSuffix(file, "_test.go") {
			break
		}
	}

	if ok {
		if index := strings.LastIndex(file, "/"); index >= 0 {
			file = file[index+1:]
		} else if index = strings.LastIndex(file, "\\"); index >= 0 {
			file = file[index+1:]
		}
	}

	failure := &Failure{
		message:  fmt.Sprintf(format, args...),
		location: fmt.Sprintf("%s:%d", file, line),
	}
	r.current.failures = append(r.current.failures, failure)
}

func (r *Runner) ErrorMessage(format string, args ...interface{}) {
	if r.current != nil {
		r.current.ErrorMessage(format, args...)
	}
}

type result struct {
	method      string
	failures    []*Failure
	typeName    string
	start       time.Time
	end         time.Time
	skipMessage string
	skip        bool
}

type Failure struct {
	message  string
	location string
}

func (r *result) Skip(format string, args ...interface{}) {
	r.skip = true
	r.skipMessage = fmt.Sprintf(format, args...)
}

func (r *result) Passed() bool {
	return r.skip || len(r.failures) == 0
}

func (r *result) ErrorMessage(format string, args ...interface{}) {
	l := len(r.failures)
	if l > 0 {
		r.failures[l-1].message = fmt.Sprintf(format, args...)
	}
}

func (r *result) Report() {
	if r.end.IsZero() {
		r.end = time.Now()
	}
	info := fmt.Sprintf(" %-70s%dms", r.method, r.end.Sub(r.start).Nanoseconds()/1000000)
	if r.skip {
		color.Println(" @y⸚", info)
		color.Println("   @." + r.skipMessage)
	} else if r.Passed() {
		color.Println(" @g✓", info)
	} else {
		color.Println(" @r×", info)
		for _, failure := range r.failures {
			color.Printf("    @.%-40s%s\n", failure.location, failure.message)
		}
	}
}

func (r *result) Summary() {
	info := fmt.Sprintf(" %s.%-40s", r.typeName, r.method)
	if r.skip {
		color.Println(" @y⸚", info)
	} else if r.Passed() {
		color.Println(" @g✓", info)
	} else {
		color.Print(" @r×", info)
		color.Printf("%2d\n", len(r.failures))
	}
}
<|endoftext|>


<commit_before>package jobutil

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"time"
)

func Check(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

const POLL_INTERVAL = 2000

func encode(jobname string) []byte {
	list := make([]interface{}, 2)
	list[0] = POLL_INTERVAL
	list[1] = []string{jobname}
	json_jobname, err := json.Marshal(list)
	Check(err)
	return json_jobname
}

func decode_response(input []byte) (status string, results []string) {
	result := make([]interface{}, 1)
	err := json.Unmarshal(input, &result)
	Check(err)
	input0 := result[0].([]interface{})
	// jobname := input0[0].(string)

	result_list := input0[1].([]interface{})
	status = result_list[0].(string)
	inter0 := result_list[1].([]interface{})
	if len(inter0) == 0 {
		results = []string{""}
	} else {
		inter1 := inter0[0].([]interface{})
		results = make([]string, len(inter1))
		for i, item := range inter1 {
			results[i] = item.(string)
		}
	}
	return
}

func get_results(c chan []string, errChan chan error, url string, reqBody []byte) {
	resp, err := http.Post(url, "application/json", bytes.NewReader(reqBody))
	defer resp.Body.Close()
	// TODO only retry on certain errors
	if err != nil || resp.StatusCode != http.StatusOK {
		time.Sleep(time.Duration(POLL_INTERVAL) * time.Millisecond)
		get_results(c, errChan, url, reqBody)
	}
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		errChan <- err
	}
	status, inputs := decode_response(body)
	if status == "active" {
		time.Sleep(time.Duration(POLL_INTERVAL) * time.Millisecond)
		get_results(c, errChan, url, reqBody)

	} else if status == "ready" {
		c <- inputs
	}
}

type TimeOut struct {
}

func (t *TimeOut) Error() string {
	return "time out"
}

func Wait(master string, jobname string, timeout time.Duration) ([]string, error) {
	encoded := encode(jobname)
	url := master + "/disco/ctrl/get_results"
	c := make(chan []string)
	errChan := make(chan error)
	go get_results(c, errChan, url, encoded)
	select {
	case <-time.After(timeout * time.Second):
		return nil, new(TimeOut)
	case outputs := <-c:
		return outputs, nil
	case err := <-errChan:
		return nil, err
	}
}
<commit_msg>Do not close the response body if an error occurs.<commit_after>package jobutil

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"time"
)

func Check(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

const POLL_INTERVAL = 2000

func encode(jobname string) []byte {
	list := make([]interface{}, 2)
	list[0] = POLL_INTERVAL
	list[1] = []string{jobname}
	json_jobname, err := json.Marshal(list)
	Check(err)
	return json_jobname
}

func decode_response(input []byte) (status string, results []string) {
	result := make([]interface{}, 1)
	err := json.Unmarshal(input, &result)
	Check(err)
	input0 := result[0].([]interface{})
	// jobname := input0[0].(string)

	result_list := input0[1].([]interface{})
	status = result_list[0].(string)
	inter0 := result_list[1].([]interface{})
	if len(inter0) == 0 {
		results = []string{""}
	} else {
		inter1 := inter0[0].([]interface{})
		results = make([]string, len(inter1))
		for i, item := range inter1 {
			results[i] = item.(string)
		}
	}
	return
}

func get_results(c chan []string, errChan chan error, url string, reqBody []byte) {
	resp, err := http.Post(url, "application/json", bytes.NewReader(reqBody))
	// TODO only retry on certain errors
	if err != nil {
		time.Sleep(time.Duration(POLL_INTERVAL) * time.Millisecond)
		get_results(c, errChan, url, reqBody)
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		time.Sleep(time.Duration(POLL_INTERVAL) * time.Millisecond)
		get_results(c, errChan, url, reqBody)
	}
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		errChan <- err
	}
	status, inputs := decode_response(body)
	if status == "active" {
		time.Sleep(time.Duration(POLL_INTERVAL) * time.Millisecond)
		get_results(c, errChan, url, reqBody)

	} else if status == "ready" {
		c <- inputs
	}
}

type TimeOut struct {
}

func (t *TimeOut) Error() string {
	return "time out"
}

func Wait(master string, jobname string, timeout time.Duration) ([]string, error) {
	encoded := encode(jobname)
	url := master + "/disco/ctrl/get_results"
	c := make(chan []string)
	errChan := make(chan error)
	go get_results(c, errChan, url, encoded)
	select {
	case <-time.After(timeout * time.Second):
		return nil, new(TimeOut)
	case outputs := <-c:
		return outputs, nil
	case err := <-errChan:
		return nil, err
	}
}
<|endoftext|>