<commit_before>package moves

import (
	"errors"
	"github.com/jkomoros/boardgame"
)

//CurrentPhaseSetter should be implemented by you gameState to set the
//CurrentPhase. Must be implemented if you use the StartPhase move type.
type CurrentPhaseSetter interface {
	SetCurrentPhase(int)
}

//PhaseToEnterer should be implemented by moves that embed moves.StartPhase to
//configure which phase to enter.
type PhaseToEnterer interface {
	PhaseToEnter(currentPhase int) int
}

//StartPhase is a simple move, often used in game SetUp phases, to advance to
//the next phase, as returned by the embedding move's PhaseToEnter().
type StartPhase struct {
	Base
}

func (s *StartPhase) ValidConfiguration(exampleState boardgame.MutableState) error {
	embeddingMove := s.Info().Type().NewMove(exampleState)

	if _, ok := embeddingMove.(PhaseToEnterer); !ok {
		return errors.New("The embedding move does not implement PhaseToEnterer")
	}

	if _, ok := exampleState.GameState().(CurrentPhaseSetter); !ok {
		return errors.New("The gameState does not implement CurrentPhaseSetter")
	}

	return nil
}

func (s *StartPhase) Apply(state boardgame.MutableState) error {
	embeddingMove := s.Info().Type().NewMove(state)

	phaseEnterer, ok := embeddingMove.(PhaseToEnterer)

	if !ok {
		return errors.New("The embedding move does not implement PhaseToEnterer")
	}

	currentPhase := state.Game().Manager().Delegate().CurrentPhase(state)

	phaseToEnter := phaseEnterer.PhaseToEnter(currentPhase)

	phaseSetter, ok := state.GameState().(CurrentPhaseSetter)

	if !ok {
		return errors.New("The gameState does not implement CurrentPhaseSetter")
	}

	phaseSetter.SetCurrentPhase(phaseToEnter)

	return nil
}
<commit_msg>moves.StartPhase also grows a BeforeLeavePhaser and BeforeEnterPhaser that are hooks before changing phases. Part of #516.<commit_after>package moves

import (
	"errors"
	"github.com/jkomoros/boardgame"
)

//CurrentPhaseSetter should be implemented by you gameState to set the
//CurrentPhase. Must be implemented if you use the StartPhase move type.
type CurrentPhaseSetter interface {
	SetCurrentPhase(int)
}

//PhaseToEnterer should be implemented by moves that embed moves.StartPhase to
//configure which phase to enter.
type PhaseToEnterer interface {
	PhaseToEnter(currentPhase int) int
}

//BeforeLeavePhaser is an interface to implement on GameState if you want to
//do some action on state before leaving the given phase.
type BeforeLeavePhaser interface {
	BeforeLeavePhase(phase int, state boardgame.MutableState) error
}

//BeforeEnterPhaser is an interface to implement on GameState if you want to
//do some action on state just before entering the givenn state.
type BeforeEnterPhaser interface {
	BeforeEnterPhase(phase int, state boardgame.MutableState) error
}

//StartPhase is a simple move, often used in game SetUp phases, to advance to
//the next phase, as returned by the embedding move's PhaseToEnter(). If
//BeforeLeavePhase or BeforeEnterPhase are defined they will be called at the
//appropriate time.
type StartPhase struct {
	Base
}

func (s *StartPhase) ValidConfiguration(exampleState boardgame.MutableState) error {
	embeddingMove := s.Info().Type().NewMove(exampleState)

	if _, ok := embeddingMove.(PhaseToEnterer); !ok {
		return errors.New("The embedding move does not implement PhaseToEnterer")
	}

	if _, ok := exampleState.GameState().(CurrentPhaseSetter); !ok {
		return errors.New("The gameState does not implement CurrentPhaseSetter")
	}

	return nil
}

func (s *StartPhase) Apply(state boardgame.MutableState) error {
	embeddingMove := s.Info().Type().NewMove(state)

	phaseEnterer, ok := embeddingMove.(PhaseToEnterer)

	if !ok {
		return errors.New("The embedding move does not implement PhaseToEnterer")
	}

	currentPhase := state.Game().Manager().Delegate().CurrentPhase(state)

	phaseToEnter := phaseEnterer.PhaseToEnter(currentPhase)

	phaseSetter, ok := state.GameState().(CurrentPhaseSetter)

	if !ok {
		return errors.New("The gameState does not implement CurrentPhaseSetter")
	}

	beforeLeaver, ok := state.GameState().(BeforeLeavePhaser)

	if ok {
		if err := beforeLeaver.BeforeLeavePhase(currentPhase, state); err != nil {
			return errors.New("Before Leave Phase errored: " + err.Error())
		}
	}

	beforeEnterer, ok := state.GameState().(BeforeEnterPhaser)

	if ok {
		if err := beforeEnterer.BeforeEnterPhase(phaseToEnter, state); err != nil {
			return errors.New("Before Enter Phase errored: " + err.Error())
		}
	}

	phaseSetter.SetCurrentPhase(phaseToEnter)

	return nil
}
<|endoftext|>


<commit_before>package routing

import (
	"reflect"
	"testing"

	"github.com/davecgh/go-spew/spew"
	"github.com/lightningnetwork/lnd/lnwire"

	"github.com/lightningnetwork/lnd/routing/route"
)

var (
	hops = []route.Vertex{
		{1, 0}, {1, 1}, {1, 2}, {1, 3}, {1, 4},
	}

	routeOneHop = route.Route{
		SourcePubKey: hops[0],
		TotalAmount:  100,
		Hops: []*route.Hop{
			{PubKeyBytes: hops[1], AmtToForward: 99},
		},
	}

	routeTwoHop = route.Route{
		SourcePubKey: hops[0],
		TotalAmount:  100,
		Hops: []*route.Hop{
			{PubKeyBytes: hops[1], AmtToForward: 99},
			{PubKeyBytes: hops[2], AmtToForward: 97},
		},
	}

	routeThreeHop = route.Route{
		SourcePubKey: hops[0],
		TotalAmount:  100,
		Hops: []*route.Hop{
			{PubKeyBytes: hops[1], AmtToForward: 99},
			{PubKeyBytes: hops[2], AmtToForward: 97},
			{PubKeyBytes: hops[3], AmtToForward: 94},
		},
	}

	routeFourHop = route.Route{
		SourcePubKey: hops[0],
		TotalAmount:  100,
		Hops: []*route.Hop{
			{PubKeyBytes: hops[1], AmtToForward: 99},
			{PubKeyBytes: hops[2], AmtToForward: 97},
			{PubKeyBytes: hops[3], AmtToForward: 94},
			{PubKeyBytes: hops[4], AmtToForward: 90},
		},
	}
)

func getTestPair(from, to int) DirectedNodePair {
	return NewDirectedNodePair(hops[from], hops[to])
}

func getPolicyFailure(from, to int) *DirectedNodePair {
	pair := getTestPair(from, to)
	return &pair
}

type resultTestCase struct {
	name          string
	route         *route.Route
	success       bool
	failureSrcIdx int
	failure       lnwire.FailureMessage

	expectedResult *interpretedResult
}

