<commit_before>// Copyright (c) 2017 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package tchannel_test

import (
	"fmt"
	"strings"
	"testing"
	"time"

	. "github.com/uber/tchannel-go"

	"github.com/uber/tchannel-go/raw"
	"github.com/uber/tchannel-go/testutils"

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

// peerStatusListener is a test tool used to wait for connections to drop by
// listening to status events from a channel.
type peerStatusListener struct {
	changes chan struct{}
}

func newPeerStatusListener() *peerStatusListener {
	return &peerStatusListener{
		changes: make(chan struct{}, 10),
	}
}

func (pl *peerStatusListener) onStatusChange(p *Peer) {
	pl.changes <- struct{}{}
}

func (pl *peerStatusListener) waitForZeroConnections(t testing.TB, channels ...*Channel) bool {
	for {
		select {
		case <-pl.changes:
			if allConnectionsClosed(channels) {
				return true
			}

		case <-time.After(testutils.Timeout(time.Second)):
			t.Fatalf("Some connections are still open: %s", connectionStatus(channels))
			return false
		}
	}
}

func (pl *peerStatusListener) waitForZeroExchanges(t testing.TB, channels ...*Channel) {
	var (
		isEmpty bool
		status  []string
	)
	if !testutils.WaitFor(100*time.Millisecond, func() bool {
		isEmpty, status = allExchangesEmpty(channels)
		return isEmpty
	}) {
		t.Fatalf("Some exchanges are still non-empty: %s", strings.Join(status, ", "))
	}
}

func allConnectionsClosed(channels []*Channel) bool {
	for _, ch := range channels {
		if numConnections(ch) != 0 {
			return false
		}
	}

	return true
}

func allExchangesEmpty(channels []*Channel) (isEmpty bool, status []string) {
	for _, ch := range channels {
		n := numExchanges(ch)
		if n == 0 {
			return true, nil
		}
		status = append(status,
			fmt.Sprintf("%s: %d open", ch.PeerInfo().ProcessName, n))
	}
	return false, status
}

func numConnections(ch *Channel) int {
	rootPeers := ch.RootPeers().Copy()
	count := 0

	for _, peer := range rootPeers {
		in, out := peer.NumConnections()
		count += in + out
	}

	return count
}

func numExchanges(ch *Channel) int {
	var num int
	rootPeers := ch.RootPeers().Copy()
	for _, p := range rootPeers {
		state := p.IntrospectState(nil)
		for _, c := range state.InboundConnections {
			num += c.InboundExchange.Count + c.OutboundExchange.Count
		}
		for _, c := range state.OutboundConnections {
			num += c.InboundExchange.Count + c.OutboundExchange.Count
		}
	}
	return num
}

func connectionStatus(channels []*Channel) string {
	status := make([]string, 0)
	for _, ch := range channels {
		status = append(status,
			fmt.Sprintf("%s: %d open", ch.PeerInfo().ProcessName, numConnections(ch)))
	}
	return strings.Join(status, ", ")
}

// Validates that inbound idle connections are dropped.
func TestServerBasedSweep(t *testing.T) {
	listener := newPeerStatusListener()
	ctx, cancel := NewContext(time.Second)
	defer cancel()

	serverTicker := testutils.NewFakeTicker()
	clock := testutils.NewStubClock(time.Now())

	serverOpts := testutils.NewOpts().
		SetTimeTicker(serverTicker.New).
		SetIdleCheckInterval(30 * time.Second).
		SetMaxIdleTime(3 * time.Minute).
		SetOnPeerStatusChanged(listener.onStatusChange).
		SetTimeNow(clock.Now).
		NoRelay()

	clientOpts := testutils.NewOpts().
		SetOnPeerStatusChanged(listener.onStatusChange)

	testutils.WithTestServer(t, serverOpts, func(t testing.TB, ts *testutils.TestServer) {
		testutils.RegisterEcho(ts.Server(), nil)

		client := ts.NewClient(clientOpts)
		raw.Call(ctx, client, ts.HostPort(), ts.ServiceName(), "echo", nil, nil)

		// Both server and client now have an active connection. After 3 minutes they
		// should be cleared out by the idle sweep.
		for i := 0; i < 2; i++ {
			clock.Elapse(1 * time.Minute)
			serverTicker.Tick()

			assert.Equal(t, 1, numConnections(ts.Server()))
			assert.Equal(t, 1, numConnections(client))
		}

		// Move the clock forward and trigger the idle poller.
		clock.Elapse(90 * time.Second)
		serverTicker.Tick()
		listener.waitForZeroConnections(t, ts.Server(), client)
	})
}

// Validates that outbound idle connections are dropped.
func TestClientBasedSweep(t *testing.T) {
	listener := newPeerStatusListener()
	ctx, cancel := NewContext(time.Second)
	defer cancel()

	clientTicker := testutils.NewFakeTicker()
	clock := testutils.NewStubClock(time.Now())

	serverOpts := testutils.NewOpts().
		SetOnPeerStatusChanged(listener.onStatusChange).
		NoRelay()

	clientOpts := testutils.NewOpts().
		SetTimeNow(clock.Now).
		SetTimeTicker(clientTicker.New).
		SetMaxIdleTime(3 * time.Minute).
		SetOnPeerStatusChanged(listener.onStatusChange).
		SetIdleCheckInterval(30 * time.Second)

	testutils.WithTestServer(t, serverOpts, func(t testing.TB, ts *testutils.TestServer) {
		testutils.RegisterEcho(ts.Server(), nil)

		client := ts.NewClient(clientOpts)
		raw.Call(ctx, client, ts.HostPort(), ts.ServiceName(), "echo", nil, nil)

		// Both server and client now have an active connection. After 3 minutes they
		// should be cleared out by the idle sweep.
		clientTicker.Tick()

		assert.Equal(t, 1, numConnections(ts.Server()))
		assert.Equal(t, 1, numConnections(client))

		// Move the clock forward and trigger the idle poller.
		clock.Elapse(180 * time.Second)
		clientTicker.Tick()
		listener.waitForZeroConnections(t, ts.Server(), client)
	})
}

// Validates that a relay also disconnects idle connections - both inbound and
// outbound.
func TestRelayBasedSweep(t *testing.T) {
	listener := newPeerStatusListener()
	relayTicker := testutils.NewFakeTicker()
	clock := testutils.NewStubClock(time.Now())

	opts := testutils.NewOpts().
		SetOnPeerStatusChanged(listener.onStatusChange)

	relayOpts := testutils.NewOpts().
		SetTimeNow(clock.Now).
		SetTimeTicker(relayTicker.New).
		SetMaxIdleTime(3 * time.Minute).
		SetIdleCheckInterval(30 * time.Second).
		SetOnPeerStatusChanged(listener.onStatusChange).
		SetDisableServer(). // We create our own server without the idle sweeper.
		SetRelayOnly()
	testutils.WithTestServer(t, relayOpts, func(t testing.TB, ts *testutils.TestServer) {
		server := ts.NewServer(opts)
		testutils.RegisterEcho(server, nil)

		// Make a call to the server via relay, which will establish connections:
		// Client -> Relay -> Server
		client := ts.NewClient(opts)
		testutils.AssertEcho(t, client, ts.HostPort(), server.ServiceName())

		relayTicker.Tick()

		// Relay has 1 inbound + 1 outbound
		assert.Equal(t, 2, numConnections(ts.Relay()))
		assert.Equal(t, 1, numConnections(server))
		assert.Equal(t, 1, numConnections(client))

		// The relay will drop both sides of the connection after 3 minutes of inactivity.
		clock.Elapse(180 * time.Second)
		listener.waitForZeroExchanges(t, client)

		relayTicker.Tick()
		listener.waitForZeroConnections(t, ts.Relay(), server, client)
	})
}

// Validates that pings do not keep the connection alive.
func TestIdleSweepWithPings(t *testing.T) {
	listener := newPeerStatusListener()
	ctx, cancel := NewContext(time.Second)
	defer cancel()

	clientTicker := testutils.NewFakeTicker()
	clock := testutils.NewStubClock(time.Now())

	serverOpts := testutils.NewOpts().
		SetOnPeerStatusChanged(listener.onStatusChange).
		NoRelay()

	clientOpts := testutils.NewOpts().
		SetTimeNow(clock.Now).
		SetTimeTicker(clientTicker.New).
		SetMaxIdleTime(3 * time.Minute).
		SetIdleCheckInterval(30 * time.Second).
		SetOnPeerStatusChanged(listener.onStatusChange)

	testutils.WithTestServer(t, serverOpts, func(t testing.TB, ts *testutils.TestServer) {
		testutils.RegisterEcho(ts.Server(), nil)

		client := ts.NewClient(clientOpts)
		raw.Call(ctx, client, ts.HostPort(), ts.ServiceName(), "echo", nil, nil)

		// Generate pings every minute.
		for i := 0; i < 2; i++ {
			clock.Elapse(60 * time.Second)
			client.Ping(ctx, ts.HostPort())

			clientTicker.Tick()

			assert.Equal(t, 1, numConnections(ts.Server()))
			assert.Equal(t, 1, numConnections(client))
		}

		clock.Elapse(60 * time.Second)
		clientTicker.Tick()

		// Connections should still drop, regardless of the ping.
		listener.waitForZeroConnections(t, ts.Server(), client)
	})
}

// Validates that when MaxIdleTime isn't set, NewChannel returns an error.
func TestIdleSweepMisconfiguration(t *testing.T) {
	ch, err := NewChannel("svc", &ChannelOptions{
		IdleCheckInterval: time.Duration(30 * time.Second),
	})

	assert.Nil(t, ch, "NewChannel should not return a channel")
	assert.Error(t, err, "NewChannel should fail")
}

func TestIdleSweepIgnoresConnectionsWithCalls(t *testing.T) {
	ctx, cancel := NewContext(time.Second)
	defer cancel()

	clientTicker := testutils.NewFakeTicker()
	clock := testutils.NewStubClock(time.Now())

	listener := newPeerStatusListener()
	// TODO: Log filtering doesn't require the message to be seen.
	serverOpts := testutils.NewOpts().
		AddLogFilter("Skip closing idle Connection as it has pending calls.", 2).
		SetOnPeerStatusChanged(listener.onStatusChange).
		SetTimeNow(clock.Now).
		SetTimeTicker(clientTicker.New).
		SetRelayMaxTimeout(time.Hour).
		SetMaxIdleTime(3 * time.Minute).
		SetIdleCheckInterval(30 * time.Second)

	testutils.WithTestServer(t, serverOpts, func(t testing.TB, ts *testutils.TestServer) {
		var (
			gotCall = make(chan struct{})
			block   = make(chan struct{})
		)
		testutils.RegisterEcho(ts.Server(), func() {
			close(gotCall)
			<-block
		})

		clientOpts := testutils.NewOpts().SetOnPeerStatusChanged(listener.onStatusChange)

		// Client 1 will just ping, so we create a connection that should be closed.
		c1 := ts.NewClient(clientOpts)
		require.True(t, testutils.WaitFor(5*time.Second, func() bool {
			return c1.Ping(ctx, ts.HostPort()) == nil
		}), "Ping failed")

		// Client 2 will make a call that will be blocked. Wait for the call to be received.
		c2CallComplete := make(chan struct{})
		c2 := ts.NewClient(clientOpts)
		go func() {
			testutils.AssertEcho(t, c2, ts.HostPort(), ts.ServiceName())
			close(c2CallComplete)
		}()
		<-gotCall

		// If we are in no-relay mode, we expect 2 connections to the server (from each client).
		// If we are in relay mode, the relay will have the 2 connections from clients + 1 connection to the server.
		check := struct {
			ch            *Channel
			preCloseConns int
			tick          func()
		}{
			ch:            ts.Server(),
			preCloseConns: 2,
			tick: func() {
				clock.Elapse(5 * time.Minute)
				clientTicker.Tick()
			},
		}

		if ts.HasRelay() {
			relay := ts.Relay()
			check.ch = relay
			check.preCloseConns++
			oldTick := check.tick
			check.tick = func() {
				oldTick()

				// The same ticker is being used by the server and the relay
				// so we need to tick it twice.
				clientTicker.Tick()
			}
		}

		assert.Equal(t, check.preCloseConns, check.ch.IntrospectNumConnections(), "Expect connection to client 1 and client 2")

		// Let the idle checker close client 1's connection.
		check.tick()
		listener.waitForZeroConnections(t, c1)

		// Make sure we have only a connection for client 2, which is active.
		assert.Equal(t, check.preCloseConns-1, check.ch.IntrospectNumConnections(), "Expect connection only to client 2")
		state := check.ch.IntrospectState(nil)
		require.Empty(t, state.InactiveConnections, "Ensure all connections are active")

		// Unblock the call.
		close(block)
		<-c2CallComplete

		// Since the idle sweep loop and message exchange run concurrently, there is
		// a race between the idle sweep and exchange shutdown. To mitigate this,
		// wait for the exchanges to shut down before triggering the idle sweep.
		listener.waitForZeroExchanges(t, ts.Server(), c2)

		check.tick()
		listener.waitForZeroConnections(t, ts.Server(), c2)
	})
}
<commit_msg>fix flaky test TestIdleSweepIgnoresConnectionsWithCalls (#873)<commit_after>// Copyright (c) 2017 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package tchannel_test

import (
	"fmt"
	"strings"
	"testing"
	"time"

	. "github.com/uber/tchannel-go"

	"github.com/uber/tchannel-go/raw"
	"github.com/uber/tchannel-go/testutils"

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

// peerStatusListener is a test tool used to wait for connections to drop by
// listening to status events from a channel.
type peerStatusListener struct {
	changes chan struct{}
}

func newPeerStatusListener() *peerStatusListener {
	return &peerStatusListener{
		changes: make(chan struct{}, 10),
	}
}

func (pl *peerStatusListener) onStatusChange(p *Peer) {
	pl.changes <- struct{}{}
}

func (pl *peerStatusListener) waitForZeroConnections(t testing.TB, channels ...*Channel) bool {
	for {
		select {
		case <-pl.changes:
			if allConnectionsClosed(channels) {
				return true
			}

		case <-time.After(testutils.Timeout(time.Second)):
			t.Fatalf("Some connections are still open: %s", connectionStatus(channels))
			return false
		}
	}
}

func (pl *peerStatusListener) waitForZeroExchanges(t testing.TB, channels ...*Channel) {
	var (
		isEmpty bool
		status  []string
	)
	if !testutils.WaitFor(100*time.Millisecond, func() bool {
		isEmpty, status = allExchangesEmpty(channels)
		return isEmpty
	}) {
		t.Fatalf("Some exchanges are still non-empty: %s", strings.Join(status, ", "))
	}
}

func allConnectionsClosed(channels []*Channel) bool {
	for _, ch := range channels {
		if numConnections(ch) != 0 {
			return false
		}
	}

	return true
}

func allExchangesEmpty(channels []*Channel) (isEmpty bool, status []string) {
	for _, ch := range channels {
		n := numExchanges(ch)
		if n == 0 {
			return true, nil
		}
		status = append(status,
			fmt.Sprintf("%s: %d open", ch.PeerInfo().ProcessName, n))
	}
	return false, status
}

func numConnections(ch *Channel) int {
	rootPeers := ch.RootPeers().Copy()
	count := 0

	for _, peer := range rootPeers {
		in, out := peer.NumConnections()
		count += in + out
	}

	return count
}

func numExchanges(ch *Channel) int {
	var num int
	rootPeers := ch.RootPeers().Copy()
	for _, p := range rootPeers {
		state := p.IntrospectState(nil)
		for _, c := range state.InboundConnections {
			num += c.InboundExchange.Count + c.OutboundExchange.Count
		}
		for _, c := range state.OutboundConnections {
			num += c.InboundExchange.Count + c.OutboundExchange.Count
		}
	}
	return num
}

func connectionStatus(channels []*Channel) string {
	status := make([]string, 0)
	for _, ch := range channels {
		status = append(status,
			fmt.Sprintf("%s: %d open", ch.PeerInfo().ProcessName, numConnections(ch)))
	}
	return strings.Join(status, ", ")
}

// Validates that inbound idle connections are dropped.
func TestServerBasedSweep(t *testing.T) {
	listener := newPeerStatusListener()
	ctx, cancel := NewContext(time.Second)
	defer cancel()

	serverTicker := testutils.NewFakeTicker()
	clock := testutils.NewStubClock(time.Now())

	serverOpts := testutils.NewOpts().
		SetTimeTicker(serverTicker.New).
		SetIdleCheckInterval(30 * time.Second).
		SetMaxIdleTime(3 * time.Minute).
		SetOnPeerStatusChanged(listener.onStatusChange).
		SetTimeNow(clock.Now).
		NoRelay()

	clientOpts := testutils.NewOpts().
		SetOnPeerStatusChanged(listener.onStatusChange)

	testutils.WithTestServer(t, serverOpts, func(t testing.TB, ts *testutils.TestServer) {
		testutils.RegisterEcho(ts.Server(), nil)

		client := ts.NewClient(clientOpts)
		raw.Call(ctx, client, ts.HostPort(), ts.ServiceName(), "echo", nil, nil)

		// Both server and client now have an active connection. After 3 minutes they
		// should be cleared out by the idle sweep.
		for i := 0; i < 2; i++ {
			clock.Elapse(1 * time.Minute)
			serverTicker.Tick()

			assert.Equal(t, 1, numConnections(ts.Server()))
			assert.Equal(t, 1, numConnections(client))
		}

		// Move the clock forward and trigger the idle poller.
		clock.Elapse(90 * time.Second)
		serverTicker.Tick()
		listener.waitForZeroConnections(t, ts.Server(), client)
	})
}

// Validates that outbound idle connections are dropped.
func TestClientBasedSweep(t *testing.T) {
	listener := newPeerStatusListener()
	ctx, cancel := NewContext(time.Second)
	defer cancel()

	clientTicker := testutils.NewFakeTicker()
	clock := testutils.NewStubClock(time.Now())

	serverOpts := testutils.NewOpts().
		SetOnPeerStatusChanged(listener.onStatusChange).
		NoRelay()

	clientOpts := testutils.NewOpts().
		SetTimeNow(clock.Now).
		SetTimeTicker(clientTicker.New).
		SetMaxIdleTime(3 * time.Minute).
		SetOnPeerStatusChanged(listener.onStatusChange).
		SetIdleCheckInterval(30 * time.Second)

	testutils.WithTestServer(t, serverOpts, func(t testing.TB, ts *testutils.TestServer) {
		testutils.RegisterEcho(ts.Server(), nil)

		client := ts.NewClient(clientOpts)
		raw.Call(ctx, client, ts.HostPort(), ts.ServiceName(), "echo", nil, nil)

		// Both server and client now have an active connection. After 3 minutes they
		// should be cleared out by the idle sweep.
		clientTicker.Tick()

		assert.Equal(t, 1, numConnections(ts.Server()))
		assert.Equal(t, 1, numConnections(client))

		// Move the clock forward and trigger the idle poller.
		clock.Elapse(180 * time.Second)
		clientTicker.Tick()
		listener.waitForZeroConnections(t, ts.Server(), client)
	})
}

// Validates that a relay also disconnects idle connections - both inbound and
// outbound.
func TestRelayBasedSweep(t *testing.T) {
	listener := newPeerStatusListener()
	relayTicker := testutils.NewFakeTicker()
	clock := testutils.NewStubClock(time.Now())

	opts := testutils.NewOpts().
		SetOnPeerStatusChanged(listener.onStatusChange)

	relayOpts := testutils.NewOpts().
		SetTimeNow(clock.Now).
		SetTimeTicker(relayTicker.New).
		SetMaxIdleTime(3 * time.Minute).
		SetIdleCheckInterval(30 * time.Second).
		SetOnPeerStatusChanged(listener.onStatusChange).
		SetDisableServer(). // We create our own server without the idle sweeper.
		SetRelayOnly()
	testutils.WithTestServer(t, relayOpts, func(t testing.TB, ts *testutils.TestServer) {
		server := ts.NewServer(opts)
		testutils.RegisterEcho(server, nil)

		// Make a call to the server via relay, which will establish connections:
		// Client -> Relay -> Server
		client := ts.NewClient(opts)
		testutils.AssertEcho(t, client, ts.HostPort(), server.ServiceName())

		relayTicker.Tick()

		// Relay has 1 inbound + 1 outbound
		assert.Equal(t, 2, numConnections(ts.Relay()))
		assert.Equal(t, 1, numConnections(server))
		assert.Equal(t, 1, numConnections(client))

		// The relay will drop both sides of the connection after 3 minutes of inactivity.
		clock.Elapse(180 * time.Second)
		listener.waitForZeroExchanges(t, client)

		relayTicker.Tick()
		listener.waitForZeroConnections(t, ts.Relay(), server, client)
	})
}

// Validates that pings do not keep the connection alive.
func TestIdleSweepWithPings(t *testing.T) {
	listener := newPeerStatusListener()
	ctx, cancel := NewContext(time.Second)
	defer cancel()

	clientTicker := testutils.NewFakeTicker()
	clock := testutils.NewStubClock(time.Now())

	serverOpts := testutils.NewOpts().
		SetOnPeerStatusChanged(listener.onStatusChange).
		NoRelay()

	clientOpts := testutils.NewOpts().
		SetTimeNow(clock.Now).
		SetTimeTicker(clientTicker.New).
		SetMaxIdleTime(3 * time.Minute).
		SetIdleCheckInterval(30 * time.Second).
		SetOnPeerStatusChanged(listener.onStatusChange)

	testutils.WithTestServer(t, serverOpts, func(t testing.TB, ts *testutils.TestServer) {
		testutils.RegisterEcho(ts.Server(), nil)

		client := ts.NewClient(clientOpts)
		raw.Call(ctx, client, ts.HostPort(), ts.ServiceName(), "echo", nil, nil)

		// Generate pings every minute.
		for i := 0; i < 2; i++ {
			clock.Elapse(60 * time.Second)
			client.Ping(ctx, ts.HostPort())

			clientTicker.Tick()

			assert.Equal(t, 1, numConnections(ts.Server()))
			assert.Equal(t, 1, numConnections(client))
		}

		clock.Elapse(60 * time.Second)
		clientTicker.Tick()

		// Connections should still drop, regardless of the ping.
		listener.waitForZeroConnections(t, ts.Server(), client)
	})
}

// Validates that when MaxIdleTime isn't set, NewChannel returns an error.
func TestIdleSweepMisconfiguration(t *testing.T) {
	ch, err := NewChannel("svc", &ChannelOptions{
		IdleCheckInterval: time.Duration(30 * time.Second),
	})

	assert.Nil(t, ch, "NewChannel should not return a channel")
	assert.Error(t, err, "NewChannel should fail")
}

func TestIdleSweepIgnoresConnectionsWithCalls(t *testing.T) {
	ctx, cancel := NewContext(time.Second)
	defer cancel()

	clientTicker := testutils.NewFakeTicker()
	clock := testutils.NewStubClock(time.Now())

	listener := newPeerStatusListener()
	// TODO: Log filtering doesn't require the message to be seen.
	serverOpts := testutils.NewOpts().
		AddLogFilter("Skip closing idle Connection as it has pending calls.", 2).
		SetOnPeerStatusChanged(listener.onStatusChange).
		SetTimeNow(clock.Now).
		SetTimeTicker(clientTicker.New).
		SetRelayMaxTimeout(time.Hour).
		SetMaxIdleTime(3 * time.Minute).
		SetIdleCheckInterval(30 * time.Second)

	testutils.WithTestServer(t, serverOpts, func(t testing.TB, ts *testutils.TestServer) {
		var (
			gotCall = make(chan struct{})
			block   = make(chan struct{})
		)
		testutils.RegisterEcho(ts.Server(), func() {
			close(gotCall)
			<-block
		})

		clientOpts := testutils.NewOpts().SetOnPeerStatusChanged(listener.onStatusChange)

		// Client 1 will just ping, so we create a connection that should be closed.
		c1 := ts.NewClient(clientOpts)
		require.True(t, testutils.WaitFor(10*time.Second, func() bool {
			return c1.Ping(ctx, ts.HostPort()) == nil
		}), "Ping failed")

		// Client 2 will make a call that will be blocked. Wait for the call to be received.
		c2CallComplete := make(chan struct{})
		c2 := ts.NewClient(clientOpts)
		go func() {
			testutils.AssertEcho(t, c2, ts.HostPort(), ts.ServiceName())
			close(c2CallComplete)
		}()
		<-gotCall

		// If we are in no-relay mode, we expect 2 connections to the server (from each client).
		// If we are in relay mode, the relay will have the 2 connections from clients + 1 connection to the server.
		check := struct {
			ch            *Channel
			preCloseConns int
			tick          func()
		}{
			ch:            ts.Server(),
			preCloseConns: 2,
			tick: func() {
				clock.Elapse(5 * time.Minute)
				clientTicker.Tick()
			},
		}

		if ts.HasRelay() {
			relay := ts.Relay()
			check.ch = relay
			check.preCloseConns++
			oldTick := check.tick
			check.tick = func() {
				oldTick()

				// The same ticker is being used by the server and the relay
				// so we need to tick it twice.
				clientTicker.Tick()
			}
		}

		assert.Equal(t, check.preCloseConns, check.ch.IntrospectNumConnections(), "Expect connection to client 1 and client 2")

		// Let the idle checker close client 1's connection.
		listener.waitForZeroExchanges(t, c1)

		check.tick()
		listener.waitForZeroConnections(t, c1)

		// Make sure we have only a connection for client 2, which is active.
		assert.Equal(t, check.preCloseConns-1, check.ch.IntrospectNumConnections(), "Expect connection only to client 2")
		state := check.ch.IntrospectState(nil)
		require.Empty(t, state.InactiveConnections, "Ensure all connections are active")

		// Unblock the call.
		close(block)
		<-c2CallComplete

		// Since the idle sweep loop and message exchange run concurrently, there is
		// a race between the idle sweep and exchange shutdown. To mitigate this,
		// wait for the exchanges to shut down before triggering the idle sweep.
		listener.waitForZeroExchanges(t, ts.Server(), c2)

		check.tick()
		listener.waitForZeroConnections(t, ts.Server(), c2)
	})
}
<|endoftext|>


<commit_before>package dice

import (
	"errors"
	"fmt"
	"regexp"
	"strings"
)

type RollResult interface {
	fmt.Stringer
	Description() string
	Int() int
}

type roller interface {
	Pattern() *regexp.Regexp
	Roll([]string) (RollResult, error)
}

type basicRollResult struct {
	desc string
}

func (r basicRollResult) Description() string { return strings.Trim(r.desc, " \t\r\n") }

var rollHandlers []roller

func addRollHandler(handler roller) {
	rollHandlers = append(rollHandlers, handler)
}

/*
	open - regexp.MustCompile(`([0-9]+)d([0-9]+)(e)?o$`)
	sil - regexp.MustCompile(`([0-9]+)d([0-9]+)(e)?s$`)
*/

func Roll(desc string) (RollResult, string, error) {
	for _, rollHandler := range rollHandlers {
		rollHandler.Pattern().Longest()

		if r := rollHandler.Pattern().FindStringSubmatch(desc); r != nil {
			result, err := rollHandler.Roll(r)
			if err != nil {
				return nil, "", err
			}

			indexes := rollHandler.Pattern().FindStringSubmatchIndex(desc)
			reason := strings.Trim(desc[indexes[0]+len(r[0]):], " \t\r\n")
			return result, reason, nil
		}
	}

	return nil, "", errors.New("Bad roll format: " + desc)
}
<commit_msg>Add some package documentation.<commit_after>// Package dice provides a library for rolling tabletop role-playing style dice
// via a text description similar to that used in such games.
//
// Examples
//
//    dice.Roll("3d6") // Roll and sum 3 six-sided dice
//    dice.Roll("1d20+2") // Roll a twenty-sided die and add 2
//
// Supported formats
//
// Standard: `xdy[[k|d][h|l]z][+/-c]` - rolls and sums x y-sided dice,
// keeping or dropping the lowest or highest z dice and optionally adding
// or subtracting c. Example: 4d6kh3+4
//
// Fudge: `xdf[+/-c]` - rolls and sums x fudge dice (Dice that return
// numbers between -1 and 1), and optionally adding or subtracting c.
// Example: 4df+4
//
// Versus: `xdy[e|r]vt` - rolls x y-sided dice, counting the number that
// roll t or greater.
//
// EotE: `xc [xc ...]` - rolls x dice of color c (b, blk, g, p, r, w, y)
// and returns the aggregate result.
package dice

import (
	"errors"
	"fmt"
	"regexp"
	"strings"
)

// RollResult is an interface to describe a dice roll and its outcome.
//
// RollResult contains [fmt.Stringer], and calling `String()` on a RollResult
// will get a textual description of the roll outcome.
//
// Description returns a textual description of the roll. This is often the
// same as the input to [dice.Roll].
//
// Int will get the result of the roll as an integer.
type RollResult interface {
	fmt.Stringer

	Description() string

	Int() int
}

type roller interface {
	Pattern() *regexp.Regexp
	Roll([]string) (RollResult, error)
}

type basicRollResult struct {
	desc string
}

func (r basicRollResult) Description() string { return strings.Trim(r.desc, " \t\r\n") }

var rollHandlers []roller

func addRollHandler(handler roller) {
	rollHandlers = append(rollHandlers, handler)
}

// Roll parses the given description and calls the appropriate roller implementation,
// if found. Returns the result plus any extra trailing text if successful.
func Roll(desc string) (RollResult, string, error) {
	for _, rollHandler := range rollHandlers {
		rollHandler.Pattern().Longest()

		if r := rollHandler.Pattern().FindStringSubmatch(desc); r != nil {
			result, err := rollHandler.Roll(r)
			if err != nil {
				return nil, "", err
			}

			indexes := rollHandler.Pattern().FindStringSubmatchIndex(desc)
			reason := strings.Trim(desc[indexes[0]+len(r[0]):], " \t\r\n")
			return result, reason, nil
		}
	}

	return nil, "", errors.New("Bad roll format: " + desc)
}
<|endoftext|>


<commit_before>package models

import (
	"socialapi/workers/common/runner"
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

func TestChannelMessageListFetchMessageChannels(t *testing.T) {
	r := runner.New("test")
	if err := r.Init(); err != nil {
		t.Fatalf("couldnt start bongo %s", err.Error())
	}
	defer r.Close()

	Convey("while fethcing channel message of a message", t, func() {
		Convey("channels should be valid", func() {
			c1 := createNewChannelWithTest()
			So(c1.Create(), ShouldBeNil)

			c2 := createNewChannelWithTest()
			So(c2.Create(), ShouldBeNil)

			c3 := createNewChannelWithTest()
			So(c3.Create(), ShouldBeNil)

			cm := NewChannelMessage()
			cm.Body = "gel beri abi"
			cm.AccountId = c1.CreatorId
			cm.InitialChannelId = c1.Id
			So(cm.Create(), ShouldBeNil)

			// add to first channel
			_, err := c1.AddMessage(cm.Id)
			So(err, ShouldBeNil)

			// add to second channel
			_, err = c2.AddMessage(cm.Id)
			So(err, ShouldBeNil)

			// add to 3rd channel
			_, err = c3.AddMessage(cm.Id)
			So(err, ShouldBeNil)

			channels, err := NewChannelMessageList().FetchMessageChannels(cm.Id)
			So(err, ShouldBeNil)
			So(len(channels), ShouldEqual, 3)

			So(c1.Name, ShouldEqual, channels[0].Name)
			So(c2.Name, ShouldEqual, channels[1].Name)
			So(c3.Name, ShouldEqual, channels[2].Name)

			So(c1.GroupName, ShouldEqual, channels[0].GroupName)
			So(c2.GroupName, ShouldEqual, channels[1].GroupName)
			So(c3.GroupName, ShouldEqual, channels[2].GroupName)
		})
	})
}

func TestChannelMessageListCount(t *testing.T) {
	r := runner.New("test")
	if err := r.Init(); err != nil {
		t.Fatalf("couldnt start bongo %s", err.Error())
	}
	defer r.Close()

	Convey("while counting messages", t, func() {
		Convey("it should error if channel id is not set", func() {
			cml := NewChannelMessageList()

			c, err := cml.Count(0)
			So(err, ShouldNotBeNil)
			So(err, ShouldEqual, ErrChannelIdIsNotSet)
			So(c, ShouldEqual, 0)
		})

		Convey("it should not error if message in the channel", func() {
			// create message
			cm := createMessageWithTest()
			So(cm.Create(), ShouldBeNil)

			c := createNewChannelWithTest()
			So(c.Create(), ShouldBeNil)

			_, err := c.AddMessage(cm.Id)
			So(err, ShouldBeNil)

			cml := NewChannelMessageList()
			cml.ChannelId = c.Id

			cnt, err := cml.Count(cml.ChannelId)
			So(err, ShouldBeNil)
			So(cnt, ShouldEqual, 1)
		})

		Convey("it should not count message if account of message is troll ", func() {
			// create channel
			c := createNewChannelWithTest()
			So(c.Create(), ShouldBeNil)

			// create account as troll
			acc1 := createAccountWithTest()
			acc1.IsTroll = true
			So(acc1.Create(), ShouldBeNil)

			acc2 := createAccountWithTest()
			So(acc2.Create(), ShouldBeNil)

			// create message that creator is troll
			msg := createMessageWithTest()
			msg.AccountId = acc1.Id
			So(msg.Create(), ShouldBeNil)

			msg2 := createMessageWithTest()
			msg2.AccountId = acc2.Id
			So(msg2.Create(), ShouldBeNil)

			// add message to the channel
			// account is troll !!
			_, err := c.AddMessage(msg.Id)
			So(err, ShouldBeNil)

			_, erre := c.AddMessage(msg2.Id)
			So(erre, ShouldBeNil)

			cml := NewChannelMessageList()
			cml.ChannelId = c.Id

			// there is 2 message in the channel
			// but one of the account of message is troll so;
			// Count will not count this message
			// messages of troll is not valid to count
			cnt, err := cml.Count(cml.ChannelId)
			So(err, ShouldBeNil)
			So(cnt, ShouldEqual, 1)
		})
	})
}

func TestChannelMessageListisExempt(t *testing.T) {
	r := runner.New("test")
	if err := r.Init(); err != nil {
		t.Fatalf("couldnt start bongo %s", err.Error())
	}
	defer r.Close()

	Convey("while testing is exempt", t, func() {
		Convey("it should have error if message id is not set ", func() {
			cml := NewChannelMessageList()

			is, err := cml.isExempt()
			So(err, ShouldNotBeNil)
			So(err, ShouldEqual, ErrMessageIdIsNotSet)
			So(is, ShouldEqual, false)
		})

		Convey("it should return true is channel is exempt", func() {
			// create account as troll
			acc := createAccountWithTest()
			acc.IsTroll = true
			So(acc.Create(), ShouldBeNil)
			// create channel
			c := createNewChannelWithTest()
			c.CreatorId = acc.Id

			// create message
			msg := createMessageWithTest()
			msg.AccountId = acc.Id
			So(msg.Create(), ShouldBeNil)

			cml := NewChannelMessageList()
			cml.ChannelId = c.Id
			cml.MessageId = msg.Id

			is, err := cml.isExempt()
			So(err, ShouldBeNil)
			So(is, ShouldEqual, true)
		})

		Convey("it should return false is channel is not exempt", func() {
			// create account as not troll
			acc := createAccountWithTest()
			acc.IsTroll = false
			So(acc.Create(), ShouldBeNil)
			// create channel
			c := createNewChannelWithTest()
			c.CreatorId = acc.Id

			// create message
			msg := createMessageWithTest()
			msg.AccountId = acc.Id
			So(msg.Create(), ShouldBeNil)

			cml := NewChannelMessageList()
			cml.ChannelId = c.Id
			cml.MessageId = msg.Id

			is, err := cml.isExempt()
			So(err, ShouldBeNil)
			So(is, ShouldEqual, false)
		})
	})
}

func TestChannelMessageListMarkIfExempt(t *testing.T) {
	r := runner.New("test")
	if err := r.Init(); err != nil {
		t.Fatalf("couldnt start bongo %s", err.Error())
	}
	defer r.Close()

	Convey("while marking if channel is exempt", t, func() {
		Convey("it should have error if message id is not set", func() {
			cml := NewChannelMessageList()

			err := cml.MarkIfExempt()
			So(err, ShouldNotBeNil)
			So(err, ShouldEqual, ErrMessageIdIsNotSet)
		})

	})
}
<commit_msg>social/tests: markIfExempt tests are done, in channelmessagelist<commit_after>package models

import (
	"socialapi/workers/common/runner"
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

func TestChannelMessageListFetchMessageChannels(t *testing.T) {
	r := runner.New("test")
	if err := r.Init(); err != nil {
		t.Fatalf("couldnt start bongo %s", err.Error())
	}
	defer r.Close()

	Convey("while fethcing channel message of a message", t, func() {
		Convey("channels should be valid", func() {
			c1 := createNewChannelWithTest()
			So(c1.Create(), ShouldBeNil)

			c2 := createNewChannelWithTest()
			So(c2.Create(), ShouldBeNil)

			c3 := createNewChannelWithTest()
			So(c3.Create(), ShouldBeNil)

			cm := NewChannelMessage()
			cm.Body = "gel beri abi"
			cm.AccountId = c1.CreatorId
			cm.InitialChannelId = c1.Id
			So(cm.Create(), ShouldBeNil)

			// add to first channel
			_, err := c1.AddMessage(cm.Id)
			So(err, ShouldBeNil)

			// add to second channel
			_, err = c2.AddMessage(cm.Id)
			So(err, ShouldBeNil)

			// add to 3rd channel
			_, err = c3.AddMessage(cm.Id)
			So(err, ShouldBeNil)

			channels, err := NewChannelMessageList().FetchMessageChannels(cm.Id)
			So(err, ShouldBeNil)
			So(len(channels), ShouldEqual, 3)

			So(c1.Name, ShouldEqual, channels[0].Name)
			So(c2.Name, ShouldEqual, channels[1].Name)
			So(c3.Name, ShouldEqual, channels[2].Name)

			So(c1.GroupName, ShouldEqual, channels[0].GroupName)
			So(c2.GroupName, ShouldEqual, channels[1].GroupName)
			So(c3.GroupName, ShouldEqual, channels[2].GroupName)
		})
	})
}

func TestChannelMessageListCount(t *testing.T) {
	r := runner.New("test")
	if err := r.Init(); err != nil {
		t.Fatalf("couldnt start bongo %s", err.Error())
	}
	defer r.Close()

	Convey("while counting messages", t, func() {
		Convey("it should error if channel id is not set", func() {
			cml := NewChannelMessageList()

			c, err := cml.Count(0)
			So(err, ShouldNotBeNil)
			So(err, ShouldEqual, ErrChannelIdIsNotSet)
			So(c, ShouldEqual, 0)
		})

		Convey("it should not error if message in the channel", func() {
			// create message
			cm := createMessageWithTest()
			So(cm.Create(), ShouldBeNil)

			c := createNewChannelWithTest()
			So(c.Create(), ShouldBeNil)

			_, err := c.AddMessage(cm.Id)
			So(err, ShouldBeNil)

			cml := NewChannelMessageList()
			cml.ChannelId = c.Id

			cnt, err := cml.Count(cml.ChannelId)
			So(err, ShouldBeNil)
			So(cnt, ShouldEqual, 1)
		})

		Convey("it should not count message if account of message is troll ", func() {
			// create channel
			c := createNewChannelWithTest()
			So(c.Create(), ShouldBeNil)

			// create account as troll
			acc1 := createAccountWithTest()
			acc1.IsTroll = true
			So(acc1.Create(), ShouldBeNil)

			acc2 := createAccountWithTest()
			So(acc2.Create(), ShouldBeNil)

			// create message that creator is troll
			msg := createMessageWithTest()
			msg.AccountId = acc1.Id
			So(msg.Create(), ShouldBeNil)

			msg2 := createMessageWithTest()
			msg2.AccountId = acc2.Id
			So(msg2.Create(), ShouldBeNil)

			// add message to the channel
			// account is troll !!
			_, err := c.AddMessage(msg.Id)
			So(err, ShouldBeNil)

			_, erre := c.AddMessage(msg2.Id)
			So(erre, ShouldBeNil)

			cml := NewChannelMessageList()
			cml.ChannelId = c.Id

			// there is 2 message in the channel
			// but one of the account of message is troll so;
			// Count will not count this message
			// messages of troll is not valid to count
			cnt, err := cml.Count(cml.ChannelId)
			So(err, ShouldBeNil)
			So(cnt, ShouldEqual, 1)
		})
	})
}

func TestChannelMessageListisExempt(t *testing.T) {
	r := runner.New("test")
	if err := r.Init(); err != nil {
		t.Fatalf("couldnt start bongo %s", err.Error())
	}
	defer r.Close()

	Convey("while testing is exempt", t, func() {
		Convey("it should have error if message id is not set ", func() {
			cml := NewChannelMessageList()

			is, err := cml.isExempt()
			So(err, ShouldNotBeNil)
			So(err, ShouldEqual, ErrMessageIdIsNotSet)
			So(is, ShouldEqual, false)
		})

		Convey("it should return true is channel is exempt", func() {
			// create account as troll
			acc := createAccountWithTest()
			acc.IsTroll = true
			So(acc.Create(), ShouldBeNil)
			// create channel
			c := createNewChannelWithTest()
			c.CreatorId = acc.Id

			// create message
			msg := createMessageWithTest()
			msg.AccountId = acc.Id
			So(msg.Create(), ShouldBeNil)

			cml := NewChannelMessageList()
			cml.ChannelId = c.Id
			cml.MessageId = msg.Id

			is, err := cml.isExempt()
			So(err, ShouldBeNil)
			So(is, ShouldEqual, true)
		})

		Convey("it should return false is channel is not exempt", func() {
			// create account as not troll
			acc := createAccountWithTest()
			acc.IsTroll = false
			So(acc.Create(), ShouldBeNil)
			// create channel
			c := createNewChannelWithTest()
			c.CreatorId = acc.Id

			// create message
			msg := createMessageWithTest()
			msg.AccountId = acc.Id
			So(msg.Create(), ShouldBeNil)

			cml := NewChannelMessageList()
			cml.ChannelId = c.Id
			cml.MessageId = msg.Id

			is, err := cml.isExempt()
			So(err, ShouldBeNil)
			So(is, ShouldEqual, false)
		})
	})
}

func TestChannelMessageListMarkIfExempt(t *testing.T) {
	r := runner.New("test")
	if err := r.Init(); err != nil {
		t.Fatalf("couldnt start bongo %s", err.Error())
	}
	defer r.Close()

	Convey("while marking if channel is exempt", t, func() {
		Convey("it should have error if message id is not set", func() {
			cml := NewChannelMessageList()

			err := cml.MarkIfExempt()
			So(err, ShouldNotBeNil)
			So(err, ShouldEqual, ErrMessageIdIsNotSet)
		})

		Convey("it should mark as exempt if channel is exempt", func() {
			// create account as troll
			acc := createAccountWithTest()
			acc.IsTroll = true
			So(acc.Create(), ShouldBeNil)
			// create channel
			c := createNewChannelWithTest()
			c.CreatorId = acc.Id

			// create message
			msg := createMessageWithTest()
			msg.AccountId = acc.Id
			So(msg.Create(), ShouldBeNil)

			cml := NewChannelMessageList()
			cml.ChannelId = c.Id
			cml.MessageId = msg.Id

			err := cml.MarkIfExempt()
			So(err, ShouldBeNil)
		})

	})
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strings"

	_ "v.io/core/veyron/profiles"
	"v.io/core/veyron2"
	"v.io/core/veyron2/ipc"
	"v.io/core/veyron2/naming"
	"v.io/core/veyron2/security"

	"test_service"
)

// openAuthorizer allows RPCs from all clients.
type openAuthorizer struct{}

func (openAuthorizer) Authorize(security.Context) error {
	return nil
}

type testServiceDispatcher struct {
	cache           interface{}
	errorThrower    interface{}
	cancelCollector interface{}
}

func (sd *testServiceDispatcher) Lookup(suffix string) (interface{}, security.Authorizer, error) {
	authorizer := openAuthorizer{}

	if strings.HasPrefix(suffix, "cache") {
		return ipc.ReflectInvoker(sd.cache), authorizer, nil
	}

	if strings.HasPrefix(suffix, "errorThrower") {
		return ipc.ReflectInvoker(sd.errorThrower), authorizer, nil
	}

	if strings.HasPrefix(suffix, "serviceToCancel") {
		return ipc.ReflectInvoker(sd.cancelCollector), authorizer, nil
	}

	return ipc.ReflectInvoker(sd.cache), authorizer, nil
}

func StartServer(r veyron2.Runtime) (ipc.Server, naming.Endpoint, error) {
	// Create a new server instance.
	s, err := r.NewServer()
	if err != nil {
		return nil, nil, fmt.Errorf("failure creating server: %v", err)
	}

	disp := &testServiceDispatcher{
		cache:           test_service.CacheServer(NewCached()),
		errorThrower:    test_service.ErrorThrowerServer(NewErrorThrower()),
		cancelCollector: test_service.CancelCollectorServer(NewCancelCollector()),
	}

	// Create an endpoint and begin listening.
	spec := ipc.ListenSpec{Addrs: ipc.ListenAddrs{{"ws", "127.0.0.1:0"}}}
	endpoints, err := s.Listen(spec)
	if err != nil {
		return nil, nil, fmt.Errorf("error listening to service: %v", err)
	}

	// Publish the services. This will register them in the mount table and
	// maintain the registration until StopServing is called.
	if err := s.ServeDispatcher("test_service", disp); err != nil {
		return nil, nil, fmt.Errorf("error publishing service '%s': %v", err)
	}

	return s, endpoints[0], nil
}
<commit_msg>javascript: Change ReflectInvoker to ReflectInvokerOrDie.<commit_after>package main

import (
	"fmt"
	"strings"

	_ "v.io/core/veyron/profiles"
	"v.io/core/veyron2"
	"v.io/core/veyron2/ipc"
	"v.io/core/veyron2/naming"
	"v.io/core/veyron2/security"

	"test_service"
)

// openAuthorizer allows RPCs from all clients.
type openAuthorizer struct{}

func (openAuthorizer) Authorize(security.Context) error {
	return nil
}

type testServiceDispatcher struct {
	cache           interface{}
	errorThrower    interface{}
	cancelCollector interface{}
}

func (sd *testServiceDispatcher) Lookup(suffix string) (interface{}, security.Authorizer, error) {
	authorizer := openAuthorizer{}

	if strings.HasPrefix(suffix, "cache") {
		return ipc.ReflectInvokerOrDie(sd.cache), authorizer, nil
	}

	if strings.HasPrefix(suffix, "errorThrower") {
		return ipc.ReflectInvokerOrDie(sd.errorThrower), authorizer, nil
	}

	if strings.HasPrefix(suffix, "serviceToCancel") {
		return ipc.ReflectInvokerOrDie(sd.cancelCollector), authorizer, nil
	}

	return ipc.ReflectInvokerOrDie(sd.cache), authorizer, nil
}

func StartServer(r veyron2.Runtime) (ipc.Server, naming.Endpoint, error) {
	// Create a new server instance.
	s, err := r.NewServer()
	if err != nil {
		return nil, nil, fmt.Errorf("failure creating server: %v", err)
	}

	disp := &testServiceDispatcher{
		cache:           test_service.CacheServer(NewCached()),
		errorThrower:    test_service.ErrorThrowerServer(NewErrorThrower()),
		cancelCollector: test_service.CancelCollectorServer(NewCancelCollector()),
	}

	// Create an endpoint and begin listening.
	spec := ipc.ListenSpec{Addrs: ipc.ListenAddrs{{"ws", "127.0.0.1:0"}}}
	endpoints, err := s.Listen(spec)
	if err != nil {
		return nil, nil, fmt.Errorf("error listening to service: %v", err)
	}

	// Publish the services. This will register them in the mount table and
	// maintain the registration until StopServing is called.
	if err := s.ServeDispatcher("test_service", disp); err != nil {
		return nil, nil, fmt.Errorf("error publishing service '%s': %v", err)
	}

	return s, endpoints[0], nil
}
<|endoftext|>


<commit_before>package config

import (
	"github.com/mitchellh/go-homedir"
	"strings"
	"testing"
)

func TestGlobalDir(t *testing.T) {
	dir := GlobalDir()
	if !strings.HasSuffix(dir, ".nanobox") {
		t.Errorf("missing nanobox suffix")
	}
}

func TestLocalDir(t *testing.T) {
	dir := LocalDir()
	if !strings.HasSuffix(dir, "nanobox") {
		t.Errorf("missing nanobox suffix")
	}
}

func TestLocalDirName(t *testing.T) {
	if LocalDirName() != "nanobox" {
		t.Errorf("local dir name mismatch")
	}
}

func TestBinDir(t *testing.T) {
	dir := BinDir()
	if !strings.HasSuffix(dir, ".nanobox/bin") {
		t.Errorf("bin dir failure")
	}
}

func TestSSHDir(t *testing.T) {
	homedir, _ := homedir.Dir()
	if SSHDir() != homedir+"/.ssh" {
		t.Errorf("incorrect ssh directory")
	}
}
<commit_msg>fix tests<commit_after>package config

import (
	"github.com/mitchellh/go-homedir"
	"strings"
	"testing"
)

func TestGlobalDir(t *testing.T) {
	dir := GlobalDir()
	if !strings.HasSuffix(dir, ".nanobox") {
		t.Errorf("missing nanobox suffix")
	}
}

func TestLocalDir(t *testing.T) {
	dir := LocalDir()
	if !strings.HasSuffix(dir, "nanobox") {
		t.Errorf("missing nanobox suffix")
	}
}

func TestLocalDirName(t *testing.T) {
	if LocalDirName() != "nanobox" {
		t.Errorf("local dir name mismatch")
	}
}

func TestSSHDir(t *testing.T) {
	homedir, _ := homedir.Dir()
	if SSHDir() != homedir+"/.ssh" {
		t.Errorf("incorrect ssh directory")
	}
}
<|endoftext|>


<commit_before>package ipfs

import (
	"bytes"
	"context"
	"encoding/base64"
	"errors"
	"golang.org/x/net/proxy"
	"io/ioutil"
	"net/http"
	"time"

	"gx/ipfs/QmTbxNB1NwDesLmKTscr4udL2tVP7MaxvXnD1D9yX7g3PN/go-cid"
	peer "gx/ipfs/QmYVXrKrKHDC9FobgmcmshCDyWwdrfwfanNQN4oxJ9Fk3h/go-libp2p-peer"
	routing "gx/ipfs/QmYxUdYY9S6yg5tSPVin5GFTvtfsLauVcr7reHDD3dM8xf/go-libp2p-routing"
	ropts "gx/ipfs/QmYxUdYY9S6yg5tSPVin5GFTvtfsLauVcr7reHDD3dM8xf/go-libp2p-routing/options"
	pstore "gx/ipfs/QmaCTz9RkrU13bm9kMB54f7atgqM4qkjDZpRwRoJiWXEqs/go-libp2p-peerstore"
)

var apiRouterHTTPClient = &http.Client{
	Timeout: time.Second * 30,
}

// ensure APIRouter satisfies the interface
var _ routing.IpfsRouting = &APIRouter{}

// ErrNotStarted is returned if a method is called before the router
// is started using the Start() method.
var ErrNotStarted = errors.New("API router not started")

// APIRouter is a routing.IpfsRouting compliant struct backed by an API. It only
// provides the features offerened by routing.ValueStore and marks the others as
// unsupported.
type APIRouter struct {
	uri     string
	started bool
}

// NewAPIRouter creates a new APIRouter backed by the given URI.
func NewAPIRouter(uri string) APIRouter {
	return APIRouter{uri: uri}
}

func (r APIRouter) Start(proxyDialer proxy.Dialer) {
	if proxyDialer != nil {
		tbTransport := &http.Transport{Dial: proxyDialer.Dial}
		apiRouterHTTPClient.Transport = tbTransport
	}
	r.started = true
}

// Bootstrap is a no-op. We don't need any setup to query the API.
func (r APIRouter) Bootstrap(_ context.Context) error {
	return nil
}

// PutValue writes the given value to the API for the given key
func (r APIRouter) PutValue(ctx context.Context, key string, value []byte, opts ...ropts.Option) error {
	if !r.started {
		return ErrNotStarted
	}
	req, err := http.NewRequest("PUT", r.pathForKey(key), bytes.NewBuffer(value))
	if err != nil {
		return err
	}

	_, err = apiRouterHTTPClient.Do(req)
	return err
}

// GetValue reads the value for the given key
func (r APIRouter) GetValue(ctx context.Context, key string, opts ...ropts.Option) ([]byte, error) {
	if !r.started {
		return nil, ErrNotStarted
	}
	resp, err := apiRouterHTTPClient.Get(r.pathForKey(key))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	return ioutil.ReadAll(resp.Body)
}

// GetValues reads the value for the given key. The API does not return multiple
// values.
func (r APIRouter) GetValues(ctx context.Context, key string, opts ...ropts.Option) ([]byte, error) {
	if !r.started {
		return nil, ErrNotStarted
	}
	return r.GetValue(ctx, key, opts...)
}

// SearchValue returns the value for the given key. It return either an error or
// a closed channel containing one value.
func (r APIRouter) SearchValue(ctx context.Context, key string, opts ...ropts.Option) (<-chan []byte, error) {
	if !r.started {
		return nil, ErrNotStarted
	}
	value, err := r.GetValue(ctx, key, opts...)
	if err != nil {
		return nil, err
	}

	valueCh := make(chan []byte, 1)
	valueCh <- value
	close(valueCh)
	return valueCh, nil
}

// FindPeer is unsupported
func (r APIRouter) FindPeer(_ context.Context, id peer.ID) (pstore.PeerInfo, error) {
	return pstore.PeerInfo{}, routing.ErrNotSupported
}

// FindProvidersAsync is unsupported
func (r APIRouter) FindProvidersAsync(_ context.Context, _ cid.Cid, _ int) <-chan pstore.PeerInfo {
	return nil
}

// Provide is unsupported
func (r APIRouter) Provide(_ context.Context, _ cid.Cid, _ bool) error {
	return routing.ErrNotSupported
}

func (r APIRouter) pathForKey(key string) string {
	return r.uri + "/value/" + base64.URLEncoding.EncodeToString([]byte(key))
}
<commit_msg>BUGFIX: Fix APIRouter.Start() to correctly start router.<commit_after>package ipfs

import (
	"bytes"
	"context"
	"encoding/base64"
	"errors"
	"golang.org/x/net/proxy"
	"io/ioutil"
	"net/http"
	"time"

	"gx/ipfs/QmTbxNB1NwDesLmKTscr4udL2tVP7MaxvXnD1D9yX7g3PN/go-cid"
	peer "gx/ipfs/QmYVXrKrKHDC9FobgmcmshCDyWwdrfwfanNQN4oxJ9Fk3h/go-libp2p-peer"
	routing "gx/ipfs/QmYxUdYY9S6yg5tSPVin5GFTvtfsLauVcr7reHDD3dM8xf/go-libp2p-routing"
	ropts "gx/ipfs/QmYxUdYY9S6yg5tSPVin5GFTvtfsLauVcr7reHDD3dM8xf/go-libp2p-routing/options"
	pstore "gx/ipfs/QmaCTz9RkrU13bm9kMB54f7atgqM4qkjDZpRwRoJiWXEqs/go-libp2p-peerstore"
)

var apiRouterHTTPClient = &http.Client{
	Timeout: time.Second * 30,
}

// ensure APIRouter satisfies the interface
var _ routing.IpfsRouting = &APIRouter{}

// ErrNotStarted is returned if a method is called before the router
// is started using the Start() method.
var ErrNotStarted = errors.New("API router not started")

// APIRouter is a routing.IpfsRouting compliant struct backed by an API. It only
// provides the features offerened by routing.ValueStore and marks the others as
// unsupported.
type APIRouter struct {
	uri     string
	started bool
}

// NewAPIRouter creates a new APIRouter backed by the given URI.
func NewAPIRouter(uri string) APIRouter {
	return APIRouter{uri: uri}
}

func (r *APIRouter) Start(proxyDialer proxy.Dialer) {
	if proxyDialer != nil {
		tbTransport := &http.Transport{Dial: proxyDialer.Dial}
		apiRouterHTTPClient.Transport = tbTransport
	}
	r.started = true
}

// Bootstrap is a no-op. We don't need any setup to query the API.
func (r APIRouter) Bootstrap(_ context.Context) error {
	return nil
}

// PutValue writes the given value to the API for the given key
func (r APIRouter) PutValue(ctx context.Context, key string, value []byte, opts ...ropts.Option) error {
	if !r.started {
		return ErrNotStarted
	}
	req, err := http.NewRequest("PUT", r.pathForKey(key), bytes.NewBuffer(value))
	if err != nil {
		return err
	}

	_, err = apiRouterHTTPClient.Do(req)
	return err
}

// GetValue reads the value for the given key
func (r APIRouter) GetValue(ctx context.Context, key string, opts ...ropts.Option) ([]byte, error) {
	if !r.started {
		return nil, ErrNotStarted
	}
	resp, err := apiRouterHTTPClient.Get(r.pathForKey(key))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	return ioutil.ReadAll(resp.Body)
}

// GetValues reads the value for the given key. The API does not return multiple
// values.
func (r APIRouter) GetValues(ctx context.Context, key string, opts ...ropts.Option) ([]byte, error) {
	if !r.started {
		return nil, ErrNotStarted
	}
	return r.GetValue(ctx, key, opts...)
}

// SearchValue returns the value for the given key. It return either an error or
// a closed channel containing one value.
func (r APIRouter) SearchValue(ctx context.Context, key string, opts ...ropts.Option) (<-chan []byte, error) {
	if !r.started {
		return nil, ErrNotStarted
	}
	value, err := r.GetValue(ctx, key, opts...)
	if err != nil {
		return nil, err
	}

	valueCh := make(chan []byte, 1)
	valueCh <- value
	close(valueCh)
	return valueCh, nil
}

// FindPeer is unsupported
func (r APIRouter) FindPeer(_ context.Context, id peer.ID) (pstore.PeerInfo, error) {
	return pstore.PeerInfo{}, routing.ErrNotSupported
}

// FindProvidersAsync is unsupported
func (r APIRouter) FindProvidersAsync(_ context.Context, _ cid.Cid, _ int) <-chan pstore.PeerInfo {
	return nil
}

// Provide is unsupported
func (r APIRouter) Provide(_ context.Context, _ cid.Cid, _ bool) error {
	return routing.ErrNotSupported
}

func (r APIRouter) pathForKey(key string) string {
	return r.uri + "/value/" + base64.URLEncoding.EncodeToString([]byte(key))
}
<|endoftext|>


<commit_before>package goonix

import (
	"os"
	"syscall"
)

type Disk struct {
}

func (d *Disk) Space(path string) (uint64, error) {

	exists, err := d.Exists(path)
	if err != nil {
		return 0, err
	}
	isDir, err := d.IsDirectory(path)
	if err != nil {
		return 0, err
	}
	if exists && isDir {
		var stat syscall.Statfs_t
		syscall.Statfs(path, &stat)
		// Available blocks * size per block = available space in bytes
		return stat.Bavail * uint64(stat.Bsize), nil
	}
	return uint64(0), nil
}

func (d *Disk) IsDirectory(path string) (bool, error) {
	fi, err := os.Stat(path)
	if err != nil {
		return false, err
	}
	mode := fi.Mode()
	return mode.IsDir(), err
}

func (d *Disk) Exists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err
}
<commit_msg>add write permission checking.<commit_after>package goonix

import (
	"os"
	"syscall"
)

type Disk struct {
}

func (d *Disk) Space(path string) (uint64, error) {

	exists, err := d.Exists(path)
	if err != nil {
		return 0, err
	}
	isDir, err := d.IsDirectory(path)
	if err != nil {
		return 0, err
	}
	if exists && isDir {
		var stat syscall.Statfs_t
		syscall.Statfs(path, &stat)
		// Available blocks * size per block = available space in bytes
		return stat.Bavail * uint64(stat.Bsize), nil
	}
	return uint64(0), nil
}

func (d *Disk) IsDirectory(path string) (bool, error) {
	fi, err := os.Stat(path)
	if err != nil {
		return false, err
	}
	mode := fi.Mode()
	return mode.IsDir(), err
}

// current user
func (d *Disk) HasWritePermission(path string) (bool, error) {
	_, err := d.Exists(path)
	if err != nil {
		return false, err
	}
	return syscall.Access(path, 2) == nil, nil
}

func (d *Disk) NamedUserHasWritePermission(user, path string) (bool, error) {
	// execute namei -l /usr/local
	// get results that should look like this:
	//f: /home/matthew
	//drwxr-xr-x root    root    /
	//drwxr-xr-x root    root    home
	//drwxr-xr-x matthew matthew matthew
	// read last line
	//
	return false, nil
}

// works for paths and files
func (d *Disk) Exists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err
}
<|endoftext|>


<commit_before>package dist

import (
	"bytes"
	"log"
	"encoding/binary"
	"crypto/md5"
	"io"
	"net"
	"errors"
	"strings"
	"strconv"
	"erlang/term"
)

type flagId uint32

const (
	PUBLISHED           = flagId(0x1)
	ATOM_CACHE          = 0x2
	EXTENDED_REFERENCES = 0x4
	DIST_MONITOR        = 0x8
	FUN_TAGS            = 0x10
	DIST_MONITOR_NAME   = 0x20
	HIDDEN_ATOM_CACHE   = 0x40
	NEW_FUN_TAGS        = 0x80
	EXTENDED_PIDS_PORTS = 0x100
	EXPORT_PTR_TAG      = 0x200
	BIT_BINARIES        = 0x400
	NEW_FLOATS          = 0x800
	UNICODE_IO          = 0x1000
	DIST_HDR_ATOM_CACHE = 0x2000
	SMALL_ATOM_TAGS     = 0x4000
)

type nodeFlag flagId

func (nf nodeFlag) toUint32() (flag uint32) {
	flag = uint32(nf)
	return
}

func (nf nodeFlag) isSet(f flagId) (is bool) {
	is = (uint32(nf) & uint32(f)) != 0
	return
}

func toNodeFlag(f ...flagId) (nf nodeFlag) {
	var flags uint32
	for _, v := range f {
		flags |= uint32(v)
	}
	nf = nodeFlag(flags)
	return
}

type nodeState uint8

const (
	HANDSHAKE    nodeState   = iota
	CONNECTED
)

type NodeDesc struct {
	Name   string
	Cookie string
	Hidden bool
	remote *NodeDesc
	state nodeState
	challenge uint32
	flag   nodeFlag
	version uint16
}

func NewNodeDesc(name, cookie string, isHidden bool) (nd *NodeDesc) {
	nd = &NodeDesc{
		Name: name,
		Cookie: cookie,
		Hidden: isHidden,
		remote: nil,
		state: HANDSHAKE,
		flag: toNodeFlag(PUBLISHED, UNICODE_IO, EXTENDED_PIDS_PORTS, EXTENDED_REFERENCES),
		version: 5,
	}
	return nd
}

func (currNd *NodeDesc) ReadMessage(c net.Conn) (err error) {
	rcbuf := new(bytes.Buffer)

	var buf []byte

	for {
		var n int
		rbuf := make([]byte, 1024)
		n, err = c.Read(rbuf)

		if (err != nil) && (n == 0) {
			log.Printf("Stop enode loop (%d): %v", n, err)
			return
		}
		rcbuf.Write(rbuf[:n])
		if n < len(rbuf) {
			break
		}
	}

	buf = rcbuf.Bytes()

	switch currNd.state {
	case HANDSHAKE:
		length := binary.BigEndian.Uint16(buf[0:2])
		msg := buf[2:]
		log.Printf("Read from enode %d: %v", length, msg)

		sendData := func(data []byte) (int, error) {
			reply := make([]byte, len(data)+2)
			binary.BigEndian.PutUint16(reply[0:2], uint16(len(data)))
			copy(reply[2:], data)
			log.Printf("Write to enode: %v", reply)
			return c.Write(reply)
		}

		switch msg[0] {
		case 'n':
			sn := currNd.read_SEND_NAME(msg)
			// Statuses: ok, nok, ok_simultaneous, alive, not_allowed
			sok := currNd.compose_SEND_STATUS(sn, true)
			_, err = sendData(sok)
			if err != nil {
				return
			}

			currNd.challenge = 2112311231 // FIXME

			// Now send challenge
			challenge := currNd.compose_SEND_CHALLENGE(sn)
			sendData(challenge)
			if err != nil {
				return
			}

		case 'r':
			sn := currNd.remote
			ok := currNd.read_SEND_CHALLENGE_REPLY(sn, msg)
			if ok {
				challengeAck := currNd.compose_SEND_CHALLENGE_ACK(sn)
				sendData(challengeAck)
				if err != nil {
					return
				}
			} else {
				err = errors.New("bad handshake")
				return
			}
		}
	case CONNECTED:
		length := binary.BigEndian.Uint32(buf[0:4])
		msg := buf[4:]
		log.Printf("Read from enode %d: %v", length, msg)

		if length == 0 {
			log.Printf("Keepalive")
			return
		}

		switch msg[0] {
		case 'p':
			pos := 1
			log.Printf("BIN TERM: %v", msg[pos:])
			for {
				res, nr := currNd.read_TERM(msg[pos:])
				if nr == 0 {
					break
				}
				pos += nr
				log.Printf("READ TERM (%d): %+v", nr, res)
			}
		}
	}
	return
}

func (nd *NodeDesc) compose_SEND_NAME() (msg []byte) {
	msg = make([]byte, 7+len(nd.Name))
	msg[0] = byte('n')
	binary.BigEndian.PutUint16(msg[1:3], nd.version)
	binary.BigEndian.PutUint32(msg[3:7], nd.flag.toUint32())
	copy(msg[7:], nd.Name)
	return
}

func (currNd *NodeDesc) read_SEND_NAME(msg []byte) (nd *NodeDesc) {
	version := binary.BigEndian.Uint16(msg[1:3])
	flag := nodeFlag(binary.BigEndian.Uint32(msg[3:7]))
	name := string(msg[7:])
	nd = &NodeDesc{
		Name: name,
		version: version,
		flag: flag,
	}
	currNd.remote = nd
	return
}

func (currNd *NodeDesc) compose_SEND_STATUS(nd *NodeDesc, isOk bool) (msg []byte) {
	msg = make([]byte, 3)
	msg[0] = byte('s')
	copy(msg[1:], "ok")
	return
}

func (currNd *NodeDesc) compose_SEND_CHALLENGE(nd *NodeDesc) (msg []byte) {
	msg = make([]byte, 11+len(currNd.Name))
	msg[0] = byte('n')
	binary.BigEndian.PutUint16(msg[1:3], currNd.version)
	binary.BigEndian.PutUint32(msg[3:7], currNd.flag.toUint32())
	binary.BigEndian.PutUint32(msg[7:11], currNd.challenge)
	copy(msg[11:], currNd.Name)
	return
}

func (currNd *NodeDesc) read_SEND_CHALLENGE_REPLY(nd *NodeDesc, msg []byte) (isOk bool) {
	nd.challenge = binary.BigEndian.Uint32(msg[1:5])
	digestB := msg[5:]

	digestA := genDigest(currNd.challenge, currNd.Cookie)
	if bytes.Compare(digestA, digestB) == 0 {
		isOk = true
		currNd.state = CONNECTED
	} else {
		isOk = false
	}
	return
}

func (currNd *NodeDesc) compose_SEND_CHALLENGE_ACK(nd *NodeDesc) (msg []byte) {
	msg = make([]byte, 17)
	msg[0] = byte('a')

	digestB := genDigest(nd.challenge, currNd.Cookie) // FIXME: use his cookie, not mine

	copy(msg[1:], digestB)
	return
}

func genDigest(challenge uint32, cookie string) (sum []byte) {
	h := md5.New()
	s := strings.Join([]string{cookie, strconv.FormatUint(uint64(challenge), 10)}, "")
	io.WriteString(h, s)
	sum = h.Sum(nil)
	return
}

func (nd NodeDesc) Flags() (flags []string) {
	fs := map[flagId]string{
		PUBLISHED           : "PUBLISHED",
		ATOM_CACHE          : "ATOM_CACHE",
		EXTENDED_REFERENCES : "EXTENDED_REFERENCES",
		DIST_MONITOR        : "DIST_MONITOR",
		FUN_TAGS            : "FUN_TAGS",
		DIST_MONITOR_NAME   : "DIST_MONITOR_NAME",
		HIDDEN_ATOM_CACHE   : "HIDDEN_ATOM_CACHE",
		NEW_FUN_TAGS        : "NEW_FUN_TAGS",
		EXTENDED_PIDS_PORTS : "EXTENDED_PIDS_PORTS",
		EXPORT_PTR_TAG      : "EXPORT_PTR_TAG",
		BIT_BINARIES        : "BIT_BINARIES",
		NEW_FLOATS          : "NEW_FLOATS",
		UNICODE_IO          : "UNICODE_IO",
		DIST_HDR_ATOM_CACHE : "DIST_HDR_ATOM_CACHE",
		SMALL_ATOM_TAGS     : "SMALL_ATOM_TAGS",
	}

	for k, v := range fs {
		if nd.flag.isSet(k) {
			flags = append(flags, v)
		}
	}
	return
}

func (currNd *NodeDesc) read_TERM(msg []byte) (t term.Term, n int) {
	t, n = term.Read(msg)
	return
}
<commit_msg>Use random challenge value<commit_after>package dist

import (
	"bytes"
	"math/rand"
	"time"
	"log"
	"encoding/binary"
	"crypto/md5"
	"io"
	"net"
	"errors"
	"strings"
	"strconv"
	"erlang/term"
)

type flagId uint32

const (
	PUBLISHED           = flagId(0x1)
	ATOM_CACHE          = 0x2
	EXTENDED_REFERENCES = 0x4
	DIST_MONITOR        = 0x8
	FUN_TAGS            = 0x10
	DIST_MONITOR_NAME   = 0x20
	HIDDEN_ATOM_CACHE   = 0x40
	NEW_FUN_TAGS        = 0x80
	EXTENDED_PIDS_PORTS = 0x100
	EXPORT_PTR_TAG      = 0x200
	BIT_BINARIES        = 0x400
	NEW_FLOATS          = 0x800
	UNICODE_IO          = 0x1000
	DIST_HDR_ATOM_CACHE = 0x2000
	SMALL_ATOM_TAGS     = 0x4000
)

type nodeFlag flagId

func (nf nodeFlag) toUint32() (flag uint32) {
	flag = uint32(nf)
	return
}

func (nf nodeFlag) isSet(f flagId) (is bool) {
	is = (uint32(nf) & uint32(f)) != 0
	return
}

func toNodeFlag(f ...flagId) (nf nodeFlag) {
	var flags uint32
	for _, v := range f {
		flags |= uint32(v)
	}
	nf = nodeFlag(flags)
	return
}

type nodeState uint8

const (
	HANDSHAKE    nodeState   = iota
	CONNECTED
)

type NodeDesc struct {
	Name   string
	Cookie string
	Hidden bool
	remote *NodeDesc
	state nodeState
	challenge uint32
	flag   nodeFlag
	version uint16
}

func NewNodeDesc(name, cookie string, isHidden bool) (nd *NodeDesc) {
	nd = &NodeDesc{
		Name: name,
		Cookie: cookie,
		Hidden: isHidden,
		remote: nil,
		state: HANDSHAKE,
		flag: toNodeFlag(PUBLISHED, UNICODE_IO, EXTENDED_PIDS_PORTS, EXTENDED_REFERENCES),
		version: 5,
	}
	return nd
}

func (currNd *NodeDesc) ReadMessage(c net.Conn) (err error) {
	rcbuf := new(bytes.Buffer)

	var buf []byte

	for {
		var n int
		rbuf := make([]byte, 1024)
		n, err = c.Read(rbuf)

		if (err != nil) && (n == 0) {
			log.Printf("Stop enode loop (%d): %v", n, err)
			return
		}
		rcbuf.Write(rbuf[:n])
		if n < len(rbuf) {
			break
		}
	}

	buf = rcbuf.Bytes()

	switch currNd.state {
	case HANDSHAKE:
		length := binary.BigEndian.Uint16(buf[0:2])
		msg := buf[2:]
		log.Printf("Read from enode %d: %v", length, msg)

		sendData := func(data []byte) (int, error) {
			reply := make([]byte, len(data)+2)
			binary.BigEndian.PutUint16(reply[0:2], uint16(len(data)))
			copy(reply[2:], data)
			log.Printf("Write to enode: %v", reply)
			return c.Write(reply)
		}

		switch msg[0] {
		case 'n':
			sn := currNd.read_SEND_NAME(msg)
			// Statuses: ok, nok, ok_simultaneous, alive, not_allowed
			sok := currNd.compose_SEND_STATUS(sn, true)
			_, err = sendData(sok)
			if err != nil {
				return
			}

			rand.Seed(time.Now().UTC().UnixNano())
			currNd.challenge = rand.Uint32()

			// Now send challenge
			challenge := currNd.compose_SEND_CHALLENGE(sn)
			sendData(challenge)
			if err != nil {
				return
			}

		case 'r':
			sn := currNd.remote
			ok := currNd.read_SEND_CHALLENGE_REPLY(sn, msg)
			if ok {
				challengeAck := currNd.compose_SEND_CHALLENGE_ACK(sn)
				sendData(challengeAck)
				if err != nil {
					return
				}
			} else {
				err = errors.New("bad handshake")
				return
			}
		}
	case CONNECTED:
		length := binary.BigEndian.Uint32(buf[0:4])
		msg := buf[4:]
		log.Printf("Read from enode %d: %v", length, msg)

		if length == 0 {
			log.Printf("Keepalive")
			return
		}

		switch msg[0] {
		case 'p':
			pos := 1
			log.Printf("BIN TERM: %v", msg[pos:])
			for {
				res, nr := currNd.read_TERM(msg[pos:])
				if nr == 0 {
					break
				}
				pos += nr
				log.Printf("READ TERM (%d): %+v", nr, res)
			}
		}
	}
	return
}

func (nd *NodeDesc) compose_SEND_NAME() (msg []byte) {
	msg = make([]byte, 7+len(nd.Name))
	msg[0] = byte('n')
	binary.BigEndian.PutUint16(msg[1:3], nd.version)
	binary.BigEndian.PutUint32(msg[3:7], nd.flag.toUint32())
	copy(msg[7:], nd.Name)
	return
}

func (currNd *NodeDesc) read_SEND_NAME(msg []byte) (nd *NodeDesc) {
	version := binary.BigEndian.Uint16(msg[1:3])
	flag := nodeFlag(binary.BigEndian.Uint32(msg[3:7]))
	name := string(msg[7:])
	nd = &NodeDesc{
		Name: name,
		version: version,
		flag: flag,
	}
	currNd.remote = nd
	return
}

func (currNd *NodeDesc) compose_SEND_STATUS(nd *NodeDesc, isOk bool) (msg []byte) {
	msg = make([]byte, 3)
	msg[0] = byte('s')
	copy(msg[1:], "ok")
	return
}

func (currNd *NodeDesc) compose_SEND_CHALLENGE(nd *NodeDesc) (msg []byte) {
	msg = make([]byte, 11+len(currNd.Name))
	msg[0] = byte('n')
	binary.BigEndian.PutUint16(msg[1:3], currNd.version)
	binary.BigEndian.PutUint32(msg[3:7], currNd.flag.toUint32())
	binary.BigEndian.PutUint32(msg[7:11], currNd.challenge)
	copy(msg[11:], currNd.Name)
	return
}

func (currNd *NodeDesc) read_SEND_CHALLENGE_REPLY(nd *NodeDesc, msg []byte) (isOk bool) {
	nd.challenge = binary.BigEndian.Uint32(msg[1:5])
	digestB := msg[5:]

	digestA := genDigest(currNd.challenge, currNd.Cookie)
	if bytes.Compare(digestA, digestB) == 0 {
		isOk = true
		currNd.state = CONNECTED
	} else {
		isOk = false
	}
	return
}

func (currNd *NodeDesc) compose_SEND_CHALLENGE_ACK(nd *NodeDesc) (msg []byte) {
	msg = make([]byte, 17)
	msg[0] = byte('a')

	digestB := genDigest(nd.challenge, currNd.Cookie) // FIXME: use his cookie, not mine

	copy(msg[1:], digestB)
	return
}

func genDigest(challenge uint32, cookie string) (sum []byte) {
	h := md5.New()
	s := strings.Join([]string{cookie, strconv.FormatUint(uint64(challenge), 10)}, "")
	io.WriteString(h, s)
	sum = h.Sum(nil)
	return
}

func (nd NodeDesc) Flags() (flags []string) {
	fs := map[flagId]string{
		PUBLISHED           : "PUBLISHED",
		ATOM_CACHE          : "ATOM_CACHE",
		EXTENDED_REFERENCES : "EXTENDED_REFERENCES",
		DIST_MONITOR        : "DIST_MONITOR",
		FUN_TAGS            : "FUN_TAGS",
		DIST_MONITOR_NAME   : "DIST_MONITOR_NAME",
		HIDDEN_ATOM_CACHE   : "HIDDEN_ATOM_CACHE",
		NEW_FUN_TAGS        : "NEW_FUN_TAGS",
		EXTENDED_PIDS_PORTS : "EXTENDED_PIDS_PORTS",
		EXPORT_PTR_TAG      : "EXPORT_PTR_TAG",
		BIT_BINARIES        : "BIT_BINARIES",
		NEW_FLOATS          : "NEW_FLOATS",
		UNICODE_IO          : "UNICODE_IO",
		DIST_HDR_ATOM_CACHE : "DIST_HDR_ATOM_CACHE",
		SMALL_ATOM_TAGS     : "SMALL_ATOM_TAGS",
	}

	for k, v := range fs {
		if nd.flag.isSet(k) {
			flags = append(flags, v)
		}
	}
	return
}

func (currNd *NodeDesc) read_TERM(msg []byte) (t term.Term, n int) {
	t, n = term.Read(msg)
	return
}
<|endoftext|>


<commit_before>package main

import (
    "net/http"
    "github.com/elazarl/goproxy"
    "github.com/elazarl/goproxy/ext/image"
    "fmt"
    "log"
    "flag"
    "io/ioutil"
    "image"
    "golang.org/x/image/draw"
    "code.google.com/p/freetype-go/freetype"
    "code.google.com/p/freetype-go/freetype/truetype"
    "code.google.com/p/freetype-go/freetype/raster"
)

var (
    dpi      = flag.Float64("dpi", 72, "screen resolution in Dots Per Inch")
    fontFile = flag.String("fontfile", "Lato-Regular.ttf", "filename of the ttf font")
    hinting  = flag.String("hinting", "none", "none | full")
    size     = flag.Float64("size", 12, "font size in points")
    verbose  = flag.Bool("verbose", false, "proxy verbose mode, boolean")
    port     = flag.String("port", "8080", "proxy port number")
    indent   = flag.Int("indent", 5, "label indentation from the top-left image's corner in pixels")
    fontContext  *freetype.Context
)

func main() {
    flag.Parse()

    font, err := loadFont()
    if err != nil {
        log.Println(err)
        return
    }

    fontContext = createContext(font)
    fontHeight := int(fontContext.PointToFix32(*size)>>8)
    // two points to output the text and its shadow
    ptA := freetype.Pt(*indent + 1, *indent + 1 + fontHeight)
    ptB := freetype.Pt(*indent, *indent + fontHeight)

    proxy := goproxy.NewProxyHttpServer()
    proxy.OnResponse().Do(goproxy_image.HandleImage(func(img image.Image, ctx *goproxy.ProxyCtx) image.Image {
        outImage := image.NewRGBA(img.Bounds())
        draw.Copy(outImage, image.ZP, img, img.Bounds(), nil)
        text := fmt.Sprintf("%dx%d", img.Bounds().Dx(), img.Bounds().Dy())
        fontContext.SetClip(img.Bounds())
        fontContext.SetDst(outImage)

        drawString(image.White, ptA, text)
        drawString(image.Black, ptB, text)

        return outImage
    }))
    proxy.Verbose = *verbose
    log.Fatal(http.ListenAndServe(":" + *port, proxy))
}

func loadFont() (*truetype.Font, error){
    fontBytes, err := ioutil.ReadFile(*fontFile)
    if err != nil {
        log.Println(err)
        return nil, err
    }
    font, err := freetype.ParseFont(fontBytes)
    if err != nil {
        log.Println(err)
        return nil, err
    }
    return font, nil
}

func drawString(src image.Image, position raster.Point, text string){
    fontContext.SetSrc(src)
    _, err := fontContext.DrawString(text, position)
    if err != nil {
        log.Println(err)
    }
}

func createContext(font *truetype.Font) *freetype.Context {
    ctx := freetype.NewContext()
    ctx.SetDPI(*dpi)
    ctx.SetFont(font)
    ctx.SetFontSize(*size)
    switch *hinting {
        default:
        ctx.SetHinting(freetype.NoHinting)
        case "full":
        ctx.SetHinting(freetype.FullHinting)
    }
    return ctx
}<commit_msg>Fix concurrent access to fontContext<commit_after>package main

import (
    "net/http"
    "github.com/elazarl/goproxy"
    "github.com/elazarl/goproxy/ext/image"
    "fmt"
    "log"
    "flag"
    "io/ioutil"
    "image"
    "golang.org/x/image/draw"
    "code.google.com/p/freetype-go/freetype"
    "code.google.com/p/freetype-go/freetype/truetype"
    "code.google.com/p/freetype-go/freetype/raster"
)

var (
    dpi      = flag.Float64("dpi", 72, "screen resolution in Dots Per Inch")
    fontFile = flag.String("fontfile", "Lato-Regular.ttf", "filename of the ttf font")
    hinting  = flag.String("hinting", "none", "none | full")
    size     = flag.Float64("size", 12, "font size in points")
    verbose  = flag.Bool("verbose", false, "proxy verbose mode, boolean")
    port     = flag.String("port", "8080", "proxy port number")
    indent   = flag.Int("indent", 5, "label indentation from the top-left image's corner in pixels")
)

func main() {
    flag.Parse()

    font, err := loadFont()
    if err != nil {
        log.Println(err)
        return
    }

    fontHeight := int(createContext(font).PointToFix32(*size)>>8)
    // two points to output the text and its shadow
    ptA := freetype.Pt(*indent + 1, *indent + 1 + fontHeight)
    ptB := freetype.Pt(*indent, *indent + fontHeight)

    proxy := goproxy.NewProxyHttpServer()
    proxy.OnResponse().Do(goproxy_image.HandleImage(func(img image.Image, ctx *goproxy.ProxyCtx) image.Image {
        outImage := image.NewRGBA(img.Bounds())
        draw.Copy(outImage, image.ZP, img, img.Bounds(), nil)
        text := fmt.Sprintf("%dx%d", img.Bounds().Dx(), img.Bounds().Dy())
        fontContext := createContext(font)
        fontContext.SetClip(img.Bounds())
        fontContext.SetDst(outImage)

        drawString(image.White, fontContext, ptA, text)
        drawString(image.Black, fontContext, ptB, text)

        return outImage
    }))
    proxy.Verbose = *verbose
    log.Fatal(http.ListenAndServe(":" + *port, proxy))
}

func loadFont() (*truetype.Font, error){
    fontBytes, err := ioutil.ReadFile(*fontFile)
    if err != nil {
        log.Println(err)
        return nil, err
    }
    font, err := freetype.ParseFont(fontBytes)
    if err != nil {
        log.Println(err)
        return nil, err
    }
    return font, nil
}

func drawString(src image.Image, fontContext *freetype.Context, position raster.Point, text string){
    fontContext.SetSrc(src)
    _, err := fontContext.DrawString(text, position)
    if err != nil {
        log.Println(err)
    }
}

func createContext(font *truetype.Font) *freetype.Context {
    ctx := freetype.NewContext()
    ctx.SetDPI(*dpi)
    ctx.SetFont(font)
    ctx.SetFontSize(*size)
    switch *hinting {
        default:
        ctx.SetHinting(freetype.NoHinting)
        case "full":
        ctx.SetHinting(freetype.FullHinting)
    }
    return ctx
}<|endoftext|>


<commit_before>package reaper

/*  Note:  This is a *nix only implementation.  */

//  Prefer #include style directives.
import "fmt"
import "os"
import "os/signal"
import "syscall"

//  Handle death of child (SIGCHLD) messages. Pushes the signal onto the
//  notifications channel if there is a waiter.
func sigChildHandler(notifications chan os.Signal) {
	var sigs = make(chan os.Signal, 3)
	signal.Notify(sigs, syscall.SIGCHLD)

	for {
		var sig = <- sigs
		select {
		case notifications <-sig:  /*  published it.  */
		default:
			/*
			 *  Notifications channel full - drop it to the
			 *  floor. This ensures we don't fill up the SIGCHLD
			 *  queue. The reaper just waits for any child
			 *  process (pid=-1), so we ain't loosing it!! ;^)
			 */
		}
	}

}  /*  End of function  sigChildHandler.  */

//  Be a good parent - clean up behind the children.
func reapChildren() {
	var notifications = make(chan os.Signal, 1)

	go sigChildHandler(notifications)

	for {
		var sig = <-notifications
		fmt.Printf(" - Received signal %v\n", sig)
		for {
			var wstatus syscall.WaitStatus

			/*
			 *  Reap 'em, so that zombies don't accumulate.
			 *  Plants vs. Zombies!!
			 */
			pid, err := syscall.Wait4(-1, &wstatus, 0, nil)
			for syscall.EINTR == err {
				pid, err = syscall.Wait4(-1, &wstatus, 0, nil)
			}

			if syscall.ECHILD == err {
				break
			}

			fmt.Printf(" - Grim reaper cleanup: pid=%d, wstatus=%+v\n",
				pid, wstatus)

		}
	}

}  /*   End of function  reapChildren.  */

/*
 *  ======================================================================
 *  Section: Exported functions
 *  ======================================================================
 */

//  Entry point for the reaper code. Start reaping children in the
//  background inside a goroutine.
func Reap() {
	/*
	 *  Only reap processes if we are taking over init's duties aka
	 *  we are running as pid 1 inside a docker container.
	 */
	 if 1 == os.Getpid() {
		 /*
		  *  Ok, we are the grandma of 'em all, so we get to play
		  *  the grim reaper.
		  *  You will be missed, Terry Pratchett!! RIP
		  */
		  go reapChildren()
	 }

}  /*  End of [exported] function  Reap.  */

<commit_msg>Rework lib to add another exported entry point to pass down wait4 specific configuration and also test with bypassing pid 1 checks.<commit_after>package reaper

/*  Note:  This is a *nix only implementation.  */

//  Prefer #include style directives.
import "fmt"
import "os"
import "os/signal"
import "syscall"

type Config struct {
	Pid     int
	Options int
}

//  Handle death of child (SIGCHLD) messages. Pushes the signal onto the
//  notifications channel if there is a waiter.
func sigChildHandler(notifications chan os.Signal) {
	var sigs = make(chan os.Signal, 3)
	signal.Notify(sigs, syscall.SIGCHLD)

	for {
		var sig = <-sigs
		select {
		case notifications <- sig: /*  published it.  */
		default:
			/*
			 *  Notifications channel full - drop it to the
			 *  floor. This ensures we don't fill up the SIGCHLD
			 *  queue. The reaper just waits for any child
			 *  process (pid=-1), so we ain't loosing it!! ;^)
			 */
		}
	}

} /*  End of function  sigChildHandler.  */

//  Be a good parent - clean up behind the children.
func reapChildren(config Config) {
	var notifications = make(chan os.Signal, 1)

	go sigChildHandler(notifications)

	pid := config.Pid
	opts := config.Options

	for {
		var sig = <-notifications
		fmt.Printf(" - Received signal %v\n", sig)
		for {
			var wstatus syscall.WaitStatus

			/*
			 *  Reap 'em, so that zombies don't accumulate.
			 *  Plants vs. Zombies!!
			 */
			pid, err := syscall.Wait4(pid, &wstatus, opts, nil)
			for syscall.EINTR == err {
				pid, err = syscall.Wait4(pid, &wstatus, opts, nil)
			}

			if syscall.ECHILD == err {
				break
			}

			fmt.Printf(" - Grim reaper cleanup: pid=%d, wstatus=%+v\n",
				pid, wstatus)

		}
	}

} /*   End of function  reapChildren.  */

/*
 *  ======================================================================
 *  Section: Exported functions
 *  ======================================================================
 */

//  Normal entry point for the reaper code. Start reaping children in the
//  background inside a goroutine.
func Reap() {
	/*
	 *  Only reap processes if we are taking over init's duties aka
	 *  we are running as pid 1 inside a docker container.
	 */
	if 1 == os.Getpid() {
		config := Config{Pid: -1, Options: 0}

		/*
		 *  Ok, we are the grandma of 'em all, so we get to play
		 *  the grim reaper.
		 *  You will be missed, Terry Pratchett!! RIP
		 */
		go reapChildren(config)
	}

} /*  End of [exported] function  Reap.  */

//  Entry point for invoking the reaper code bypassing pid 1 checks and
//  with a specific configuration. Starts reaping children in the background
//  inside a goroutine.
func Start(config Config) {
	/*
	 *  Start the Reaper with configuration options. This allows you to
	 *  reap processes even if the current pid isn't running as pid 1.
	 *  So ... use with caution!!
	 *
	 *  In most cases, you are better off just using Reap() as that
	 *  checks if we are running as Pid 1.
	 */
	go reapChildren(config)

} /*  End of [exported] function  Start.  */
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"math"
	"path/filepath"
	"regexp"

	"github.com/disintegration/imaging"
)

var width = flag.Int("width", math.MaxInt16, "Output image width")
var height = flag.Int("height", math.MaxInt16, "Output image height")
var output = flag.String("type", "png", "Output image format")

func main() {
	flag.Parse()

	extMatch := regexp.MustCompile(`\.[a-zA-Z0-9]+$`)

	for _, srcArg := range flag.Args() {
		srcFilenames, err := filepath.Glob(srcArg)
		if err != nil {
			log.Printf("Glob error: %s\n", err)
			continue
		}
		for _, srcFilename := range srcFilenames {
			fmt.Printf("Processing [%s]... ", srcFilename)
			src, err := imaging.Open(srcFilename)
			if err != nil {
				log.Printf("error: %s\n", err)
				continue
			}
			dest := imaging.Fit(src, *width, *height, imaging.MitchellNetravali)
			destFilename := extMatch.ReplaceAllString(srcFilename, "") + fmt.Sprintf("-%dx%d.%s", dest.Bounds().Dx(), dest.Bounds().Dy(), *output)
			err = imaging.Save(dest, destFilename)
			if err != nil {
				log.Printf("error: %s\n", err)
				continue
			}
			fmt.Printf("OK; written to %s\n", destFilename)
		}
	}
}
<commit_msg>Added destination flag<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"math"
	"os"
	"path/filepath"
	"regexp"

	"github.com/disintegration/imaging"
)

var width = flag.Int("width", math.MaxInt16, "Output image width")
var height = flag.Int("height", math.MaxInt16, "Output image height")
var output = flag.String("type", "png", "Output image format")
var destination = flag.String("destination", "", "Output image folder")

func main() {
	flag.Parse()

	if len(*destination) > 0 {
		err := os.MkdirAll(*destination, os.ModePerm)
		if err != nil {
			fmt.Printf("Unable to create destination: %s\n", err)
			os.Exit(1)
		}
	}

	extMatch := regexp.MustCompile(`\.[a-zA-Z0-9]+$`)

	filelist := flag.Args()
	if len(filelist) == 0 {
		filelist = []string{"./*.*"}
	}

	for _, srcArg := range filelist {
		srcFilenames, err := filepath.Glob(srcArg)
		if err != nil {
			log.Printf("Glob error: %s\n", err)
			continue
		}
		for _, srcFilename := range srcFilenames {
			fmt.Printf("Processing [%s]... ", srcFilename)
			src, err := imaging.Open(srcFilename)
			if err != nil {
				log.Printf("error: %s\n", err)
				continue
			}
			dest := imaging.Fit(src, *width, *height, imaging.MitchellNetravali)
			destFilename := extMatch.ReplaceAllString(srcFilename, "") + fmt.Sprintf("-%dx%d.%s", dest.Bounds().Dx(), dest.Bounds().Dy(), *output)
			if len(*destination) > 0 {
				_, file := filepath.Split(destFilename)
				destFilename = filepath.Join(*destination, file)
			}
			err = imaging.Save(dest, destFilename)
			if err != nil {
				log.Printf("error: %s\n", err)
				continue
			}
			fmt.Printf("OK; written to %s\n", destFilename)
		}
	}
}
<|endoftext|>


<commit_before>package cart

import (
	"strings"
)

type (

	HandlerRoute func(*Router)

	Method struct {
		Key string
		HandlerCompose
	}
	Router struct {
		engine 		*Engine
		basePath 	string
		Composed	HandlerCompose
		Methods 	[]Method
	}
)

func (r *Router) getMethod(httpMethod string) (HandlerCompose, bool) {
	for _, entry := range r.Methods {
		if entry.Key == httpMethod {
			return entry.HandlerCompose, true
		}
	}
	return nil, false
}

func (r *Router) handle(httpMethod, absolutePath string, handler HandlerCompose) *Router {
	next := r.engine.getRouter(absolutePath)
	sp := strings.Split(absolutePath[0:len(absolutePath)],"/")
	findParent := false
	for i, _ := range sp {
		tempPath :=  strings.Join(sp[0:len(sp)-i],"/")
		if tempPath == ""  {
			tempPath = "/"
		}
		if pr,find := r.engine.findRouter(tempPath); find{
			findParent = true
			parentComposed := pr.Composed
			if httpMethod == "" {
				//middleware
				next.Composed = compose(parentComposed,handler)
			} else {
				//http mothod
				next.Composed = compose(parentComposed)
				method := Method{Key:httpMethod, HandlerCompose:handler}
				next.Methods = append(next.Methods, method)
			}
			break;
		}
	}

	if(!findParent) {
		if httpMethod == "" {
			//middleware
			next.Composed = compose(handler)
		} else {
			//http mothod
			method := Method{Key:httpMethod, HandlerCompose:handler}
			next.Methods = append(next.Methods, method)
		}
	}
	r.engine.addRoute(next)
	return next
}

func (r *Router) Route(relativePath string, handles ...HandlerRoute) *Router {
	absolutePath := joinPaths(r.basePath, relativePath)
	next := r.engine.getRouter(absolutePath)
	for _, handle := range handles {
		handle(next)
	}
	return next
}

func (r *Router) Use(relativePath string, handles ...Handler) *Router {
	absolutePath := joinPaths(r.basePath, relativePath)
	next := r.handle("",absolutePath,makeCompose(handles...))
	return next
}

func (r *Router) ANY(handler Handler) *Router {
	return r.handle("ANY",r.basePath,makeCompose(handler))
}

func (r *Router) Handle(httpMethod string, handler HandlerFinal) *Router {
	tempHandler := func(c *Context,nex Next) {
		handler(c);
	}
	return r.handle(httpMethod,r.basePath,makeCompose(tempHandler))
}

func (r *Router) GET(handler HandlerFinal) *Router {
	return r.Handle("GET",handler)
}

func (r *Router) POST(handler HandlerFinal) *Router {
	return r.Handle("POST",handler)
}

func (r *Router) PUT(handler HandlerFinal) *Router {
	return r.Handle("PUT",handler)
}

func (r *Router) PATCH(handler HandlerFinal) *Router {
	return r.Handle("PATCH",handler)
}

func (r *Router) HEAD(handler HandlerFinal) *Router {
	return r.Handle("HEAD",handler)
}

func (r *Router) OPTIONS(handler HandlerFinal) *Router {
	return r.Handle("OPTIONS",handler)
}

func (r *Router) DELETE(handler HandlerFinal) *Router {
	return r.Handle("DELETE",handler)
}

func (r *Router) CONNECT(handler HandlerFinal) *Router {
	return r.Handle("CONNECT",handler)
}

func (r *Router) TRACE(handler HandlerFinal) *Router {
	return r.Handle("TRACE",handler)
}

<commit_msg>add . GET POST<commit_after>package cart

import (
	"strings"
)

type (

	HandlerRoute func(*Router)

	Method struct {
		Key string
		HandlerCompose
	}
	Router struct {
		engine 		*Engine
		basePath 	string
		Composed	HandlerCompose
		Methods 	[]Method
	}
)

func (r *Router) getMethod(httpMethod string) (HandlerCompose, bool) {
	for _, entry := range r.Methods {
		if entry.Key == httpMethod {
			return entry.HandlerCompose, true
		}
	}
	return nil, false
}

func (r *Router) mixComposed(absolutePath string) HandlerCompose {
	sp := strings.Split(absolutePath,"/")
	for i, _ := range sp {
		//find it's self first ..... last is root path / router
		tempPath := strings.Join(sp[0:len(sp)-i], "/")
		if tempPath == "" {
			tempPath = "/"
		}
		if pr, find := r.engine.findRouter(tempPath); find {
			return pr.Composed
		}
	}
	return nil
}

func (r *Router) use(absolutePath string, handler HandlerCompose) *Router {
	next := r.engine.getRouter(absolutePath)
	if composed := r.mixComposed(absolutePath); composed!=nil {
		next.Composed = compose(composed, handler)
	} else {
		next.Composed = compose(handler)
	}
	r.engine.addRoute(next)
	return next
}

func (r *Router) handle(httpMethod, absolutePath string, handler HandlerCompose) *Router {
	next := r.engine.getRouter(absolutePath)
	if composed := r.mixComposed(absolutePath); composed!=nil {
		next.Composed = compose(composed)
	}
	method := Method{Key:httpMethod, HandlerCompose:handler}
	next.Methods = append(next.Methods, method)
	r.engine.addRoute(next)
	return next
}

func (r *Router) Route(relativePath string, handles ...HandlerRoute) *Router {
	absolutePath := joinPaths(r.basePath, relativePath)
	next := r.engine.getRouter(absolutePath)
	for _, handle := range handles {
		handle(next)
	}
	return next
}

func (r *Router) Use(relativePath string, handles ...Handler) *Router {
	absolutePath := joinPaths(r.basePath, relativePath)
	next := r.use(absolutePath, makeCompose(handles...))
	return next
}

func (r *Router) ANY(handler Handler) *Router {
	return r.handle("ANY",r.basePath,makeCompose(handler))
}

func (r *Router) Handle(httpMethod string, handler HandlerFinal) *Router {
	tempHandler := func(c *Context,nex Next) {
		handler(c);
	}
	return r.handle(httpMethod,r.basePath,makeCompose(tempHandler))
}

func (r *Router) GET(handler HandlerFinal) *Router {
	return r.Handle("GET",handler)
}

func (r *Router) POST(handler HandlerFinal) *Router {
	return r.Handle("POST",handler)
}

func (r *Router) PUT(handler HandlerFinal) *Router {
	return r.Handle("PUT",handler)
}

func (r *Router) PATCH(handler HandlerFinal) *Router {
	return r.Handle("PATCH",handler)
}

func (r *Router) HEAD(handler HandlerFinal) *Router {
	return r.Handle("HEAD",handler)
}

func (r *Router) OPTIONS(handler HandlerFinal) *Router {
	return r.Handle("OPTIONS",handler)
}

func (r *Router) DELETE(handler HandlerFinal) *Router {
	return r.Handle("DELETE",handler)
}

func (r *Router) CONNECT(handler HandlerFinal) *Router {
	return r.Handle("CONNECT",handler)
}

func (r *Router) TRACE(handler HandlerFinal) *Router {
	return r.Handle("TRACE",handler)
}

<|endoftext|>


<commit_before>package overcurrent

import (
	"errors"
	"time"

	. "gopkg.in/check.v1"
)

func (s *OvercurrentSuite) TestSuccess(c *C) {
	cb := NewBreaker(NewBreakerConfig())
	fn := func() error {
		return nil
	}

	c.Assert(cb.Call(fn), Equals, nil)
}

func (s *OvercurrentSuite) TestNaturalError(c *C) {
	err := errors.New("Test error.")

	cb := NewBreaker(NewBreakerConfig())
	fn := func() error {
		return err
	}

	c.Assert(cb.Call(fn), Equals, err)
}

func (s *OvercurrentSuite) TestNaturalErrorTrip(c *C) {
	err := errors.New("Test error.")

	cb := NewBreaker(NewBreakerConfig())
	fn := func() error {
		return err
	}

	for i := 0; i < 5; i++ {
		c.Assert(cb.Call(fn), Equals, err)
	}

	c.Assert(cb.Call(fn), Equals, CircuitOpenError)
}

func (s *OvercurrentSuite) TestTimeout(c *C) {
	cb := NewBreaker(NewBreakerConfig())
	fn := func() error {
		<-time.After(250 * time.Millisecond)
		return nil
	}

	c.Assert(cb.Call(fn), Equals, InvocationTimeoutError)
}

func (s *OvercurrentSuite) TestTimeoutTrip(c *C) {
	cb := NewBreaker(NewBreakerConfig())
	fn := func() error {
		<-time.After(250 * time.Millisecond)
		return nil
	}

	for i := 0; i < 5; i++ {
		c.Assert(cb.Call(fn), Equals, InvocationTimeoutError)
	}

	c.Assert(cb.Call(fn), Equals, CircuitOpenError)
}

func (s *OvercurrentSuite) TestHalfOpenFailure(c *C) {
	cb := NewBreaker(BreakerConfig{
		InvocationTimeout:          DefaultInvocationTimeout,
		ResetTimeout:               250 * time.Millisecond,
		HalfClosedRetryProbability: 1,
		FailureInterpreter:         NewAnyErrorFailureInterpreter(),
		TripCondition:              NewConsecutiveFailureTripCondition(5),
	})

	err := errors.New("Test error.")
	fn1 := func() error { return err }
	fn2 := func() error { return nil }

	for i := 0; i < 5; i++ {
		c.Assert(cb.Call(fn1), Equals, err)
	}

	c.Assert(cb.Call(fn1), Equals, CircuitOpenError)
	<-time.After(250 * time.Millisecond)
	c.Assert(cb.Call(fn1), Equals, err)
	c.Assert(cb.Call(fn2), Equals, CircuitOpenError)
}

func (s *OvercurrentSuite) TestHalfOpenReset(c *C) {
	cb := NewBreaker(BreakerConfig{
		InvocationTimeout:          DefaultInvocationTimeout,
		ResetTimeout:               250 * time.Millisecond,
		HalfClosedRetryProbability: 1,
		FailureInterpreter:         NewAnyErrorFailureInterpreter(),
		TripCondition:              NewConsecutiveFailureTripCondition(5),
	})

	err := errors.New("Test error.")
	fn1 := func() error { return err }
	fn2 := func() error { return nil }

	for i := 0; i < 5; i++ {
		c.Assert(cb.Call(fn1), Equals, err)
	}

	c.Assert(cb.Call(fn1), Equals, CircuitOpenError)
	<-time.After(250 * time.Millisecond)
	c.Assert(cb.Call(fn2), Equals, nil)
}

func (s *OvercurrentSuite) TestHalfOpenProbability(c *C) {
	runs := 5000
	prob := .25
	dist := .01

	success := 0
	failure := 0

	fn1 := func() error { return errors.New("Test error.") }
	fn2 := func() error {
		success++
		return nil
	}

	for i := 0; i < runs; i++ {
		cb := NewBreaker(BreakerConfig{
			InvocationTimeout:          DefaultInvocationTimeout,
			ResetTimeout:               1 * time.Nanosecond,
			HalfClosedRetryProbability: prob,
			FailureInterpreter:         NewAnyErrorFailureInterpreter(),
			TripCondition:              NewConsecutiveFailureTripCondition(1),
		})

		cb.Call(fn1)
		<-time.After(1 * time.Nanosecond)

		if cb.Call(fn2) == CircuitOpenError {
			failure++
		}
	}

	lower := int(float64(runs)*prob - float64(runs)*dist)
	upper := int(float64(runs)*prob + float64(runs)*dist)

	c.Assert(success+failure, Equals, runs)
	c.Assert(lower <= success && success <= upper, Equals, true)
}

func (s *OvercurrentSuite) TestHardTrip(c *C) {
	cb := NewBreaker(BreakerConfig{
		InvocationTimeout:          DefaultInvocationTimeout,
		ResetTimeout:               250 * time.Millisecond,
		HalfClosedRetryProbability: 1,
		FailureInterpreter:         NewAnyErrorFailureInterpreter(),
		TripCondition:              NewConsecutiveFailureTripCondition(1),
	})

	fn := func() error {
		return nil
	}

	c.Assert(cb.Call(fn), Equals, nil)
	cb.Trip()

	c.Assert(cb.Call(fn), Equals, CircuitOpenError)
	<-time.After(250 * time.Millisecond)
	c.Assert(cb.Call(fn), Equals, CircuitOpenError)

	cb.Reset()
	c.Assert(cb.Call(fn), Equals, nil)
}

func (s *OvercurrentSuite) TestHardReset(c *C) {
	cb := NewBreaker(NewBreakerConfig())

	err := errors.New("Test error.")
	fn1 := func() error { return err }
	fn2 := func() error { return nil }

	for i := 0; i < 5; i++ {
		c.Assert(cb.Call(fn1), Equals, err)
	}

	c.Assert(cb.Call(fn2), Equals, CircuitOpenError)

	cb.Reset()
	c.Assert(cb.Call(fn2), Equals, nil)
}
<commit_msg>Add test for additional coverage.<commit_after>package overcurrent

import (
	"errors"
	"time"

	. "gopkg.in/check.v1"
)

func (s *OvercurrentSuite) TestSuccess(c *C) {
	cb := NewBreaker(NewBreakerConfig())
	fn := func() error {
		return nil
	}

	c.Assert(cb.Call(fn), Equals, nil)
}

func (s *OvercurrentSuite) TestNaturalError(c *C) {
	err := errors.New("Test error.")

	cb := NewBreaker(NewBreakerConfig())
	fn := func() error {
		return err
	}

	c.Assert(cb.Call(fn), Equals, err)
}

func (s *OvercurrentSuite) TestNaturalErrorTrip(c *C) {
	err := errors.New("Test error.")

	cb := NewBreaker(NewBreakerConfig())
	fn := func() error {
		return err
	}

	for i := 0; i < 5; i++ {
		c.Assert(cb.Call(fn), Equals, err)
	}

	c.Assert(cb.Call(fn), Equals, CircuitOpenError)
}

func (s *OvercurrentSuite) TestTimeout(c *C) {
	cb := NewBreaker(NewBreakerConfig())
	fn := func() error {
		<-time.After(250 * time.Millisecond)
		return nil
	}

	c.Assert(cb.Call(fn), Equals, InvocationTimeoutError)
}

func (s *OvercurrentSuite) TestTimeoutTrip(c *C) {
	cb := NewBreaker(NewBreakerConfig())
	fn := func() error {
		<-time.After(250 * time.Millisecond)
		return nil
	}

	for i := 0; i < 5; i++ {
		c.Assert(cb.Call(fn), Equals, InvocationTimeoutError)
	}

	c.Assert(cb.Call(fn), Equals, CircuitOpenError)
}

func (s *OvercurrentSuite) TimeoutDisabled(c *C) {
	cb := NewBreaker(BreakerConfig{
		InvocationTimeout:          0,
		ResetTimeout:               250 * time.Millisecond,
		HalfClosedRetryProbability: 1,
		FailureInterpreter:         NewAnyErrorFailureInterpreter(),
		TripCondition:              NewConsecutiveFailureTripCondition(5),
	})

	fn := func() error {
		<-time.After(250 * time.Millisecond)
		return nil
	}

	c.Assert(cb.Call(fn), Equals, nil)
}

func (s *OvercurrentSuite) TestHalfOpenFailure(c *C) {
	cb := NewBreaker(BreakerConfig{
		InvocationTimeout:          DefaultInvocationTimeout,
		ResetTimeout:               250 * time.Millisecond,
		HalfClosedRetryProbability: 1,
		FailureInterpreter:         NewAnyErrorFailureInterpreter(),
		TripCondition:              NewConsecutiveFailureTripCondition(5),
	})

	err := errors.New("Test error.")
	fn1 := func() error { return err }
	fn2 := func() error { return nil }

	for i := 0; i < 5; i++ {
		c.Assert(cb.Call(fn1), Equals, err)
	}

	c.Assert(cb.Call(fn1), Equals, CircuitOpenError)
	<-time.After(250 * time.Millisecond)
	c.Assert(cb.Call(fn1), Equals, err)
	c.Assert(cb.Call(fn2), Equals, CircuitOpenError)
}

func (s *OvercurrentSuite) TestHalfOpenReset(c *C) {
	cb := NewBreaker(BreakerConfig{
		InvocationTimeout:          DefaultInvocationTimeout,
		ResetTimeout:               250 * time.Millisecond,
		HalfClosedRetryProbability: 1,
		FailureInterpreter:         NewAnyErrorFailureInterpreter(),
		TripCondition:              NewConsecutiveFailureTripCondition(5),
	})

	err := errors.New("Test error.")
	fn1 := func() error { return err }
	fn2 := func() error { return nil }

	for i := 0; i < 5; i++ {
		c.Assert(cb.Call(fn1), Equals, err)
	}

	c.Assert(cb.Call(fn1), Equals, CircuitOpenError)
	<-time.After(250 * time.Millisecond)
	c.Assert(cb.Call(fn2), Equals, nil)
}

func (s *OvercurrentSuite) TestHalfOpenProbability(c *C) {
	runs := 5000
	prob := .25
	dist := .01

	success := 0
	failure := 0

	fn1 := func() error { return errors.New("Test error.") }
	fn2 := func() error {
		success++
		return nil
	}

	for i := 0; i < runs; i++ {
		cb := NewBreaker(BreakerConfig{
			InvocationTimeout:          DefaultInvocationTimeout,
			ResetTimeout:               1 * time.Nanosecond,
			HalfClosedRetryProbability: prob,
			FailureInterpreter:         NewAnyErrorFailureInterpreter(),
			TripCondition:              NewConsecutiveFailureTripCondition(1),
		})

		cb.Call(fn1)
		<-time.After(1 * time.Nanosecond)

		if cb.Call(fn2) == CircuitOpenError {
			failure++
		}
	}

	lower := int(float64(runs)*prob - float64(runs)*dist)
	upper := int(float64(runs)*prob + float64(runs)*dist)

	c.Assert(success+failure, Equals, runs)
	c.Assert(lower <= success && success <= upper, Equals, true)
}

func (s *OvercurrentSuite) TestHardTrip(c *C) {
	cb := NewBreaker(BreakerConfig{
		InvocationTimeout:          DefaultInvocationTimeout,
		ResetTimeout:               250 * time.Millisecond,
		HalfClosedRetryProbability: 1,
		FailureInterpreter:         NewAnyErrorFailureInterpreter(),
		TripCondition:              NewConsecutiveFailureTripCondition(1),
	})

	fn := func() error {
		return nil
	}

	c.Assert(cb.Call(fn), Equals, nil)
	cb.Trip()

	c.Assert(cb.Call(fn), Equals, CircuitOpenError)
	<-time.After(250 * time.Millisecond)
	c.Assert(cb.Call(fn), Equals, CircuitOpenError)

	cb.Reset()
	c.Assert(cb.Call(fn), Equals, nil)
}

func (s *OvercurrentSuite) TestHardReset(c *C) {
	cb := NewBreaker(NewBreakerConfig())

	err := errors.New("Test error.")
	fn1 := func() error { return err }
	fn2 := func() error { return nil }

	for i := 0; i < 5; i++ {
		c.Assert(cb.Call(fn1), Equals, err)
	}

	c.Assert(cb.Call(fn2), Equals, CircuitOpenError)

	cb.Reset()
	c.Assert(cb.Call(fn2), Equals, nil)
}
<|endoftext|>