var resultTestCases = []resultTestCase{
	// Tests that a temporary channel failure result is properly
	// interpreted.
	{
		name:          "fail",
		route:         &routeTwoHop,
		failureSrcIdx: 1,
		failure:       lnwire.NewTemporaryChannelFailure(nil),

		expectedResult: &interpretedResult{
			pairResults: map[DirectedNodePair]pairResult{
				getTestPair(0, 1): successPairResult(100),
				getTestPair(1, 2): failPairResult(99),
			},
		},
	},

	// Tests that a expiry too soon failure result is properly interpreted.
	{
		name:          "fail expiry too soon",
		route:         &routeFourHop,
		failureSrcIdx: 3,
		failure:       lnwire.NewExpiryTooSoon(lnwire.ChannelUpdate{}),

		expectedResult: &interpretedResult{
			pairResults: map[DirectedNodePair]pairResult{
				getTestPair(0, 1): failPairResult(0),
				getTestPair(1, 0): failPairResult(0),
				getTestPair(1, 2): failPairResult(0),
				getTestPair(2, 1): failPairResult(0),
				getTestPair(2, 3): failPairResult(0),
				getTestPair(3, 2): failPairResult(0),
			},
		},
	},

	// Tests an incorrect payment details result. This should be a final
	// failure, but mark all pairs along the route as successful.
	{
		name:          "fail incorrect details",
		route:         &routeTwoHop,
		failureSrcIdx: 2,
		failure:       lnwire.NewFailIncorrectDetails(97, 0),

		expectedResult: &interpretedResult{
			pairResults: map[DirectedNodePair]pairResult{
				getTestPair(0, 1): successPairResult(100),
				getTestPair(1, 2): successPairResult(99),
			},
			finalFailureReason: &reasonIncorrectDetails,
		},
	},

	// Tests a successful direct payment.
	{
		name:    "success direct",
		route:   &routeOneHop,
		success: true,

		expectedResult: &interpretedResult{
			pairResults: map[DirectedNodePair]pairResult{
				getTestPair(0, 1): successPairResult(100),
			},
		},
	},

	// Tests a successful two hop payment.
	{
		name:    "success",
		route:   &routeTwoHop,
		success: true,

		expectedResult: &interpretedResult{
			pairResults: map[DirectedNodePair]pairResult{
				getTestPair(0, 1): successPairResult(100),
				getTestPair(1, 2): successPairResult(99),
			},
		},
	},

	// Tests a malformed htlc from a direct peer.
	{
		name:          "fail malformed htlc from direct peer",
		route:         &routeTwoHop,
		failureSrcIdx: 0,
		failure:       lnwire.NewInvalidOnionKey(nil),

		expectedResult: &interpretedResult{
			nodeFailure: &hops[1],
			pairResults: map[DirectedNodePair]pairResult{
				getTestPair(1, 0): failPairResult(0),
				getTestPair(1, 2): failPairResult(0),
				getTestPair(0, 1): failPairResult(0),
				getTestPair(2, 1): failPairResult(0),
			},
		},
	},

	// Tests a malformed htlc from a direct peer that is also the final
	// destination.
	{
		name:          "fail malformed htlc from direct final peer",
		route:         &routeOneHop,
		failureSrcIdx: 0,
		failure:       lnwire.NewInvalidOnionKey(nil),

		expectedResult: &interpretedResult{
			finalFailureReason: &reasonError,
			nodeFailure:        &hops[1],
			pairResults: map[DirectedNodePair]pairResult{
				getTestPair(1, 0): failPairResult(0),
				getTestPair(0, 1): failPairResult(0),
			},
		},
	},

	// Tests that a fee insufficient failure to an intermediate hop with
	// index 2 results in the first hop marked as success, and then a
	// bidirectional failure for the incoming channel. It should also result
	// in a policy failure for the outgoing hop.
	{
		name:          "fail fee insufficient intermediate",
		route:         &routeFourHop,
		failureSrcIdx: 2,
		failure:       lnwire.NewFeeInsufficient(0, lnwire.ChannelUpdate{}),

		expectedResult: &interpretedResult{
			pairResults: map[DirectedNodePair]pairResult{
				getTestPair(0, 1): {
					success: true,
					amt:     100,
				},
				getTestPair(1, 2): {},
				getTestPair(2, 1): {},
			},
			policyFailure: getPolicyFailure(2, 3),
		},
	},

	// Tests an invalid onion payload from a final hop. The final hop should
	// be failed while the proceeding hops are reproed as successes. The
	// failure is terminal since the receiver can't process our onion.
	{
		name:          "fail invalid onion payload final hop four",
		route:         &routeFourHop,
		failureSrcIdx: 4,
		failure:       lnwire.NewInvalidOnionPayload(0, 0),

		expectedResult: &interpretedResult{
			pairResults: map[DirectedNodePair]pairResult{
				getTestPair(0, 1): {
					success: true,
					amt:     100,
				},
				getTestPair(1, 2): {
					success: true,
					amt:     99,
				},
				getTestPair(2, 3): {
					success: true,
					amt:     97,
				},
				getTestPair(4, 3): {},
				getTestPair(3, 4): {},
			},
			finalFailureReason: &reasonError,
			nodeFailure:        &hops[4],
		},
	},

	// Tests an invalid onion payload from a final hop on a three hop route.
	{
		name:          "fail invalid onion payload final hop three",
		route:         &routeThreeHop,
		failureSrcIdx: 3,
		failure:       lnwire.NewInvalidOnionPayload(0, 0),

		expectedResult: &interpretedResult{
			pairResults: map[DirectedNodePair]pairResult{
				getTestPair(0, 1): {
					success: true,
					amt:     100,
				},
				getTestPair(1, 2): {
					success: true,
					amt:     99,
				},
				getTestPair(3, 2): {},
				getTestPair(2, 3): {},
			},
			finalFailureReason: &reasonError,
			nodeFailure:        &hops[3],
		},
	},

	// Tests an invalid onion payload from an intermediate hop. Only the
	// reporting node should be failed. The failure is non-terminal since we
	// can still try other paths.
	{
		name:          "fail invalid onion payload intermediate",
		route:         &routeFourHop,
		failureSrcIdx: 3,
		failure:       lnwire.NewInvalidOnionPayload(0, 0),

		expectedResult: &interpretedResult{
			pairResults: map[DirectedNodePair]pairResult{
				getTestPair(0, 1): {
					success: true,
					amt:     100,
				},
				getTestPair(1, 2): {
					success: true,
					amt:     99,
				},
				getTestPair(3, 2): {},
				getTestPair(3, 4): {},
				getTestPair(2, 3): {},
				getTestPair(4, 3): {},
			},
			nodeFailure: &hops[3],
		},
	},

	// Tests an invalid onion payload in a direct peer that is also the
	// final hop. The final node should be failed and the error is terminal
	// since the remote node can't process our onion.
	{
		name:          "fail invalid onion payload direct",
		route:         &routeOneHop,
		failureSrcIdx: 1,
		failure:       lnwire.NewInvalidOnionPayload(0, 0),

		expectedResult: &interpretedResult{
			pairResults: map[DirectedNodePair]pairResult{
				getTestPair(1, 0): {},
				getTestPair(0, 1): {},
			},
			finalFailureReason: &reasonError,
			nodeFailure:        &hops[1],
		},
	},

	// Tests a single hop mpp timeout. Test that final node is not
	// penalized. This is a temporary measure while we decide how to
	// penalize mpp timeouts.
	{
		name:          "one hop mpp timeout",
		route:         &routeOneHop,
		failureSrcIdx: 1,
		failure:       &lnwire.FailMPPTimeout{},

		expectedResult: &interpretedResult{
			pairResults: map[DirectedNodePair]pairResult{
				getTestPair(0, 1): successPairResult(100),
			},
			nodeFailure: nil,
		},
	},

	// Tests a two hop mpp timeout. Test that final node is not penalized
	// and the intermediate hop is attributed the success. This is a
	// temporary measure while we decide how to penalize mpp timeouts.
	{
		name:          "two hop mpp timeout",
		route:         &routeTwoHop,
		failureSrcIdx: 2,
		failure:       &lnwire.FailMPPTimeout{},

		expectedResult: &interpretedResult{
			pairResults: map[DirectedNodePair]pairResult{
				getTestPair(0, 1): successPairResult(100),
				getTestPair(1, 2): successPairResult(99),
			},
			nodeFailure: nil,
		},
	},
}

// TestResultInterpretation executes a list of test cases that test the result
// interpretation logic.
func TestResultInterpretation(t *testing.T) {
	emptyResults := make(map[DirectedNodePair]pairResult)

	for _, testCase := range resultTestCases {
		t.Run(testCase.name, func(t *testing.T) {
			i := interpretResult(
				testCase.route, testCase.success,
				&testCase.failureSrcIdx, testCase.failure,
			)

			expected := testCase.expectedResult

			// Replace nil pairResults with empty map to satisfy
			// DeepEqual.
			if expected.pairResults == nil {
				expected.pairResults = emptyResults
			}

			if !reflect.DeepEqual(i, expected) {
				t.Fatalf("unexpected result\nwant: %v\ngot: %v",
					spew.Sdump(expected), spew.Sdump(i))
			}
		})
	}
}
<commit_msg>routing: add test case for result interpretation of Channel Disabled failure<commit_after>package routing

import (
	"reflect"
	"testing"

	"github.com/davecgh/go-spew/spew"
	"github.com/lightningnetwork/lnd/lnwire"

	"github.com/lightningnetwork/lnd/routing/route"
)

var (
	hops = []route.Vertex{
		{1, 0}, {1, 1}, {1, 2}, {1, 3}, {1, 4},
	}

	routeOneHop = route.Route{
		SourcePubKey: hops[0],
		TotalAmount:  100,
		Hops: []*route.Hop{
			{PubKeyBytes: hops[1], AmtToForward: 99},
		},
	}

	routeTwoHop = route.Route{
		SourcePubKey: hops[0],
		TotalAmount:  100,
		Hops: []*route.Hop{
			{PubKeyBytes: hops[1], AmtToForward: 99},
			{PubKeyBytes: hops[2], AmtToForward: 97},
		},
	}

	routeThreeHop = route.Route{
		SourcePubKey: hops[0],
		TotalAmount:  100,
		Hops: []*route.Hop{
			{PubKeyBytes: hops[1], AmtToForward: 99},
			{PubKeyBytes: hops[2], AmtToForward: 97},
			{PubKeyBytes: hops[3], AmtToForward: 94},
		},
	}

	routeFourHop = route.Route{
		SourcePubKey: hops[0],
		TotalAmount:  100,
		Hops: []*route.Hop{
			{PubKeyBytes: hops[1], AmtToForward: 99},
			{PubKeyBytes: hops[2], AmtToForward: 97},
			{PubKeyBytes: hops[3], AmtToForward: 94},
			{PubKeyBytes: hops[4], AmtToForward: 90},
		},
	}
)

func getTestPair(from, to int) DirectedNodePair {
	return NewDirectedNodePair(hops[from], hops[to])
}

func getPolicyFailure(from, to int) *DirectedNodePair {
	pair := getTestPair(from, to)
	return &pair
}

type resultTestCase struct {
	name          string
	route         *route.Route
	success       bool
	failureSrcIdx int
	failure       lnwire.FailureMessage

	expectedResult *interpretedResult
}

var resultTestCases = []resultTestCase{
	// Tests that a temporary channel failure result is properly
	// interpreted.
	{
		name:          "fail",
		route:         &routeTwoHop,
		failureSrcIdx: 1,
		failure:       lnwire.NewTemporaryChannelFailure(nil),

		expectedResult: &interpretedResult{
			pairResults: map[DirectedNodePair]pairResult{
				getTestPair(0, 1): successPairResult(100),
				getTestPair(1, 2): failPairResult(99),
			},
		},
	},

	// Tests that a expiry too soon failure result is properly interpreted.
	{
		name:          "fail expiry too soon",
		route:         &routeFourHop,
		failureSrcIdx: 3,
		failure:       lnwire.NewExpiryTooSoon(lnwire.ChannelUpdate{}),

		expectedResult: &interpretedResult{
			pairResults: map[DirectedNodePair]pairResult{
				getTestPair(0, 1): failPairResult(0),
				getTestPair(1, 0): failPairResult(0),
				getTestPair(1, 2): failPairResult(0),
				getTestPair(2, 1): failPairResult(0),
				getTestPair(2, 3): failPairResult(0),
				getTestPair(3, 2): failPairResult(0),
			},
		},
	},

	// Tests an incorrect payment details result. This should be a final
	// failure, but mark all pairs along the route as successful.
	{
		name:          "fail incorrect details",
		route:         &routeTwoHop,
		failureSrcIdx: 2,
		failure:       lnwire.NewFailIncorrectDetails(97, 0),

		expectedResult: &interpretedResult{
			pairResults: map[DirectedNodePair]pairResult{
				getTestPair(0, 1): successPairResult(100),
				getTestPair(1, 2): successPairResult(99),
			},
			finalFailureReason: &reasonIncorrectDetails,
		},
	},

	// Tests a successful direct payment.
	{
		name:    "success direct",
		route:   &routeOneHop,
		success: true,

		expectedResult: &interpretedResult{
			pairResults: map[DirectedNodePair]pairResult{
				getTestPair(0, 1): successPairResult(100),
			},
		},
	},

	// Tests a successful two hop payment.
	{
		name:    "success",
		route:   &routeTwoHop,
		success: true,

		expectedResult: &interpretedResult{
			pairResults: map[DirectedNodePair]pairResult{
				getTestPair(0, 1): successPairResult(100),
				getTestPair(1, 2): successPairResult(99),
			},
		},
	},

	// Tests a malformed htlc from a direct peer.
	{
		name:          "fail malformed htlc from direct peer",
		route:         &routeTwoHop,
		failureSrcIdx: 0,
		failure:       lnwire.NewInvalidOnionKey(nil),

		expectedResult: &interpretedResult{
			nodeFailure: &hops[1],
			pairResults: map[DirectedNodePair]pairResult{
				getTestPair(1, 0): failPairResult(0),
				getTestPair(1, 2): failPairResult(0),
				getTestPair(0, 1): failPairResult(0),
				getTestPair(2, 1): failPairResult(0),
			},
		},
	},

	// Tests a malformed htlc from a direct peer that is also the final
	// destination.
	{
		name:          "fail malformed htlc from direct final peer",
		route:         &routeOneHop,
		failureSrcIdx: 0,
		failure:       lnwire.NewInvalidOnionKey(nil),

		expectedResult: &interpretedResult{
			finalFailureReason: &reasonError,
			nodeFailure:        &hops[1],
			pairResults: map[DirectedNodePair]pairResult{
				getTestPair(1, 0): failPairResult(0),
				getTestPair(0, 1): failPairResult(0),
			},
		},
	},

	// Tests that a fee insufficient failure to an intermediate hop with
	// index 2 results in the first hop marked as success, and then a
	// bidirectional failure for the incoming channel. It should also result
	// in a policy failure for the outgoing hop.
	{
		name:          "fail fee insufficient intermediate",
		route:         &routeFourHop,
		failureSrcIdx: 2,
		failure:       lnwire.NewFeeInsufficient(0, lnwire.ChannelUpdate{}),

		expectedResult: &interpretedResult{
			pairResults: map[DirectedNodePair]pairResult{
				getTestPair(0, 1): {
					success: true,
					amt:     100,
				},
				getTestPair(1, 2): {},
				getTestPair(2, 1): {},
			},
			policyFailure: getPolicyFailure(2, 3),
		},
	},

	// Tests an invalid onion payload from a final hop. The final hop should
	// be failed while the proceeding hops are reproed as successes. The
	// failure is terminal since the receiver can't process our onion.
	{
		name:          "fail invalid onion payload final hop four",
		route:         &routeFourHop,
		failureSrcIdx: 4,
		failure:       lnwire.NewInvalidOnionPayload(0, 0),

		expectedResult: &interpretedResult{
			pairResults: map[DirectedNodePair]pairResult{
				getTestPair(0, 1): {
					success: true,
					amt:     100,
				},
				getTestPair(1, 2): {
					success: true,
					amt:     99,
				},
				getTestPair(2, 3): {
					success: true,
					amt:     97,
				},
				getTestPair(4, 3): {},
				getTestPair(3, 4): {},
			},
			finalFailureReason: &reasonError,
			nodeFailure:        &hops[4],
		},
	},

	// Tests an invalid onion payload from a final hop on a three hop route.
	{
		name:          "fail invalid onion payload final hop three",
		route:         &routeThreeHop,
		failureSrcIdx: 3,
		failure:       lnwire.NewInvalidOnionPayload(0, 0),

		expectedResult: &interpretedResult{
			pairResults: map[DirectedNodePair]pairResult{
				getTestPair(0, 1): {
					success: true,
					amt:     100,
				},
				getTestPair(1, 2): {
					success: true,
					amt:     99,
				},
				getTestPair(3, 2): {},
				getTestPair(2, 3): {},
			},
			finalFailureReason: &reasonError,
			nodeFailure:        &hops[3],
		},
	},

	// Tests an invalid onion payload from an intermediate hop. Only the
	// reporting node should be failed. The failure is non-terminal since we
	// can still try other paths.
	{
		name:          "fail invalid onion payload intermediate",
		route:         &routeFourHop,
		failureSrcIdx: 3,
		failure:       lnwire.NewInvalidOnionPayload(0, 0),

		expectedResult: &interpretedResult{
			pairResults: map[DirectedNodePair]pairResult{
				getTestPair(0, 1): {
					success: true,
					amt:     100,
				},
				getTestPair(1, 2): {
					success: true,
					amt:     99,
				},
				getTestPair(3, 2): {},
				getTestPair(3, 4): {},
				getTestPair(2, 3): {},
				getTestPair(4, 3): {},
			},
			nodeFailure: &hops[3],
		},
	},

	// Tests an invalid onion payload in a direct peer that is also the
	// final hop. The final node should be failed and the error is terminal
	// since the remote node can't process our onion.
	{
		name:          "fail invalid onion payload direct",
		route:         &routeOneHop,
		failureSrcIdx: 1,
		failure:       lnwire.NewInvalidOnionPayload(0, 0),

		expectedResult: &interpretedResult{
			pairResults: map[DirectedNodePair]pairResult{
				getTestPair(1, 0): {},
				getTestPair(0, 1): {},
			},
			finalFailureReason: &reasonError,
			nodeFailure:        &hops[1],
		},
	},

	// Tests a single hop mpp timeout. Test that final node is not
	// penalized. This is a temporary measure while we decide how to
	// penalize mpp timeouts.
	{
		name:          "one hop mpp timeout",
		route:         &routeOneHop,
		failureSrcIdx: 1,
		failure:       &lnwire.FailMPPTimeout{},

		expectedResult: &interpretedResult{
			pairResults: map[DirectedNodePair]pairResult{
				getTestPair(0, 1): successPairResult(100),
			},
			nodeFailure: nil,
		},
	},

	// Tests a two hop mpp timeout. Test that final node is not penalized
	// and the intermediate hop is attributed the success. This is a
	// temporary measure while we decide how to penalize mpp timeouts.
	{
		name:          "two hop mpp timeout",
		route:         &routeTwoHop,
		failureSrcIdx: 2,
		failure:       &lnwire.FailMPPTimeout{},

		expectedResult: &interpretedResult{
			pairResults: map[DirectedNodePair]pairResult{
				getTestPair(0, 1): successPairResult(100),
				getTestPair(1, 2): successPairResult(99),
			},
			nodeFailure: nil,
		},
	},

	// Test a channel disabled failure from the final hop in two hops. Only the
	// disabled channel should be penalized for any amount.
	{
		name:          "two hop channel disabled",
		route:         &routeTwoHop,
		failureSrcIdx: 1,
		failure:       &lnwire.FailChannelDisabled{},

		expectedResult: &interpretedResult{
			pairResults: map[DirectedNodePair]pairResult{
				getTestPair(1, 2): failPairResult(0),
				getTestPair(2, 1): failPairResult(0),
			},
			policyFailure: getPolicyFailure(1, 2),
		},
	},
}

// TestResultInterpretation executes a list of test cases that test the result
// interpretation logic.
func TestResultInterpretation(t *testing.T) {
	emptyResults := make(map[DirectedNodePair]pairResult)

	for _, testCase := range resultTestCases {
		t.Run(testCase.name, func(t *testing.T) {
			i := interpretResult(
				testCase.route, testCase.success,
				&testCase.failureSrcIdx, testCase.failure,
			)

			expected := testCase.expectedResult

			// Replace nil pairResults with empty map to satisfy
			// DeepEqual.
			if expected.pairResults == nil {
				expected.pairResults = emptyResults
			}

			if !reflect.DeepEqual(i, expected) {
				t.Fatalf("unexpected result\nwant: %v\ngot: %v",
					spew.Sdump(expected), spew.Sdump(i))
			}
		})
	}
}
<|endoftext|>


<commit_before>package multiverse

import (
	"fmt"
	"runtime"
	"strings"
)

// Ok makes Rarity usable as a Filter.
func (r Rarity) Ok(c *Card) (bool, error) {
	for _, printing := range c.Printings {
		if printing.Rarity == r {
			return true, nil
		}
	}
	return false, nil
}

// Ok makes ManaColor usable as a Filter.
func (m ManaColor) Ok(c *Card) (bool, error) {
	if m == ManaColors.Colorless {
		return c.Colors == 0, nil
	}
	return c.Colors&m != 0, nil
}

// Ok makes SuperType useable as a Filter.
func (s SuperType) Ok(c *Card) (bool, error) {
	return c.Supertypes&s != 0, nil
}

// Ok makes Type usable as a filter.
func (t Type) Ok(c *Card) (bool, error) {
	return c.Types&t != 0, nil
}

// Ok makes MultiverseID usable as a filter.
func (m MultiverseID) Ok(c *Card) (bool, error) {
	for i := range c.Printings {
		if c.Printings[i].ID == m {
			return true, nil
		}
	}
	return false, nil
}

// Filter is a way to search through cards.
type Filter interface {
	Ok(*Card) (bool, error)
}

// Func is a generic type that allows a client to pass in any function that makes a boolean decision based on a card.
type Func func(*Card) bool

// Ok makes a Func usable as a Filter.
func (f Func) Ok(c *Card) (bool, error) {
	return f(c), nil
}

// Search for cards that match the given conditions.
func (m Multiverse) Search(f Filter) (CardList, error) {
	c := m.Cards
	cores := runtime.GOMAXPROCS(-1)
	sectionLen := len(c) / cores

	cardChan := make(chan *Card, 16*cores)
	doneChan := make(chan bool)
	errChan := make(chan error)
	list := make(CardList, 0, 1)

	for i := 0; i < cores; i++ {
		start := sectionLen * i
		end := start + sectionLen

		if i == cores-1 {
			end = len(c)
		}

		go func(start, end int) {
			for j := range c[start:end] {
				ok, err := f.Ok(&c[j+start])
				if err != nil {
					errChan <- err
					return
				}
				if ok {
					cardChan <- &c[j+start]
				}
			}
			doneChan <- true
		}(start, end)
	}

	finishChans := func() {
		for cores > 0 {
			select {
			case <-cardChan:
			case <-errChan:
				cores--
			case <-doneChan:
				cores--
			}
		}

		close(cardChan)
		close(errChan)
		close(doneChan)
	}

	for cores > 0 {
		select {
		case <-doneChan:
			cores--
		case c := <-cardChan:
			list.add(c)
		case err := <-errChan:
			cores--
			go finishChans()
			return nil, err
		}
	}

	close(cardChan)
	close(errChan)
	close(doneChan)

	for c := range cardChan {
		list.add(c)
	}

	list.trim()

	return list, nil
}

// Not allows us to search for exclusive conditions.
type Not struct {
	Filter
}

// Ok makes Not usable as a Filter.
func (n Not) Ok(c *Card) (bool, error) {
	ok, err := n.Filter.Ok(c)
	return !ok, err
}

// And allows us to search for multiple conditions that must be true.
type And []Filter

// Ok makes And usable as a Filter.
func (a And) Ok(c *Card) (bool, error) {
	for _, f := range a {
		ok, err := f.Ok(c)
		if !ok || err != nil {
			return ok, err
		}
	}
	return true, nil
}

// Or allows us to search for multiple conditions that at least one of must be true.
// Performs short-circuit evaluation.
type Or []Filter

// Ok makes Or usable as a Filter.
func (o Or) Ok(c *Card) (bool, error) {
	for _, f := range o {
		ok, err := f.Ok(c)
		if ok || err != nil {
			return ok, err
		}
	}
	return false, nil
}

// Cond provides a way to search for non-builtin properties without resorting to a custom type.
type Cond map[string]interface{}

// Ok makes Cond usable as a Filter.
func (c Cond) Ok(card *Card) (bool, error) {
	for key, val := range c {
		switch key {
		case "color", "colors":
			same, err := handleColorSearch(card.Colors, val)
			if err != nil || !same {
				return same, err
			}
		case "cost":
			if val, ok := val.(string); ok {
				if strings.ToLower(card.Cost) != strings.ToLower(val) {
					return false, nil
				}
			} else {
				println("Unable to convert cost")
			}
		default:
			return false, fmt.Errorf("unsupported search method: %s", key)
		}
	}
	return true, nil
}

func handleColorSearch(cardColor ManaColor, val interface{}) (bool, error) {
	switch val := val.(type) {
	case ManaColor:
		if cardColor&val != 0 {
			return true, nil
		}
		return false, nil
	case string:
		switch strings.ToLower(val) {
		case "red":
			return cardColor&ManaColors.Red != 0, nil
		case "green":
			return cardColor&ManaColors.Green != 0, nil
		case "blue":
			return cardColor&ManaColors.Blue != 0, nil
		case "black":
			return cardColor&ManaColors.Black != 0, nil
		case "white":
			return cardColor&ManaColors.White != 0, nil
		case "colorless":
			return cardColor == 0, nil
		}
	}

	return false, fmt.Errorf("unexpected color type %T", val)
}
<commit_msg>Rearranged file for easier reading.<commit_after>package multiverse

import (
	"fmt"
	"runtime"
	"strings"
)

// Filter is a way to search through cards.
type Filter interface {
	Ok(*Card) (bool, error)
}

// Func is a generic type that allows a client to pass in any function that makes a boolean decision based on a card.
type Func func(*Card) bool

// Ok makes a Func usable as a Filter.
func (f Func) Ok(c *Card) (bool, error) {
	return f(c), nil
}

// Ok makes Rarity usable as a Filter.
func (r Rarity) Ok(c *Card) (bool, error) {
	for _, printing := range c.Printings {
		if printing.Rarity == r {
			return true, nil
		}
	}
	return false, nil
}

// Ok makes ManaColor usable as a Filter.
func (m ManaColor) Ok(c *Card) (bool, error) {
	if m == ManaColors.Colorless {
		return c.Colors == 0, nil
	}
	return c.Colors&m != 0, nil
}

// Ok makes SuperType useable as a Filter.
func (s SuperType) Ok(c *Card) (bool, error) {
	return c.Supertypes&s != 0, nil
}

// Ok makes Type usable as a filter.
func (t Type) Ok(c *Card) (bool, error) {
	return c.Types&t != 0, nil
}

// Ok makes MultiverseID usable as a filter.
func (m MultiverseID) Ok(c *Card) (bool, error) {
	for i := range c.Printings {
		if c.Printings[i].ID == m {
			return true, nil
		}
	}
	return false, nil
}

// Search for cards that match the given conditions.
func (m Multiverse) Search(f Filter) (CardList, error) {
	c := m.Cards
	cores := runtime.GOMAXPROCS(-1)
	sectionLen := len(c) / cores

	cardChan := make(chan *Card, 16*cores)
	doneChan := make(chan bool)
	errChan := make(chan error)
	list := make(CardList, 0, 1)

	for i := 0; i < cores; i++ {
		start := sectionLen * i
		end := start + sectionLen

		if i == cores-1 {
			end = len(c)
		}

		go func(start, end int) {
			for j := range c[start:end] {
				ok, err := f.Ok(&c[j+start])
				if err != nil {
					errChan <- err
					return
				}
				if ok {
					cardChan <- &c[j+start]
				}
			}
			doneChan <- true
		}(start, end)
	}

	finishChans := func() {
		for cores > 0 {
			select {
			case <-cardChan:
			case <-errChan:
				cores--
			case <-doneChan:
				cores--
			}
		}

		close(cardChan)
		close(errChan)
		close(doneChan)
	}

	for cores > 0 {
		select {
		case <-doneChan:
			cores--
		case c := <-cardChan:
			list.add(c)
		case err := <-errChan:
			cores--
			go finishChans()
			return nil, err
		}
	}

	close(cardChan)
	close(errChan)
	close(doneChan)

	for c := range cardChan {
		list.add(c)
	}

	list.trim()

	return list, nil
}

// Not allows us to search for exclusive conditions.
type Not struct {
	Filter
}

// Ok makes Not usable as a Filter.
func (n Not) Ok(c *Card) (bool, error) {
	ok, err := n.Filter.Ok(c)
	return !ok, err
}

// And allows us to search for multiple conditions that must be true.
type And []Filter

// Ok makes And usable as a Filter.
func (a And) Ok(c *Card) (bool, error) {
	for _, f := range a {
		ok, err := f.Ok(c)
		if !ok || err != nil {
			return ok, err
		}
	}
	return true, nil
}

// Or allows us to search for multiple conditions that at least one of must be true.
// Performs short-circuit evaluation.
type Or []Filter

// Ok makes Or usable as a Filter.
func (o Or) Ok(c *Card) (bool, error) {
	for _, f := range o {
		ok, err := f.Ok(c)
		if ok || err != nil {
			return ok, err
		}
	}
	return false, nil
}

// Cond provides a way to search for non-builtin properties without resorting to a custom type.
type Cond map[string]interface{}

// Ok makes Cond usable as a Filter.
func (c Cond) Ok(card *Card) (bool, error) {
	for key, val := range c {
		switch key {
		case "color", "colors":
			same, err := handleColorSearch(card.Colors, val)
			if err != nil || !same {
				return same, err
			}
		case "cost":
			if val, ok := val.(string); ok {
				if strings.ToLower(card.Cost) != strings.ToLower(val) {
					return false, nil
				}
			} else {
				println("Unable to convert cost")
			}
		default:
			return false, fmt.Errorf("unsupported search method: %s", key)
		}
	}
	return true, nil
}

func handleColorSearch(cardColor ManaColor, val interface{}) (bool, error) {
	switch val := val.(type) {
	case ManaColor:
		if cardColor&val != 0 {
			return true, nil
		}
		return false, nil
	case string:
		switch strings.ToLower(val) {
		case "red":
			return cardColor&ManaColors.Red != 0, nil
		case "green":
			return cardColor&ManaColors.Green != 0, nil
		case "blue":
			return cardColor&ManaColors.Blue != 0, nil
		case "black":
			return cardColor&ManaColors.Black != 0, nil
		case "white":
			return cardColor&ManaColors.White != 0, nil
		case "colorless":
			return cardColor == 0, nil
		}
	}

	return false, fmt.Errorf("unexpected color type %T", val)
}
<|endoftext|>


<commit_before>package io

import (
	"bytes"
	"io"
	"os"
	"strings"
)

func SimulateStdin(input string, block func(r io.Reader)) {
	reader, writer := io.Pipe()

	go func() {
		writer.Write([]byte(input))
		defer writer.Close()
	}()

	block(reader)
}

func CaptureOutput(block func()) []string {
	oldSTDOUT := os.Stdout
	r, w, err := os.Pipe()
	if err != nil {
		panic(err)
	}

	os.Stdout = w
	defer func() {
		os.Stdout = oldSTDOUT
	}()

	doneWriting := make(chan bool)
	result := make(chan []string)

	go captureOutputAsyncronously(doneWriting, result, r)

	block()
	w.Close()
	doneWriting <- true
	return <-result
}

/*
 The reason we're doing is that you can't write an infinite amount of bytes into a pipe.
 On some platforms, the limit is fairly high; on other platforms, the limit is infuriatingly small
 (looking at you, Windows). To counteract this, we need to read in a goroutine from one end of
 the pipe and return the result across a channel.
*/
func captureOutputAsyncronously(doneWriting <-chan bool, result chan<- []string, reader io.Reader) {
	var readingString string

	for {
		var buf bytes.Buffer
		io.Copy(&buf, reader)
		readingString += buf.String()

		_, ok := <-doneWriting
		if ok {
			// there is no guarantee that the writer did not
			// write more in between the read above and reading from this channel
			// so we absolute must read once more if we want all the bytes
			var buf bytes.Buffer
			io.Copy(&buf, reader)
			readingString += buf.String()
			break
		}
	}

	result <- strings.Split(readingString, "\n")
}
<commit_msg>Fix capturing terminal output on windows<commit_after>package io

import (
	"bytes"
	"io"
	"os"
	"strings"
	"runtime"
	"github.com/mattn/go-colorable"
	"github.com/fatih/color"
)

func SimulateStdin(input string, block func(r io.Reader)) {
	reader, writer := io.Pipe()

	go func() {
		writer.Write([]byte(input))
		defer writer.Close()
	}()

	block(reader)
}

func CaptureOutput(block func()) []string {
	oldSTDOUT := os.Stdout
	r, w, err := os.Pipe()
	if err != nil {
		panic(err)
	}

	os.Stdout = w
	defer func() {
		os.Stdout = oldSTDOUT
	}()

	//////
	// We use fmt.Fprintf() to write to the "github.com/fatih/color".Output file
	// to get colors on Windows machines.
	// That variable gets initialized with a reference to os.Stdout when that library is imported.
	// That means that when we muck with os.Stdout above, it doesn't get reflected in
	// the printing code for windows.
	// Instead, we can just redeclare that color.Output variable with a colorable version of our
	// redirect pipe.
	if runtime.GOOS == "windows" {
		color.Output = colorable.NewColorable(w)
	}
	//////

	doneWriting := make(chan bool)
	result := make(chan []string)

	go captureOutputAsyncronously(doneWriting, result, r)

	block()
	w.Close()
	doneWriting <- true
	return <-result
}

/*
 The reason we're doing is that you can't write an infinite amount of bytes into a pipe.
 On some platforms, the limit is fairly high; on other platforms, the limit is infuriatingly small
 (looking at you, Windows). To counteract this, we need to read in a goroutine from one end of
 the pipe and return the result across a channel.
*/
func captureOutputAsyncronously(doneWriting <-chan bool, result chan<- []string, reader io.Reader) {
	var readingString string

	for {
		var buf bytes.Buffer
		io.Copy(&buf, reader)
		readingString += buf.String()

		_, ok := <-doneWriting
		if ok {
			// there is no guarantee that the writer did not
			// write more in between the read above and reading from this channel
			// so we absolute must read once more if we want all the bytes
			var buf bytes.Buffer
			io.Copy(&buf, reader)
			readingString += buf.String()
			break
		}
	}

	result <- strings.Split(readingString, "\n")
}
<|endoftext|>


<commit_before>// Copyright ©2015 The gonum 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 testlapack

import (
	"math/rand"
	"testing"

	"github.com/gonum/blas"
	"github.com/gonum/blas/blas64"
	"github.com/gonum/floats"
)

type Dpotrfer interface {
	Dpotrf(ul blas.Uplo, n int, a []float64, lda int) (ok bool)
}

func DpotrfTest(t *testing.T, impl Dpotrfer) {
	const tol = 1e-13
	rnd := rand.New(rand.NewSource(1))
	bi := blas64.Implementation()
	for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} {
		for tc, test := range []struct {
			n   int
			lda int
		}{
			{1, 0},
			{2, 0},
			{3, 0},
			{10, 0},
			{30, 0},
			{63, 0},
			{65, 0},
			{127, 0},
			{129, 0},
			{500, 0},
			{1, 10},
			{2, 10},
			{3, 10},
			{10, 20},
			{30, 50},
			{63, 100},
			{65, 100},
			{127, 200},
			{129, 200},
			{500, 600},
		} {
			n := test.n
			lda := test.lda
			if lda == 0 {
				lda = n
			}
			// Construct a diagonally-dominant symmetric matrix.
			// Such a matrix is positive definite.
			a := make([]float64, n*lda)
			for i := range a {
				a[i] = rnd.Float64()
			}
			for i := 0; i < n; i++ {
				a[i*lda+i] += float64(n)
				for j := 0; j < i; j++ {
					a[i*lda+j] = a[j*lda+i]
				}
			}

			aCopy := make([]float64, len(a))
			copy(aCopy, a)

			ok := impl.Dpotrf(uplo, n, a, lda)

			if !ok {
				t.Errorf("Case %v: unexpected failure for positive definite matrix", tc)
				continue
			}

			switch uplo {
			case blas.Upper:
				for i := 0; i < n; i++ {
					for j := 0; j < i; j++ {
						a[i*lda+j] = 0
					}
				}
			case blas.Lower:
				for i := 0; i < n; i++ {
					for j := i + 1; j < n; j++ {
						a[i*lda+j] = 0
					}
				}
			default:
				panic("bad uplo")
			}

			ans := make([]float64, len(a))
			switch uplo {
			case blas.Upper:
				// Multiply U^T * U.
				bi.Dsyrk(uplo, blas.Trans, n, n, 1, a, lda, 0, ans, lda)
			case blas.Lower:
				// Multiply L * L^T.
				bi.Dsyrk(uplo, blas.NoTrans, n, n, 1, a, lda, 0, ans, lda)
			}

			match := true
			switch uplo {
			case blas.Upper:
				for i := 0; i < n; i++ {
					for j := i; j < n; j++ {
						if !floats.EqualWithinAbsOrRel(ans[i*lda+j], aCopy[i*lda+j], tol, tol) {
							match = false
						}
					}
				}
			case blas.Lower:
				for i := 0; i < n; i++ {
					for j := 0; j <= i; j++ {
						if !floats.EqualWithinAbsOrRel(ans[i*lda+j], aCopy[i*lda+j], tol, tol) {
							match = false
						}
					}
				}
			}
			if !match {
				t.Errorf("Case %v (uplo=%v,n=%v,lda=%v): unexpected result\n%v\n%v", tc, uplo, n, lda, ans, aCopy)
			}
		}
	}
}
<commit_msg>testlapack: use Dlagsy in Dpotrf test and check expected failure for not PD matrices<commit_after>// Copyright ©2015 The gonum 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 testlapack

import (
	"math/rand"
	"testing"

	"github.com/gonum/blas"
	"github.com/gonum/blas/blas64"
	"github.com/gonum/floats"
)

type Dpotrfer interface {
	Dpotrf(ul blas.Uplo, n int, a []float64, lda int) (ok bool)
}

func DpotrfTest(t *testing.T, impl Dpotrfer) {
	const tol = 1e-13
	rnd := rand.New(rand.NewSource(1))
	bi := blas64.Implementation()
	for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} {
		for tc, test := range []struct {
			n   int
			lda int
		}{
			{1, 0},
			{2, 0},
			{3, 0},
			{10, 0},
			{30, 0},
			{63, 0},
			{65, 0},
			{127, 0},
			{129, 0},
			{500, 0},
			{1, 10},
			{2, 10},
			{3, 10},
			{10, 20},
			{30, 50},
			{63, 100},
			{65, 100},
			{127, 200},
			{129, 200},
			{500, 600},
		} {
			n := test.n

			// Random diagonal matrix D with positive entries.
			d := make([]float64, n)
			Dlatm1(d, 4, 10000, false, 1, rnd)

			// Construct a positive definite matrix A as
			//  A = U * D * U^T
			// where U is a random orthogonal matrix.
			lda := test.lda
			if lda == 0 {
				lda = n
			}
			a := make([]float64, n*lda)
			Dlagsy(n, d, a, lda, rnd, make([]float64, 2*n))

			aCopy := make([]float64, len(a))
			copy(aCopy, a)

			ok := impl.Dpotrf(uplo, n, a, lda)
			if !ok {
				t.Errorf("Case %v: unexpected failure for positive definite matrix", tc)
				continue
			}

			switch uplo {
			case blas.Upper:
				for i := 0; i < n; i++ {
					for j := 0; j < i; j++ {
						a[i*lda+j] = 0
					}
				}
			case blas.Lower:
				for i := 0; i < n; i++ {
					for j := i + 1; j < n; j++ {
						a[i*lda+j] = 0
					}
				}
			default:
				panic("bad uplo")
			}

			ans := make([]float64, len(a))
			switch uplo {
			case blas.Upper:
				// Multiply U^T * U.
				bi.Dsyrk(uplo, blas.Trans, n, n, 1, a, lda, 0, ans, lda)
			case blas.Lower:
				// Multiply L * L^T.
				bi.Dsyrk(uplo, blas.NoTrans, n, n, 1, a, lda, 0, ans, lda)
			}

			match := true
			switch uplo {
			case blas.Upper:
				for i := 0; i < n; i++ {
					for j := i; j < n; j++ {
						if !floats.EqualWithinAbsOrRel(ans[i*lda+j], aCopy[i*lda+j], tol, tol) {
							match = false
						}
					}
				}
			case blas.Lower:
				for i := 0; i < n; i++ {
					for j := 0; j <= i; j++ {
						if !floats.EqualWithinAbsOrRel(ans[i*lda+j], aCopy[i*lda+j], tol, tol) {
							match = false
						}
					}
				}
			}
			if !match {
				t.Errorf("Case %v (uplo=%v,n=%v,lda=%v): unexpected result", tc, uplo, n, lda)
			}

			// Make one element of D negative so that A is not
			// positive definite, and check that Dpotrf fails.
			d[0] *= -1
			Dlagsy(n, d, a, lda, rnd, make([]float64, 2*n))
			ok = impl.Dpotrf(uplo, n, a, lda)
			if ok {
				t.Errorf("Case %v: unexpected success for not positive definite matrix", tc)
			}
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package s3

import (
	"bytes"
	"crypto/md5"
	"encoding/base64"
	"errors"
	"github.com/jacobsa/aws/s3/auth/mock"
	"github.com/jacobsa/aws/s3/http"
	"github.com/jacobsa/aws/s3/http/mock"
	. "github.com/jacobsa/oglematchers"
	"github.com/jacobsa/oglemock"
	. "github.com/jacobsa/ogletest"
	"strings"
	"testing"
	"time"
)

func TestBucket(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func computeBase64Md5(d []byte) string {
	h := md5.New()
	if _, err := h.Write(d); err != nil {
		panic(err);
	}

	buf := new(bytes.Buffer)
	e := base64.NewEncoder(base64.StdEncoding, buf)
	if _, err := e.Write(h.Sum(nil)); err != nil {
		panic(err)
	}

	e.Close()
	return buf.String()
}

type fakeClock struct {
	now time.Time
}

func (c *fakeClock) Now() time.Time {
	return c.now
}

type bucketTest struct {
	httpConn mock_http.MockConn
	signer   mock_auth.MockSigner
	bucket   Bucket
	clock    *fakeClock
}

func (t *bucketTest) SetUp(i *TestInfo) {
	var err error

	t.httpConn = mock_http.NewMockConn(i.MockController, "httpConn")
	t.signer = mock_auth.NewMockSigner(i.MockController, "signer")
	t.clock = &fakeClock{}

	t.bucket, err = openBucket("some.bucket", t.httpConn, t.signer, t.clock)
	AssertEq(nil, err)
}

////////////////////////////////////////////////////////////////////////
// GetObject
////////////////////////////////////////////////////////////////////////

type GetObjectTest struct {
	bucketTest
}

func init() { RegisterTestSuite(&GetObjectTest{}) }

func (t *GetObjectTest) KeyNotValidUtf8() {
	key := "\x80\x81\x82"

	// Call
	_, err := t.bucket.GetObject(key)

	ExpectThat(err, Error(HasSubstr("valid")))
	ExpectThat(err, Error(HasSubstr("UTF-8")))
}

func (t *GetObjectTest) KeyTooLong() {
	key := strings.Repeat("a", 1025)

	// Call
	_, err := t.bucket.GetObject(key)

	ExpectThat(err, Error(HasSubstr("1024")))
	ExpectThat(err, Error(HasSubstr("bytes")))
}

func (t *GetObjectTest) CallsSigner() {
	key := "foo/bar/baz"

	// Clock
	t.clock.now = time.Date(1985, time.March, 18, 15, 33, 17, 123, time.UTC)

	// Signer
	var httpReq *http.Request
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Invoke(func(r *http.Request) error {
		httpReq = r
		return errors.New("")
	}))

	// Call
	t.bucket.GetObject(key)

	AssertNe(nil, httpReq)
	ExpectEq("GET", httpReq.Verb)
	ExpectEq("/some.bucket/foo/bar/baz", httpReq.Path)
	ExpectEq("Mon, 18 Mar 1985 15:33:17 UTC", httpReq.Headers["Date"])
}

func (t *GetObjectTest) SignerReturnsError() {
	key := ""

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Return(errors.New("taco")))

	// Call
	_, err := t.bucket.GetObject(key)

	ExpectThat(err, Error(HasSubstr("Sign")))
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *GetObjectTest) CallsConn() {
	key := ""

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Invoke(func(r *http.Request) error {
		r.Verb = "burrito"
		return nil
	}))

	// Conn
	var httpReq *http.Request
	ExpectCall(t.httpConn, "SendRequest")(Any()).
		WillOnce(oglemock.Invoke(func(r *http.Request) (*http.Response, error) {
		httpReq = r
		return nil, errors.New("")
	}))

	// Call
	t.bucket.GetObject(key)

	AssertNe(nil, httpReq)
	ExpectEq("burrito", httpReq.Verb)
}

func (t *GetObjectTest) ConnReturnsError() {
	key := ""

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Return(nil))

	// Conn
	ExpectCall(t.httpConn, "SendRequest")(Any()).
		WillOnce(oglemock.Return(nil, errors.New("taco")))

	// Call
	_, err := t.bucket.GetObject(key)

	ExpectThat(err, Error(HasSubstr("SendRequest")))
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *GetObjectTest) ServerReturnsError() {
	key := ""

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Return(nil))

	// Conn
	resp := &http.Response{
		StatusCode: 500,
		Body:       []byte("taco"),
	}

	ExpectCall(t.httpConn, "SendRequest")(Any()).
		WillOnce(oglemock.Return(resp, nil))

	// Call
	_, err := t.bucket.GetObject(key)

	ExpectThat(err, Error(HasSubstr("server")))
	ExpectThat(err, Error(HasSubstr("500")))
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *GetObjectTest) ServerReturnsWrongContentLength() {
	ExpectEq("TODO", "")
}

func (t *GetObjectTest) ReturnsResponseBody() {
	ExpectEq("TODO", "")
}

////////////////////////////////////////////////////////////////////////
// StoreObject
////////////////////////////////////////////////////////////////////////

type StoreObjectTest struct {
	bucketTest
}

func init() { RegisterTestSuite(&StoreObjectTest{}) }

func (t *StoreObjectTest) KeyNotValidUtf8() {
	key := "\x80\x81\x82"
	data := []byte{}

	// Call
	err := t.bucket.StoreObject(key, data)

	ExpectThat(err, Error(HasSubstr("valid")))
	ExpectThat(err, Error(HasSubstr("UTF-8")))
}

func (t *StoreObjectTest) KeyTooLong() {
	key := strings.Repeat("a", 1025)
	data := []byte{}

	// Call
	err := t.bucket.StoreObject(key, data)

	ExpectThat(err, Error(HasSubstr("1024")))
	ExpectThat(err, Error(HasSubstr("bytes")))
}

func (t *StoreObjectTest) CallsSigner() {
	key := "foo/bar/baz"
	data := []byte{0x00, 0xde, 0xad, 0xbe, 0xef}

	// Clock
	t.clock.now = time.Date(1985, time.March, 18, 15, 33, 17, 123, time.UTC)

	// Signer
	var httpReq *http.Request
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Invoke(func(r *http.Request) error {
		httpReq = r
		return errors.New("")
	}))

	// Call
	t.bucket.StoreObject(key, data)

	AssertNe(nil, httpReq)
	ExpectEq("PUT", httpReq.Verb)
	ExpectEq("/some.bucket/foo/bar/baz", httpReq.Path)
	ExpectEq("Mon, 18 Mar 1985 15:33:17 UTC", httpReq.Headers["Date"])
	ExpectEq(computeBase64Md5(data), httpReq.Headers["Content-MD5"])
	ExpectThat(httpReq.Body, DeepEquals(data))
}

func (t *StoreObjectTest) SignerReturnsError() {
	key := ""
	data := []byte{}

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Return(errors.New("taco")))

	// Call
	err := t.bucket.StoreObject(key, data)

	ExpectThat(err, Error(HasSubstr("Sign")))
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *StoreObjectTest) CallsConn() {
	key := ""
	data := []byte{}

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Invoke(func(r *http.Request) error {
		r.Verb = "burrito"
		return nil
	}))

	// Conn
	var httpReq *http.Request
	ExpectCall(t.httpConn, "SendRequest")(Any()).
		WillOnce(oglemock.Invoke(func(r *http.Request) (*http.Response, error) {
		httpReq = r
		return nil, errors.New("")
	}))

	// Call
	t.bucket.StoreObject(key, data)

	AssertNe(nil, httpReq)
	ExpectEq("burrito", httpReq.Verb)
}

func (t *StoreObjectTest) ConnReturnsError() {
	key := ""
	data := []byte{}

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Return(nil))

	// Conn
	ExpectCall(t.httpConn, "SendRequest")(Any()).
		WillOnce(oglemock.Return(nil, errors.New("taco")))

	// Call
	err := t.bucket.StoreObject(key, data)

	ExpectThat(err, Error(HasSubstr("SendRequest")))
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *StoreObjectTest) ServerReturnsError() {
	key := ""
	data := []byte{}

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Return(nil))

	// Conn
	resp := &http.Response{
		StatusCode: 500,
		Body:       []byte("taco"),
	}

	ExpectCall(t.httpConn, "SendRequest")(Any()).
		WillOnce(oglemock.Return(resp, nil))

	// Call
	err := t.bucket.StoreObject(key, data)

	ExpectThat(err, Error(HasSubstr("server")))
	ExpectThat(err, Error(HasSubstr("500")))
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *StoreObjectTest) ServerSaysOkay() {
	key := ""
	data := []byte{}

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Return(nil))

	// Conn
	resp := &http.Response{
		StatusCode: 200,
		Body:       []byte("taco"),
	}

	ExpectCall(t.httpConn, "SendRequest")(Any()).
		WillOnce(oglemock.Return(resp, nil))

	// Call
	err := t.bucket.StoreObject(key, data)

	ExpectEq(nil, err)
}
<commit_msg>Removed badly-placed test.<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package s3

import (
	"bytes"
	"crypto/md5"
	"encoding/base64"
	"errors"
	"github.com/jacobsa/aws/s3/auth/mock"
	"github.com/jacobsa/aws/s3/http"
	"github.com/jacobsa/aws/s3/http/mock"
	. "github.com/jacobsa/oglematchers"
	"github.com/jacobsa/oglemock"
	. "github.com/jacobsa/ogletest"
	"strings"
	"testing"
	"time"
)

func TestBucket(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func computeBase64Md5(d []byte) string {
	h := md5.New()
	if _, err := h.Write(d); err != nil {
		panic(err);
	}

	buf := new(bytes.Buffer)
	e := base64.NewEncoder(base64.StdEncoding, buf)
	if _, err := e.Write(h.Sum(nil)); err != nil {
		panic(err)
	}

	e.Close()
	return buf.String()
}

type fakeClock struct {
	now time.Time
}

func (c *fakeClock) Now() time.Time {
	return c.now
}

type bucketTest struct {
	httpConn mock_http.MockConn
	signer   mock_auth.MockSigner
	bucket   Bucket
	clock    *fakeClock
}

func (t *bucketTest) SetUp(i *TestInfo) {
	var err error

	t.httpConn = mock_http.NewMockConn(i.MockController, "httpConn")
	t.signer = mock_auth.NewMockSigner(i.MockController, "signer")
	t.clock = &fakeClock{}

	t.bucket, err = openBucket("some.bucket", t.httpConn, t.signer, t.clock)
	AssertEq(nil, err)
}

////////////////////////////////////////////////////////////////////////
// GetObject
////////////////////////////////////////////////////////////////////////

type GetObjectTest struct {
	bucketTest
}

func init() { RegisterTestSuite(&GetObjectTest{}) }

func (t *GetObjectTest) KeyNotValidUtf8() {
	key := "\x80\x81\x82"

	// Call
	_, err := t.bucket.GetObject(key)

	ExpectThat(err, Error(HasSubstr("valid")))
	ExpectThat(err, Error(HasSubstr("UTF-8")))
}

func (t *GetObjectTest) KeyTooLong() {
	key := strings.Repeat("a", 1025)

	// Call
	_, err := t.bucket.GetObject(key)

	ExpectThat(err, Error(HasSubstr("1024")))
	ExpectThat(err, Error(HasSubstr("bytes")))
}

func (t *GetObjectTest) CallsSigner() {
	key := "foo/bar/baz"

	// Clock
	t.clock.now = time.Date(1985, time.March, 18, 15, 33, 17, 123, time.UTC)

	// Signer
	var httpReq *http.Request
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Invoke(func(r *http.Request) error {
		httpReq = r
		return errors.New("")
	}))

	// Call
	t.bucket.GetObject(key)

	AssertNe(nil, httpReq)
	ExpectEq("GET", httpReq.Verb)
	ExpectEq("/some.bucket/foo/bar/baz", httpReq.Path)
	ExpectEq("Mon, 18 Mar 1985 15:33:17 UTC", httpReq.Headers["Date"])
}

func (t *GetObjectTest) SignerReturnsError() {
	key := ""

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Return(errors.New("taco")))

	// Call
	_, err := t.bucket.GetObject(key)

	ExpectThat(err, Error(HasSubstr("Sign")))
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *GetObjectTest) CallsConn() {
	key := ""

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Invoke(func(r *http.Request) error {
		r.Verb = "burrito"
		return nil
	}))

	// Conn
	var httpReq *http.Request
	ExpectCall(t.httpConn, "SendRequest")(Any()).
		WillOnce(oglemock.Invoke(func(r *http.Request) (*http.Response, error) {
		httpReq = r
		return nil, errors.New("")
	}))

	// Call
	t.bucket.GetObject(key)

	AssertNe(nil, httpReq)
	ExpectEq("burrito", httpReq.Verb)
}

func (t *GetObjectTest) ConnReturnsError() {
	key := ""

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Return(nil))

	// Conn
	ExpectCall(t.httpConn, "SendRequest")(Any()).
		WillOnce(oglemock.Return(nil, errors.New("taco")))

	// Call
	_, err := t.bucket.GetObject(key)

	ExpectThat(err, Error(HasSubstr("SendRequest")))
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *GetObjectTest) ServerReturnsError() {
	key := ""

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Return(nil))

	// Conn
	resp := &http.Response{
		StatusCode: 500,
		Body:       []byte("taco"),
	}

	ExpectCall(t.httpConn, "SendRequest")(Any()).
		WillOnce(oglemock.Return(resp, nil))

	// Call
	_, err := t.bucket.GetObject(key)

	ExpectThat(err, Error(HasSubstr("server")))
	ExpectThat(err, Error(HasSubstr("500")))
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *GetObjectTest) ReturnsResponseBody() {
	ExpectEq("TODO", "")
}

////////////////////////////////////////////////////////////////////////
// StoreObject
////////////////////////////////////////////////////////////////////////

type StoreObjectTest struct {
	bucketTest
}

func init() { RegisterTestSuite(&StoreObjectTest{}) }

func (t *StoreObjectTest) KeyNotValidUtf8() {
	key := "\x80\x81\x82"
	data := []byte{}

	// Call
	err := t.bucket.StoreObject(key, data)

	ExpectThat(err, Error(HasSubstr("valid")))
	ExpectThat(err, Error(HasSubstr("UTF-8")))
}

func (t *StoreObjectTest) KeyTooLong() {
	key := strings.Repeat("a", 1025)
	data := []byte{}

	// Call
	err := t.bucket.StoreObject(key, data)

	ExpectThat(err, Error(HasSubstr("1024")))
	ExpectThat(err, Error(HasSubstr("bytes")))
}

func (t *StoreObjectTest) CallsSigner() {
	key := "foo/bar/baz"
	data := []byte{0x00, 0xde, 0xad, 0xbe, 0xef}

	// Clock
	t.clock.now = time.Date(1985, time.March, 18, 15, 33, 17, 123, time.UTC)

	// Signer
	var httpReq *http.Request
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Invoke(func(r *http.Request) error {
		httpReq = r
		return errors.New("")
	}))

	// Call
	t.bucket.StoreObject(key, data)

	AssertNe(nil, httpReq)
	ExpectEq("PUT", httpReq.Verb)
	ExpectEq("/some.bucket/foo/bar/baz", httpReq.Path)
	ExpectEq("Mon, 18 Mar 1985 15:33:17 UTC", httpReq.Headers["Date"])
	ExpectEq(computeBase64Md5(data), httpReq.Headers["Content-MD5"])
	ExpectThat(httpReq.Body, DeepEquals(data))
}

func (t *StoreObjectTest) SignerReturnsError() {
	key := ""
	data := []byte{}

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Return(errors.New("taco")))

	// Call
	err := t.bucket.StoreObject(key, data)

	ExpectThat(err, Error(HasSubstr("Sign")))
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *StoreObjectTest) CallsConn() {
	key := ""
	data := []byte{}

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Invoke(func(r *http.Request) error {
		r.Verb = "burrito"
		return nil
	}))

	// Conn
	var httpReq *http.Request
	ExpectCall(t.httpConn, "SendRequest")(Any()).
		WillOnce(oglemock.Invoke(func(r *http.Request) (*http.Response, error) {
		httpReq = r
		return nil, errors.New("")
	}))

	// Call
	t.bucket.StoreObject(key, data)

	AssertNe(nil, httpReq)
	ExpectEq("burrito", httpReq.Verb)
}

func (t *StoreObjectTest) ConnReturnsError() {
	key := ""
	data := []byte{}

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Return(nil))

	// Conn
	ExpectCall(t.httpConn, "SendRequest")(Any()).
		WillOnce(oglemock.Return(nil, errors.New("taco")))

	// Call
	err := t.bucket.StoreObject(key, data)

	ExpectThat(err, Error(HasSubstr("SendRequest")))
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *StoreObjectTest) ServerReturnsError() {
	key := ""
	data := []byte{}

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Return(nil))

	// Conn
	resp := &http.Response{
		StatusCode: 500,
		Body:       []byte("taco"),
	}

	ExpectCall(t.httpConn, "SendRequest")(Any()).
		WillOnce(oglemock.Return(resp, nil))

	// Call
	err := t.bucket.StoreObject(key, data)

	ExpectThat(err, Error(HasSubstr("server")))
	ExpectThat(err, Error(HasSubstr("500")))
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *StoreObjectTest) ServerSaysOkay() {
	key := ""
	data := []byte{}

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Return(nil))

	// Conn
	resp := &http.Response{
		StatusCode: 200,
		Body:       []byte("taco"),
	}

	ExpectCall(t.httpConn, "SendRequest")(Any()).
		WillOnce(oglemock.Return(resp, nil))

	// Call
	err := t.bucket.StoreObject(key, data)

	ExpectEq(nil, err)
}
<|endoftext|>


<commit_before>/*
 *
 * Author     : Valentin Kuznetsov <vkuznet AT gmail dot com>
 * Description: URL fetch proxy server concurrently fetches data from
 *              provided URL list. It provides a POST HTTP interface
 *              "/getdata" which accepts urls as newline separated encoded
 *              string
 * Created    : Wed Mar 20 13:29:48 EDT 2013
 * License    : MIT
 *
 */
package main

import (
    "os"
    "fmt"
    "log"
    "strings"
    "net/http"
    "io/ioutil"
    "crypto/tls"
)

/*
 * Return array of certificates
 */
func get_certs() []tls.Certificate {
    uproxy := os.Getenv("X509_USER_PROXY")
    uckey  := os.Getenv("X509_USER_KEY")
    ucert  := os.Getenv("X509_USER_CERT")
    tls_certs := []tls.Certificate{}
    if  len(uproxy) > 0 {
        x509cert, err := tls.LoadX509KeyPair(uproxy, uproxy)
        if  err != nil {
            fmt.Println("Fail to parser proxy X509 certificate", err)
            return []tls.Certificate{}
        }
        tls_certs = []tls.Certificate{x509cert}
    } else if len(uckey) > 0 {
        x509cert, err := tls.LoadX509KeyPair(ucert, uckey)
        if  err != nil {
            fmt.Println("Fail to parser user X509 certificate", err)
            return []tls.Certificate{}
        }
        tls_certs = []tls.Certificate{x509cert}
    } else {
        return []tls.Certificate{}
    }
    return tls_certs
}

/*
 * getdata(url string, ch chan<- []byte)
 * Fetches data for given URL and redirect response body to given channel
 */
func getdata(url string, ch chan<- []byte) {
    msg := ""
    certs := get_certs()
    if  len(certs) == 0 {
        msg = "Unable to fullfill your request, no server X509 certificate\n"
        ch <- []byte(msg)
        return
    }
    tr := &http.Transport{
        TLSClientConfig: &tls.Config{tls.Certificates: certs},
    }
    client := &http.Client{Transport: tr}
    resp, err := client.Get(url)
    if  err != nil {
        msg = "Fail to contact " + url
        ch <- []byte(msg)
        return
    }
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if  err != nil {
        msg := "Fail to parse reponse body"
        log.Println(msg, err)
        ch <- []byte(msg)
        return
    }
    ch <- body
}

// Helper function to append bytes to existing slice
func AppendByte(slice []byte, data []byte) []byte {
    m := len(slice)
    n := m + len(data)
    if n > cap(slice) { // if necessary, reallocate
        // allocate double what's needed, for future growth.
        newSlice := make([]byte, (n+1)*2)
        copy(newSlice, slice)
        slice = newSlice
    }
    slice = slice[0:n]
    copy(slice[m:n], data)
    return slice
}

/*
 * concurrent worker wrapper around getdata fucntion
 * it creates a channel and runs getdata concurrently to fetch data from given
 * url and stored them into the channel. All results are combined and copied
 * into output buffer.
 */
func getdata4urls(urls []string) []byte {
    ch := make(chan []byte)
    n := 0
    for _, url := range urls {
        n++
        go getdata(url, ch)
    }
    out := []byte{}
    for i:=0; i<n; i++ {
        out = AppendByte(out, <-ch)
    }
    return out
}

/*
 * RequestHandler is used by web server to handle incoming requests
 */
func RequestHandler(w http.ResponseWriter, r *http.Request) {
    if  r.Method != "POST" {
        w.WriteHeader(http.StatusBadRequest)
        return
    }
    // parse input request parameter, in this case we should pass urls
    r.ParseForm()
    urls := []string{}
    for k, v := range r.Form {
        if k == "urls" {
            urls = strings.Split(v[0], "\n")
        }
    }
    log.Println(urls)

    // loop concurently over url list and store results into channel
    ch := make(chan []byte)
    n := 0
    for _, url := range urls {
        n++
        go getdata(url, ch)
    }
    // once channels are ready fill out results to response writer
    for i:=0; i<n; i++ {
        w.Write(<-ch)
        w.Write([]byte("\n"))
    }
}

func server(port string) {
    http.HandleFunc("/getdata", RequestHandler)
    err := http.ListenAndServe(":" + port, nil)
    // NOTE: later this can be replaced with secure connection
    // replace ListenAndServe(addr string, handler Handler)
    // with TLS function
    // ListenAndServeTLS(addr string, certFile string, keyFile string, handler
    // Handler)
    if  err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}

/*
 * Test functions
 */
func test_getdata4urls(urls []string) {
    ch := make(chan []byte)
    n := 0
    for _, url := range urls {
        n++
        go getdata(url, ch)
    }
    for i:=0; i<n; i++ {
        fmt.Println(string(<-ch))
    }
}
func test_getdata(url string) {
    ch := make(chan []byte)
    go getdata(url, ch)
    fmt.Println(string(<-ch))
}
func test() {
    url1 := "http://www.google.com"
    url2 := "http://www.golang.org"
    urls := []string{url1, url2}
    fmt.Println("TEST: test_getdata")
    test_getdata(url1)
    fmt.Println("TEST: test_getdata4urls")
    test_getdata4urls(urls)
}

/*
 * MAIN
 */
func main() {
    server("8000")
}

<commit_msg>Re-factor the code; add new function to create HTTP client; modified getdata to use client as an argument; remove obsolete code<commit_after>/*
 *
 * Author     : Valentin Kuznetsov <vkuznet AT gmail dot com>
 * Description: URL fetch proxy server concurrently fetches data from
 *              provided URL list. It provides a POST HTTP interface
 *              "/getdata" which accepts urls as newline separated encoded
 *              string
 * Created    : Wed Mar 20 13:29:48 EDT 2013
 * License    : MIT
 *
 */
package main

import (
    "os"
    "fmt"
    "log"
    "strings"
    "net/http"
    "io/ioutil"
    "crypto/tls"
)

/*
 * Return array of certificates
 */
func get_certs() []tls.Certificate {
    uproxy := os.Getenv("X509_USER_PROXY")
    uckey  := os.Getenv("X509_USER_KEY")
    ucert  := os.Getenv("X509_USER_CERT")
    tls_certs := []tls.Certificate{}
    if  len(uproxy) > 0 {
        x509cert, err := tls.LoadX509KeyPair(uproxy, uproxy)
        if  err != nil {
            fmt.Println("Fail to parser proxy X509 certificate", err)
            return []tls.Certificate{}
        }
        tls_certs = []tls.Certificate{x509cert}
    } else if len(uckey) > 0 {
        x509cert, err := tls.LoadX509KeyPair(ucert, uckey)
        if  err != nil {
            fmt.Println("Fail to parser user X509 certificate", err)
            return []tls.Certificate{}
        }
        tls_certs = []tls.Certificate{x509cert}
    } else {
        return []tls.Certificate{}
    }
    return tls_certs
}

/*
 *
 */
func http_client() *http.Client {
    // create HTTP client
    certs := get_certs()
    if  len(certs) == 0 {
        client := &http.Client{}
        return client
    }
    tr := &http.Transport{
        TLSClientConfig: &tls.Config{tls.Certificates: certs},
    }
    client := &http.Client{Transport: tr}
    return client
}

/*
 * getdata(url string, ch chan<- []byte)
 * Fetches data for given URL and redirect response body to given channel
 */
func getdata(client *http.Client, url string, ch chan<- []byte) {
    msg := ""
    resp, err := client.Get(url)
    if  err != nil {
        msg = "Fail to contact " + url
        ch <- []byte(msg)
        return
    }
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if  err != nil {
        msg = "Fail to parse reponse body"
        log.Println(msg, err)
        ch <- []byte(msg)
        return
    }
    ch <- body
}

/*
 * RequestHandler is used by web server to handle incoming requests
 */
func RequestHandler(w http.ResponseWriter, r *http.Request) {
    // we only accept POST request with urls (this is by design)
    if  r.Method != "POST" {
        w.WriteHeader(http.StatusBadRequest)
        return
    }

    // parse input request parameter, in this case we should pass urls
    r.ParseForm()
    urls := []string{}
    for k, v := range r.Form {
        if k == "urls" {
            urls = strings.Split(v[0], "\n")
        }
    }
    log.Println(urls)

    // create HTTP client
    client := http_client()

    // loop concurently over url list and store results into channel
    ch := make(chan []byte)
    n := 0
    for _, url := range urls {
        n++
        go getdata(client, url, ch)
    }
    // once channels are ready fill out results to response writer
    for i:=0; i<n; i++ {
        w.Write(<-ch)
        w.Write([]byte("\n"))
    }
}

func server(port string) {
    http.HandleFunc("/getdata", RequestHandler)
    err := http.ListenAndServe(":" + port, nil)
    // NOTE: later this can be replaced with secure connection
    // replace ListenAndServe(addr string, handler Handler)
    // with TLS function
    // ListenAndServeTLS(addr string, certFile string, keyFile string, handler
    // Handler)
    if  err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}

/*
 * Test functions
 */
func test_getdata4urls(urls []string) {
    // create HTTP client
    client := http_client()

    ch := make(chan []byte)
    n := 0
    for _, url := range urls {
        n++
        go getdata(client, url, ch)
    }
    for i:=0; i<n; i++ {
        fmt.Println(string(<-ch))
    }
}
func test_getdata(url string) {
    // create HTTP client
    client := http_client()

    ch := make(chan []byte)
    go getdata(client, url, ch)
    fmt.Println(string(<-ch))
}
func test() {
    url1 := "http://www.google.com"
    url2 := "http://www.golang.org"
    urls := []string{url1, url2}
    fmt.Println("TEST: test_getdata")
    test_getdata(url1)
    fmt.Println("TEST: test_getdata4urls")
    test_getdata4urls(urls)
}

/*
 * MAIN
 */
func main() {
    server("8000")
}

<|endoftext|>


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

// This package implements a basic LISP interpretor for embedding in a go program for scripting.
// This file implements Json<->Lisp conversions using frames.

package golisp

import (
	"encoding/json"
	"errors"
	"fmt"
	"math"
	"strings"
)

func JsonToLispWithFrames(json interface{}) (result *Data) {
	mapValue, ok := json.(map[string]interface{})
	if ok {
		var m = make(FrameMap, len(mapValue))
		for key, val := range mapValue {
			value := JsonToLispWithFrames(val)
			m[fmt.Sprintf("%s:", key)] = value
		}
		return FrameWithValue(&m)
	}

	arrayValue, ok := json.([]interface{})
	if ok {
		var ary *Data
		for _, val := range arrayValue {
			value := JsonToLispWithFrames(val)
			ary = Cons(value, ary)
		}
		return Reverse(ary)
	}

	numValue, ok := json.(float64)
	if ok {
		if math.Trunc(numValue) == numValue {
			return IntegerWithValue(int64(numValue))
		} else {
			return FloatWithValue(float32(numValue))
		}
	}

	strValue, ok := json.(string)
	if ok {
		return StringWithValue(strValue)
	}

	boolValue, ok := json.(bool)
	if ok {
		return BooleanWithValue(boolValue)
	}

	return
}

func JsonStringToLispWithFrames(jsonData string) (result *Data) {
	b := []byte(jsonData)
	var data interface{}
	err := json.Unmarshal(b, &data)
	if err != nil {
		panic(errors.New(fmt.Sprintf("Badly formed json: '%s'", jsonData)))
	}
	return JsonToLispWithFrames(data)
}

func LispWithFramesToJson(d *Data) (result interface{}) {
	if d == nil {
		return ""
	}

	if IntegerP(d) {
		return IntegerValue(d)
	}

	if FloatP(d) {
		return FloatValue(d)
	}

	if StringP(d) {
		return StringValue(d)
	}

	if BooleanP(d) {
		return BooleanValue(d)
	}

	if PairP(d) {
		ary := make([]interface{}, 0, Length(d))
		for c := d; NotNilP(c); c = Cdr(c) {
			ary = append(ary, LispWithFramesToJson(Car(c)))
		}
		return ary
	}

	if FrameP(d) {
		dict := make(map[string]interface{}, Length(d))
		for k, v := range *d.Frame {
			if !FunctionP(v) {
				dict[strings.TrimRight(k, ":")] = LispWithFramesToJson(v)
			}
		}
		return dict
	}

	return ""
}

func LispWithFramesToJsonString(d *Data) (result string) {
	temp := LispWithFramesToJson(d)
	j, err := json.Marshal(temp)
	if err == nil {
		return string(j)
	} else {
		return ""
	}
}
<commit_msg>Better error message<commit_after>// Copyright 2014 SteelSeries ApS.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This package implements a basic LISP interpretor for embedding in a go program for scripting.
// This file implements Json<->Lisp conversions using frames.

package golisp

import (
	"encoding/json"
	"errors"
	"fmt"
	"math"
	"strings"
)

func JsonToLispWithFrames(json interface{}) (result *Data) {
	mapValue, ok := json.(map[string]interface{})
	if ok {
		var m = make(FrameMap, len(mapValue))
		for key, val := range mapValue {
			value := JsonToLispWithFrames(val)
			m[fmt.Sprintf("%s:", key)] = value
		}
		return FrameWithValue(&m)
	}

	arrayValue, ok := json.([]interface{})
	if ok {
		var ary *Data
		for _, val := range arrayValue {
			value := JsonToLispWithFrames(val)
			ary = Cons(value, ary)
		}
		return Reverse(ary)
	}

	numValue, ok := json.(float64)
	if ok {
		if math.Trunc(numValue) == numValue {
			return IntegerWithValue(int64(numValue))
		} else {
			return FloatWithValue(float32(numValue))
		}
	}

	strValue, ok := json.(string)
	if ok {
		return StringWithValue(strValue)
	}

	boolValue, ok := json.(bool)
	if ok {
		return BooleanWithValue(boolValue)
	}

	return
}

func JsonStringToLispWithFrames(jsonData string) (result *Data) {
	b := []byte(jsonData)
	var data interface{}
	err := json.Unmarshal(b, &data)
	if err != nil {
		panic(errors.New(fmt.Sprintf("Badly formed json: '%s'\n --> %v\n", jsonData, err)))
	}
	return JsonToLispWithFrames(data)
}

func LispWithFramesToJson(d *Data) (result interface{}) {
	if d == nil {
		return ""
	}

	if IntegerP(d) {
		return IntegerValue(d)
	}

	if FloatP(d) {
		return FloatValue(d)
	}

	if StringP(d) {
		return StringValue(d)
	}

	if BooleanP(d) {
		return BooleanValue(d)
	}

	if PairP(d) {
		ary := make([]interface{}, 0, Length(d))
		for c := d; NotNilP(c); c = Cdr(c) {
			ary = append(ary, LispWithFramesToJson(Car(c)))
		}
		return ary
	}

	if FrameP(d) {
		dict := make(map[string]interface{}, Length(d))
		for k, v := range *d.Frame {
			if !FunctionP(v) {
				dict[strings.TrimRight(k, ":")] = LispWithFramesToJson(v)
			}
		}
		return dict
	}

	return ""
}

func LispWithFramesToJsonString(d *Data) (result string) {
	temp := LispWithFramesToJson(d)
	j, err := json.Marshal(temp)
	if err == nil {
		return string(j)
	} else {
		return ""
	}
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"errors"
	"log"
)

func NewContactQuery(page int, perPage int) *ContactQuery {
	if page < 1 {
		page = 1
	}
	if perPage < 1 {
		perPage = 1
	}

	return &ContactQuery{
		limit:      perPage,
		offset:     perPage * (page - 1),
		collection: NewContactList(perPage),
	}
}

type ContactQuery struct {
	limit      int
	offset     int
	collection []*Contact
	conn       *sql.DB
}

func (cq *ContactQuery) All() ContactList {
	if cq.conn = NewDBConn(); cq.conn != nil {
		defer cq.conn.Close()
	}

	err := cq.fillUsers()
	if err != nil {
		log.Print(err)
		return NewContactList(0)
	}
	return cq.collection
}

func (cq *ContactQuery) fillUsers() (err error) {
	ps, err := cq.selectUsersStmt()
	if err != nil {
		return
	}
	defer ps.Close()

	rows, err := ps.Query(cq.limit, cq.offset)
	if err != nil {
		log.Print(err)
		return
	}
	defer rows.Close()

	for rows.Next() {
		contact := NewContact()
		rows.Scan(
			&contact.Id,
			&contact.Email,
			&contact.FirstName,
			&contact.LastName,
			&contact.MiddleName,
			&contact.DateOfBirth,
			&contact.Sex,
		)

		cq.collection = append(cq.collection, contact)
	}

	return
}

func (cq *ContactQuery) selectUsersStmt() (*sql.Stmt, error) {
	if cq.conn == nil {
		return nil, errors.New("Can't connect to DB")
	}

	return cq.conn.Prepare(`
    select  id,
            email,
            first_name,
            last_name,
            middle_name,
            date_of_birth,
            sex
      from users
      where deleted_at is null
      order by id
      limit $1
      offset $2`)
}
<commit_msg>Remove extra log statement<commit_after>package main

import (
	"database/sql"
	"errors"
	"log"
)

func NewContactQuery(page int, perPage int) *ContactQuery {
	if page < 1 {
		page = 1
	}
	if perPage < 1 {
		perPage = 1
	}

	return &ContactQuery{
		limit:      perPage,
		offset:     perPage * (page - 1),
		collection: NewContactList(perPage),
	}
}

type ContactQuery struct {
	limit      int
	offset     int
	collection []*Contact
	conn       *sql.DB
}

func (cq *ContactQuery) All() ContactList {
	if cq.conn = NewDBConn(); cq.conn != nil {
		defer cq.conn.Close()
	}

	err := cq.fillUsers()
	if err != nil {
		log.Print(err)
		return NewContactList(0)
	}
	return cq.collection
}

func (cq *ContactQuery) fillUsers() (err error) {
	ps, err := cq.selectUsersStmt()
	if err != nil {
		return
	}
	defer ps.Close()

	rows, err := ps.Query(cq.limit, cq.offset)
	if err != nil {
		return
	}
	defer rows.Close()

	for rows.Next() {
		contact := NewContact()
		rows.Scan(
			&contact.Id,
			&contact.Email,
			&contact.FirstName,
			&contact.LastName,
			&contact.MiddleName,
			&contact.DateOfBirth,
			&contact.Sex,
		)

		cq.collection = append(cq.collection, contact)
	}

	return
}

func (cq *ContactQuery) selectUsersStmt() (*sql.Stmt, error) {
	if cq.conn == nil {
		return nil, errors.New("Can't connect to DB")
	}

	return cq.conn.Prepare(`
    select  id,
            email,
            first_name,
            last_name,
            middle_name,
            date_of_birth,
            sex
      from users
      where deleted_at is null
      order by id
      limit $1
      offset $2`)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
)

func checkErr(err error) {
	if err == nil {
		return
	}
	fmt.Fprintln(os.Stderr, err)
	os.Exit(1)
}

func main() {
	if len(os.Args) != 4 || (os.Args[1] != "le" && os.Args[1] != "be") {
		fmt.Fprintf(
			os.Stderr, "Usage: firmware2go le|be INPUT.bin OUTPUT.go\n",
		)
		os.Exit(1)
	}
	le := os.Args[1] != "le"
	f, err := os.Open(os.Args[2])
	checkErr(err)
	inp := bufio.NewReader(f)
	f, err = os.Create(os.Args[3])
	checkErr(err)
	defer f.Close()
	out := bufio.NewWriter(f)
	_, err = out.WriteString(
		"package main\n" + "//emgo:const\n" + "var firmware = [...]uint64{\n",
	)
	checkErr(err)
	var buf [8]byte
	for i := 0; ; i++ {
		n, err := io.ReadFull(inp, buf[:])
		if err != nil && err != io.ErrUnexpectedEOF {
			if err == io.EOF {
				if i%3 != 0 {
					checkErr(out.WriteByte('\n'))
				}
				break
			}
			checkErr(err)
		}
		var v uint64
		if le {
			for k := 0; k < n; k++ {
				v |= uint64(buf[k]) << uint(8*k)
			}
		} else {
			for k := 0; k < n; k++ {
				v |= uint64(buf[k]) << uint(56-8*k)
			}
		}
		_, err = fmt.Fprintf(out, " 0x%016X,", v)
		checkErr(err)
		if i%3 == 2 {
			checkErr(out.WriteByte('\n'))
		}
	}
	_, err = out.WriteString("}\n")
	checkErr(err)
	checkErr(out.Flush())
}
<commit_msg>tools/firmware2go: Emit bytes or string.<commit_after>package main

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"os"
)

func checkErr(err error) {
	if err == nil {
		return
	}
	os.Stderr.WriteString(err.Error())
	os.Exit(1)
}

func main() {
	if len(os.Args) != 3 || os.Args[1] != "bytes" && os.Args[1] != "string" {
		os.Stderr.WriteString("Usage: firmware2go {bytes|string} BINARY_FILE\n")
		os.Exit(1)
	}
	data, err := ioutil.ReadFile(os.Args[2])
	checkErr(err)
	w := bufio.NewWriter(os.Stdout)
	_, err = w.WriteString("package main\n\n")
	checkErr(err)
	if os.Args[1] == "bytes" {
		_, err = w.WriteString("//emgo:const\nvar firmware = [...]byte{")
		checkErr(err)
		for i, b := range data {
			if i%15 == 0 {
				_, err = w.WriteString("\n\t")
				checkErr(err)
			}
			_, err = fmt.Fprintf(w, " %d,", b)
			checkErr(err)
		}
		_, err = w.WriteString("\n}\n")
		checkErr(err)
	} else {
		_, err = w.WriteString("const firmware = \"")
		checkErr(err)
		for i, b := range data {
			if i%18 == 0 {
				_, err = w.WriteString("\" +\n\t\"")
				checkErr(err)
			}
			_, err = fmt.Fprintf(w, "\\x%02X", b)
			checkErr(err)
		}
		_, err = w.WriteString("\"\n")
		checkErr(err)
	}
	checkErr(w.Flush())
}
<|endoftext|>