<commit_before>package orbitus

import (
	"github.com/bmizerany/assert"
	"testing"
	"time"
)

func TestNewReceiverOrbiter(t *testing.T) {
	orbiter := NewReceiverOrbiter(buffer_size, nil, nil, nil, nil, nil)
	var i uint64 = 4

	// Ensure all the indexes are initialized to zero
	assert.Equal(t, i, orbiter.GetReceiverIndex())
	assert.Equal(t, i-1, orbiter.GetJournalerIndex())
	assert.Equal(t, i-2, orbiter.GetReplicatorIndex())
	assert.Equal(t, i-3, orbiter.GetUnmarshallerIndex())
	assert.Equal(t, i-4, orbiter.GetExecutorIndex())

	// Ensure buffer has been fully allocated
	for i = 0; i < buffer_size; i++ {
		msg := orbiter.GetMessage(i)
		msg.marshalled = []byte(test + string(i))
	}

	for i = 0; i < buffer_size; i++ {
		msg := orbiter.GetMessage(i)
		assert.Equal(t, msg.marshalled, []byte(test+string(i)))
	}
}

func TestReceiverOrbiterReset(t *testing.T) {
	orbiter := NewReceiverOrbiter(buffer_size, nil, nil, nil, nil, nil)
	var i uint64
	testvals := []uint64{1, buffer_size - 1, buffer_size, buffer_size + 1}

	for _, i = range testvals {
		err := orbiter.Reset(i)
		assert.Equal(t, nil, err)

		// Ensure all indexes have been set to the given value
		assert.Equal(t, i, orbiter.GetReceiverIndex())
		assert.Equal(t, i-1, orbiter.GetJournalerIndex())
		assert.Equal(t, i-2, orbiter.GetReplicatorIndex())
		assert.Equal(t, i-3, orbiter.GetUnmarshallerIndex())
		assert.Equal(t, i-4, orbiter.GetExecutorIndex())
	}

	// Ensure orbiter does not reset if running
	orbiter.running = true
	err := orbiter.Reset(buffer_size)
	assert.Equal(t, "Cannot reset a running Orbiter", err.Error())
}

func TestReceiverOrbiterStart(t *testing.T) {
	orbiter := NewReceiverOrbiter(buffer_size, nil, journaler, replicator,
		unmarshaller, executor)
	journalerRan, replicatorRan, unmarshallerRan, executorRan =
		false, false, false, false
	orbiter.Start()

	// Manually insert a new Message
	orbiter.buffer[4] = &Message{
		id:         4,
		marshalled: []byte("This is a test message"),
	}
	orbiter.receiverIndex += 1

	time.Sleep(1 * time.Millisecond)

	assert.Equal(t, true, journalerRan)
	assert.Equal(t, true, replicatorRan)
	assert.Equal(t, true, unmarshallerRan)
	assert.Equal(t, true, executorRan)
}

func TestReceiverOrbiterSetReceiverIndex(t *testing.T) {
	orbiter := NewReceiverOrbiter(buffer_size, nil, nil, nil, nil, nil)
	var err error
	var old uint64

	// Setting to value lower than current index should fail
	old = orbiter.GetReceiverIndex()
	err = orbiter.SetReceiverIndex(orbiter.GetReceiverIndex() - 1)
	assert.Equal(t, "New receiver index cannot be less than current index",
		err.Error())
	assert.Equal(t, old, orbiter.GetReceiverIndex())

	// Setting to same value as current should work (although do nothing really)
	old = orbiter.GetReceiverIndex()
	err = orbiter.SetReceiverIndex(orbiter.GetReceiverIndex())
	assert.Equal(t, nil, err)
	assert.Equal(t, old, orbiter.GetReceiverIndex())

	// Basic incrementing by one (where there is room in front) should work.
	old = orbiter.GetReceiverIndex()
	err = orbiter.SetReceiverIndex(old + 1)
	assert.Equal(t, nil, err)
	assert.Equal(t, old+1, orbiter.GetReceiverIndex())

	// Wrapping around should work, even though new modulus of index is lower
	// than the index of the consumer in front of it.
	orbiter.Reset(5)
	assert.Equal(t, uint64(1), orbiter.GetExecutorIndex())
	err = orbiter.SetReceiverIndex(buffer_size)
	assert.Equal(t, nil, err)
	assert.Equal(t, buffer_size, orbiter.GetReceiverIndex())

	// Wrapping around and setting index to the same location as the Business
	// Logic Consumer should not work.
	orbiter.Reset(5)
	assert.Equal(t, uint64(1), orbiter.GetExecutorIndex())
	old = orbiter.GetReceiverIndex()
	err = orbiter.SetReceiverIndex(buffer_size + 1)
	assert.Equal(t, "The Receiver Consumer cannot pass the Business Logic "+
		"Consumer", err.Error())
	assert.Equal(t, old, orbiter.GetReceiverIndex())

	// Wrapping around and passing the Business Logic Consumer should not work.
	orbiter.Reset(5)
	assert.Equal(t, uint64(1), orbiter.GetExecutorIndex())
	old = orbiter.GetReceiverIndex()
	err = orbiter.SetReceiverIndex(buffer_size + (buffer_size / 2))
	assert.Equal(t, "The Receiver Consumer cannot pass the Business Logic "+
		"Consumer", err.Error())
	assert.Equal(t, old, orbiter.GetReceiverIndex())
}

func TestReceiverOrbiterSetJournalerIndex(t *testing.T) {
	orbiter := NewReceiverOrbiter(buffer_size, nil, nil, nil, nil, nil)
	var err error
	var old uint64

	// Setting to value lower than current index should fail
	old = orbiter.GetJournalerIndex()
	err = orbiter.SetJournalerIndex(orbiter.GetJournalerIndex() - 1)
	assert.Equal(t, "New journaler index cannot be less than current index",
		err.Error())
	assert.Equal(t, old, orbiter.GetJournalerIndex())

	// Setting to same value as current should work (although do nothing really)
	old = orbiter.GetJournalerIndex()
	err = orbiter.SetJournalerIndex(orbiter.GetJournalerIndex())
	assert.Equal(t, nil, err)
	assert.Equal(t, old, orbiter.GetJournalerIndex())

	// Basic incrementing by one (where there is room in front) should work.
	orbiter.SetReceiverIndex(orbiter.GetReceiverIndex() + 1)
	old = orbiter.GetJournalerIndex()
	err = orbiter.SetJournalerIndex(old + 1)
	assert.Equal(t, nil, err)
	assert.Equal(t, old+1, orbiter.GetJournalerIndex())

	// Setting index to the same as the Receiver Consumer should not work.
	old = orbiter.GetJournalerIndex()
	err = orbiter.SetJournalerIndex(orbiter.GetReceiverIndex())
	assert.Equal(t, "New journaler index cannot be greater than the current "+
		"receiver index", err.Error())
	assert.Equal(t, old, orbiter.GetJournalerIndex())

	// Passing the Receiver Consumer should not work
	old = orbiter.GetJournalerIndex()
	err = orbiter.SetJournalerIndex(orbiter.GetReceiverIndex() +
		orbiter.GetBufferSize() - 1)
	assert.Equal(t, "New journaler index cannot be greater than the current "+
		"receiver index", err.Error())
	assert.Equal(t, old, orbiter.GetJournalerIndex())
}

func TestReceiverOrbiterSetReplicatorIndex(t *testing.T) {
	orbiter := NewReceiverOrbiter(buffer_size, nil, nil, nil, nil, nil)
	var err error
	var old uint64

	// Setting to value lower than current index should fail
	old = orbiter.GetReplicatorIndex()
	err = orbiter.SetReplicatorIndex(old - 1)
	assert.Equal(t, "New replicator index cannot be less than current index",
		err.Error())
	assert.Equal(t, old, orbiter.GetReplicatorIndex())

	// Setting to same value as current should work (although do nothing really)
	old = orbiter.GetReplicatorIndex()
	err = orbiter.SetReplicatorIndex(old)
	assert.Equal(t, nil, err)
	assert.Equal(t, old, orbiter.GetReplicatorIndex())

	// Basic incrementing by one (where there is room in front) should work.
	orbiter.SetReceiverIndex(orbiter.GetReceiverIndex() + 1)
	orbiter.SetJournalerIndex(orbiter.GetJournalerIndex() + 1)
	old = orbiter.GetReplicatorIndex()
	err = orbiter.SetReplicatorIndex(old + 1)
	assert.Equal(t, nil, err)
	assert.Equal(t, old+1, orbiter.GetReplicatorIndex())

	// Setting index to the same as the Journaler Consumer should not work.
	old = orbiter.GetReplicatorIndex()
	err = orbiter.SetReplicatorIndex(orbiter.GetJournalerIndex())
	assert.Equal(t, "New replicator index cannot be greater than the current "+
		"journaler index", err.Error())
	assert.Equal(t, old, orbiter.GetReplicatorIndex())

	// Passing the Journaler Consumer should not work
	old = orbiter.GetReplicatorIndex()
	err = orbiter.SetReplicatorIndex(orbiter.GetJournalerIndex() +
		orbiter.GetBufferSize() - 1)
	assert.Equal(t, "New replicator index cannot be greater than the current "+
		"journaler index", err.Error())
	assert.Equal(t, old, orbiter.GetReplicatorIndex())
}

func TestReceiverOrbiterSetUnmarshallerIndex(t *testing.T) {
	orbiter := NewReceiverOrbiter(buffer_size, nil, nil, nil, nil, nil)
	var err error
	var old uint64

	// Setting to value lower than current index should fail
	old = orbiter.GetUnmarshallerIndex()
	err = orbiter.SetUnmarshallerIndex(old - 1)
	assert.Equal(t, "New unmarshaller index cannot be less than current index",
		err.Error())
	assert.Equal(t, old, orbiter.GetUnmarshallerIndex())

	// Setting to same value as current should work (although do nothing really)
	old = orbiter.GetUnmarshallerIndex()
	err = orbiter.SetUnmarshallerIndex(old)
	assert.Equal(t, nil, err)
	assert.Equal(t, old, orbiter.GetUnmarshallerIndex())

	// Basic incrementing by one (where there is room in front) should work.
	orbiter.SetReceiverIndex(orbiter.GetReceiverIndex() + 1)
	orbiter.SetJournalerIndex(orbiter.GetJournalerIndex() + 1)
	orbiter.SetReplicatorIndex(orbiter.GetReplicatorIndex() + 1)
	old = orbiter.GetUnmarshallerIndex()
	err = orbiter.SetUnmarshallerIndex(old + 1)
	assert.Equal(t, nil, err)
	assert.Equal(t, old+1, orbiter.GetUnmarshallerIndex())

	// Setting index to the same as the Replicator Consumer should not work.
	old = orbiter.GetUnmarshallerIndex()
	err = orbiter.SetUnmarshallerIndex(orbiter.GetReplicatorIndex())
	assert.Equal(t, "New unmarshaller index cannot be greater than the current "+
		"replicator index", err.Error())
	assert.Equal(t, old, orbiter.GetUnmarshallerIndex())

	// Passing the Replicator Consumer should not work
	old = orbiter.GetUnmarshallerIndex()
	err = orbiter.SetUnmarshallerIndex(orbiter.GetReplicatorIndex() +
		orbiter.GetBufferSize() - 1)
	assert.Equal(t, "New unmarshaller index cannot be greater than the current "+
		"replicator index", err.Error())
	assert.Equal(t, old, orbiter.GetUnmarshallerIndex())
}
<commit_msg>Added SetExecutorIndex tests<commit_after>package orbitus

import (
	"github.com/bmizerany/assert"
	"testing"
	"time"
)

func TestNewReceiverOrbiter(t *testing.T) {
	orbiter := NewReceiverOrbiter(buffer_size, nil, nil, nil, nil, nil)
	var i uint64 = 4

	// Ensure all the indexes are initialized to zero
	assert.Equal(t, i, orbiter.GetReceiverIndex())
	assert.Equal(t, i-1, orbiter.GetJournalerIndex())
	assert.Equal(t, i-2, orbiter.GetReplicatorIndex())
	assert.Equal(t, i-3, orbiter.GetUnmarshallerIndex())
	assert.Equal(t, i-4, orbiter.GetExecutorIndex())

	// Ensure buffer has been fully allocated
	for i = 0; i < buffer_size; i++ {
		msg := orbiter.GetMessage(i)
		msg.marshalled = []byte(test + string(i))
	}

	for i = 0; i < buffer_size; i++ {
		msg := orbiter.GetMessage(i)
		assert.Equal(t, msg.marshalled, []byte(test+string(i)))
	}
}

func TestReceiverOrbiterReset(t *testing.T) {
	orbiter := NewReceiverOrbiter(buffer_size, nil, nil, nil, nil, nil)
	var i uint64
	testvals := []uint64{1, buffer_size - 1, buffer_size, buffer_size + 1}

	for _, i = range testvals {
		err := orbiter.Reset(i)
		assert.Equal(t, nil, err)

		// Ensure all indexes have been set to the given value
		assert.Equal(t, i, orbiter.GetReceiverIndex())
		assert.Equal(t, i-1, orbiter.GetJournalerIndex())
		assert.Equal(t, i-2, orbiter.GetReplicatorIndex())
		assert.Equal(t, i-3, orbiter.GetUnmarshallerIndex())
		assert.Equal(t, i-4, orbiter.GetExecutorIndex())
	}

	// Ensure orbiter does not reset if running
	orbiter.running = true
	err := orbiter.Reset(buffer_size)
	assert.Equal(t, "Cannot reset a running Orbiter", err.Error())
}

func TestReceiverOrbiterStart(t *testing.T) {
	orbiter := NewReceiverOrbiter(buffer_size, nil, journaler, replicator,
		unmarshaller, executor)
	journalerRan, replicatorRan, unmarshallerRan, executorRan =
		false, false, false, false
	orbiter.Start()

	// Manually insert a new Message
	orbiter.buffer[4] = &Message{
		id:         4,
		marshalled: []byte("This is a test message"),
	}
	orbiter.receiverIndex += 1

	time.Sleep(1 * time.Millisecond)

	assert.Equal(t, true, journalerRan)
	assert.Equal(t, true, replicatorRan)
	assert.Equal(t, true, unmarshallerRan)
	assert.Equal(t, true, executorRan)
}

func TestReceiverOrbiterSetReceiverIndex(t *testing.T) {
	orbiter := NewReceiverOrbiter(buffer_size, nil, nil, nil, nil, nil)
	var err error
	var old uint64

	// Setting to value lower than current index should fail
	old = orbiter.GetReceiverIndex()
	err = orbiter.SetReceiverIndex(orbiter.GetReceiverIndex() - 1)
	assert.Equal(t, "New receiver index cannot be less than current index",
		err.Error())
	assert.Equal(t, old, orbiter.GetReceiverIndex())

	// Setting to same value as current should work (although do nothing really)
	old = orbiter.GetReceiverIndex()
	err = orbiter.SetReceiverIndex(orbiter.GetReceiverIndex())
	assert.Equal(t, nil, err)
	assert.Equal(t, old, orbiter.GetReceiverIndex())

	// Basic incrementing by one (where there is room in front) should work.
	old = orbiter.GetReceiverIndex()
	err = orbiter.SetReceiverIndex(old + 1)
	assert.Equal(t, nil, err)
	assert.Equal(t, old+1, orbiter.GetReceiverIndex())

	// Wrapping around should work, even though new modulus of index is lower
	// than the index of the consumer in front of it.
	orbiter.Reset(5)
	assert.Equal(t, uint64(1), orbiter.GetExecutorIndex())
	err = orbiter.SetReceiverIndex(buffer_size)
	assert.Equal(t, nil, err)
	assert.Equal(t, buffer_size, orbiter.GetReceiverIndex())

	// Wrapping around and setting index to the same location as the Business
	// Logic Consumer should not work.
	orbiter.Reset(5)
	assert.Equal(t, uint64(1), orbiter.GetExecutorIndex())
	old = orbiter.GetReceiverIndex()
	err = orbiter.SetReceiverIndex(buffer_size + 1)
	assert.Equal(t, "The Receiver Consumer cannot pass the Business Logic "+
		"Consumer", err.Error())
	assert.Equal(t, old, orbiter.GetReceiverIndex())

	// Wrapping around and passing the Business Logic Consumer should not work.
	orbiter.Reset(5)
	assert.Equal(t, uint64(1), orbiter.GetExecutorIndex())
	old = orbiter.GetReceiverIndex()
	err = orbiter.SetReceiverIndex(buffer_size + (buffer_size / 2))
	assert.Equal(t, "The Receiver Consumer cannot pass the Business Logic "+
		"Consumer", err.Error())
	assert.Equal(t, old, orbiter.GetReceiverIndex())
}

func TestReceiverOrbiterSetJournalerIndex(t *testing.T) {
	orbiter := NewReceiverOrbiter(buffer_size, nil, nil, nil, nil, nil)
	var err error
	var old uint64

	// Setting to value lower than current index should fail
	old = orbiter.GetJournalerIndex()
	err = orbiter.SetJournalerIndex(orbiter.GetJournalerIndex() - 1)
	assert.Equal(t, "New journaler index cannot be less than current index",
		err.Error())
	assert.Equal(t, old, orbiter.GetJournalerIndex())

	// Setting to same value as current should work (although do nothing really)
	old = orbiter.GetJournalerIndex()
	err = orbiter.SetJournalerIndex(orbiter.GetJournalerIndex())
	assert.Equal(t, nil, err)
	assert.Equal(t, old, orbiter.GetJournalerIndex())

	// Basic incrementing by one (where there is room in front) should work.
	orbiter.SetReceiverIndex(orbiter.GetReceiverIndex() + 1)
	old = orbiter.GetJournalerIndex()
	err = orbiter.SetJournalerIndex(old + 1)
	assert.Equal(t, nil, err)
	assert.Equal(t, old+1, orbiter.GetJournalerIndex())

	// Setting index to the same as the Receiver Consumer should not work.
	old = orbiter.GetJournalerIndex()
	err = orbiter.SetJournalerIndex(orbiter.GetReceiverIndex())
	assert.Equal(t, "New journaler index cannot be greater than the current "+
		"receiver index", err.Error())
	assert.Equal(t, old, orbiter.GetJournalerIndex())

	// Passing the Receiver Consumer should not work
	old = orbiter.GetJournalerIndex()
	err = orbiter.SetJournalerIndex(orbiter.GetReceiverIndex() +
		orbiter.GetBufferSize() - 1)
	assert.Equal(t, "New journaler index cannot be greater than the current "+
		"receiver index", err.Error())
	assert.Equal(t, old, orbiter.GetJournalerIndex())
}

func TestReceiverOrbiterSetReplicatorIndex(t *testing.T) {
	orbiter := NewReceiverOrbiter(buffer_size, nil, nil, nil, nil, nil)
	var err error
	var old uint64

	// Setting to value lower than current index should fail
	old = orbiter.GetReplicatorIndex()
	err = orbiter.SetReplicatorIndex(old - 1)
	assert.Equal(t, "New replicator index cannot be less than current index",
		err.Error())
	assert.Equal(t, old, orbiter.GetReplicatorIndex())

	// Setting to same value as current should work (although do nothing really)
	old = orbiter.GetReplicatorIndex()
	err = orbiter.SetReplicatorIndex(old)
	assert.Equal(t, nil, err)
	assert.Equal(t, old, orbiter.GetReplicatorIndex())

	// Basic incrementing by one (where there is room in front) should work.
	orbiter.SetReceiverIndex(orbiter.GetReceiverIndex() + 1)
	orbiter.SetJournalerIndex(orbiter.GetJournalerIndex() + 1)
	old = orbiter.GetReplicatorIndex()
	err = orbiter.SetReplicatorIndex(old + 1)
	assert.Equal(t, nil, err)
	assert.Equal(t, old+1, orbiter.GetReplicatorIndex())

	// Setting index to the same as the Journaler Consumer should not work.
	old = orbiter.GetReplicatorIndex()
	err = orbiter.SetReplicatorIndex(orbiter.GetJournalerIndex())
	assert.Equal(t, "New replicator index cannot be greater than the current "+
		"journaler index", err.Error())
	assert.Equal(t, old, orbiter.GetReplicatorIndex())

	// Passing the Journaler Consumer should not work
	old = orbiter.GetReplicatorIndex()
	err = orbiter.SetReplicatorIndex(orbiter.GetJournalerIndex() +
		orbiter.GetBufferSize() - 1)
	assert.Equal(t, "New replicator index cannot be greater than the current "+
		"journaler index", err.Error())
	assert.Equal(t, old, orbiter.GetReplicatorIndex())
}

func TestReceiverOrbiterSetUnmarshallerIndex(t *testing.T) {
	orbiter := NewReceiverOrbiter(buffer_size, nil, nil, nil, nil, nil)
	var err error
	var old uint64

	// Setting to value lower than current index should fail
	old = orbiter.GetUnmarshallerIndex()
	err = orbiter.SetUnmarshallerIndex(old - 1)
	assert.Equal(t, "New unmarshaller index cannot be less than current index",
		err.Error())
	assert.Equal(t, old, orbiter.GetUnmarshallerIndex())

	// Setting to same value as current should work (although do nothing really)
	old = orbiter.GetUnmarshallerIndex()
	err = orbiter.SetUnmarshallerIndex(old)
	assert.Equal(t, nil, err)
	assert.Equal(t, old, orbiter.GetUnmarshallerIndex())

	// Basic incrementing by one (where there is room in front) should work.
	orbiter.SetReceiverIndex(orbiter.GetReceiverIndex() + 1)
	orbiter.SetJournalerIndex(orbiter.GetJournalerIndex() + 1)
	orbiter.SetReplicatorIndex(orbiter.GetReplicatorIndex() + 1)
	old = orbiter.GetUnmarshallerIndex()
	err = orbiter.SetUnmarshallerIndex(old + 1)
	assert.Equal(t, nil, err)
	assert.Equal(t, old+1, orbiter.GetUnmarshallerIndex())

	// Setting index to the same as the Replicator Consumer should not work.
	old = orbiter.GetUnmarshallerIndex()
	err = orbiter.SetUnmarshallerIndex(orbiter.GetReplicatorIndex())
	assert.Equal(t, "New unmarshaller index cannot be greater than the current "+
		"replicator index", err.Error())
	assert.Equal(t, old, orbiter.GetUnmarshallerIndex())

	// Passing the Replicator Consumer should not work
	old = orbiter.GetUnmarshallerIndex()
	err = orbiter.SetUnmarshallerIndex(orbiter.GetReplicatorIndex() +
		orbiter.GetBufferSize() - 1)
	assert.Equal(t, "New unmarshaller index cannot be greater than the current "+
		"replicator index", err.Error())
	assert.Equal(t, old, orbiter.GetUnmarshallerIndex())
}

func TestReceiverOrbiterSetExecutorIndex(t *testing.T) {
	orbiter := NewReceiverOrbiter(buffer_size, nil, nil, nil, nil, nil)
	orbiter.Reset(5)
	var err error
	var old uint64

	// Setting to value lower than current index should fail
	old = orbiter.GetExecutorIndex()
	err = orbiter.SetExecutorIndex(old - 1)
	assert.Equal(t, "New executor index cannot be less than current index",
		err.Error())
	assert.Equal(t, old, orbiter.GetExecutorIndex())

	// Setting to same value as current should work (although do nothing really)
	old = orbiter.GetExecutorIndex()
	err = orbiter.SetExecutorIndex(old)
	assert.Equal(t, nil, err)
	assert.Equal(t, old, orbiter.GetExecutorIndex())

	// Basic incrementing by one (where there is room in front) should work.
	orbiter.SetReceiverIndex(orbiter.GetReceiverIndex() + 1)
	orbiter.SetJournalerIndex(orbiter.GetJournalerIndex() + 1)
	orbiter.SetReplicatorIndex(orbiter.GetReplicatorIndex() + 1)
	orbiter.SetUnmarshallerIndex(orbiter.GetUnmarshallerIndex() + 1)
	old = orbiter.GetExecutorIndex()
	err = orbiter.SetExecutorIndex(old + 1)
	assert.Equal(t, nil, err)
	assert.Equal(t, old+1, orbiter.GetExecutorIndex())

	// Setting index to the same as the Unmarshaller Consumer should not work.
	old = orbiter.GetExecutorIndex()
	err = orbiter.SetExecutorIndex(orbiter.GetUnmarshallerIndex())
	assert.Equal(t, "New executor index cannot be greater than the current "+
		"unmarshaller index", err.Error())
	assert.Equal(t, old, orbiter.GetExecutorIndex())

	// Passing the Unmarshaller Consumer should not work
	old = orbiter.GetExecutorIndex()
	err = orbiter.SetExecutorIndex(orbiter.GetUnmarshallerIndex() +
		orbiter.GetBufferSize() - 1)
	assert.Equal(t, "New executor index cannot be greater than the current "+
		"unmarshaller index", err.Error())
	assert.Equal(t, old, orbiter.GetExecutorIndex())
}
<|endoftext|>


<commit_before>package store

import (
	"encoding/json"
	"fmt"
	"io"
	"net"
	"os"
	"path/filepath"
	"sync"
	"time"

	"github.com/hashicorp/raft"
	"github.com/hashicorp/raft-boltdb"
)

const (
	retainSnapshotCount = 2
	raftTimeout         = 10 * time.Second
)

type command struct {
	Op    string `json:"op,omitempty"`
	Key   string `json:"key,omitempty"`
	Value string `json:"value,omitempty"`
}

type Store struct {
	RaftDir  string
	RaftBind string

	mu sync.Mutex
	m  map[string]string // The key-value store for the system.

	raft *raft.Raft // The consensus mechanism
}

func New() *Store {
	return &Store{
		m: make(map[string]string),
	}
}

func (s *Store) Open() error {
	// Setup Raft configuration.
	config := raft.DefaultConfig()

	// Experiment with single-node to start.
	config.EnableSingleNode = true
	config.DisableBootstrapAfterElect = false

	// Setup Raft communication.
	addr, err := net.ResolveTCPAddr("tcp", s.RaftBind)
	if err != nil {
		return err
	}
	transport, err := raft.NewTCPTransport(s.RaftBind, addr, 3, 10*time.Second, os.Stderr)
	if err != nil {
		return err
	}

	// Create peer storage.
	peerStore := raft.NewJSONPeers(filepath.Join(s.RaftDir, "peers.json"), transport)

	// Create the log store and stable store.
	logStore, err := raftboltdb.NewBoltStore(filepath.Join(s.RaftDir, "raft.db"))
	if err != nil {
		return fmt.Errorf("new bolt store: %s", err)
	}

	// Create the snapshot store.
	snapshots, err := raft.NewFileSnapshotStore(s.RaftDir, retainSnapshotCount, os.Stderr)
	if err != nil {
		return fmt.Errorf("file snapshot store: %s", err)
	}

	// Create raft log.
	ra, err := raft.NewRaft(config, (*fsm)(s), logStore, logStore, snapshots, peerStore, transport)
	if err != nil {
		return fmt.Errorf("new raft: %s", err)
	}
	s.raft = ra
	return nil
}

func (s *Store) Get(key string) (string, error) {
	s.mu.Lock()
	defer s.mu.Unlock()
	return s.m[key], nil
}

func (s *Store) Set(key, value string) error {
	if s.raft.State() != raft.Leader {
		return fmt.Errorf("not leader")
	}

	c := &command{
		Op:    "set",
		Key:   key,
		Value: value,
	}
	b, err := json.Marshal(c)
	if err != nil {
		return err
	}

	f := s.raft.Apply(b, raftTimeout)
	if err, ok := f.(error); ok {
		return err
	}

	return nil
}

func (s *Store) Delete(key string) error {
	return nil
}

type fsm Store

func (f *fsm) Apply(l *raft.Log) interface{} {
	var c command
	if err := json.Unmarshal(l.Data, &c); err != nil {
		panic(fmt.Sprintf("failed to unmarshal command: %s", err.Error))
	}
	return nil

	switch c.Op {
	case "set":
		return f.applySet(c.Key, c.Value)
	case "delete":
		return f.applyDelete(c.Key)
	default:
		panic(fmt.Sprintf("unrecognized command op: %s", c.Op))
	}
}

func (f *fsm) Snapshot() (raft.FSMSnapshot, error) {
	return nil, nil
}

func (f *fsm) Restore(rc io.ReadCloser) error {
	return nil
}

func (f *fsm) applySet(key, value string) interface{} {
	f.mu.Lock()
	defer f.mu.Unlock()
	f.m[key] = value
	return nil
}

func (f *fsm) applyDelete(key string) interface{} {
	f.mu.Lock()
	defer f.mu.Unlock()
	delete(f.m, key)
	return nil
}
<commit_msg>Remove rogue return<commit_after>package store

import (
	"encoding/json"
	"fmt"
	"io"
	"net"
	"os"
	"path/filepath"
	"sync"
	"time"

	"github.com/hashicorp/raft"
	"github.com/hashicorp/raft-boltdb"
)

const (
	retainSnapshotCount = 2
	raftTimeout         = 10 * time.Second
)

type command struct {
	Op    string `json:"op,omitempty"`
	Key   string `json:"key,omitempty"`
	Value string `json:"value,omitempty"`
}

type Store struct {
	RaftDir  string
	RaftBind string

	mu sync.Mutex
	m  map[string]string // The key-value store for the system.

	raft *raft.Raft // The consensus mechanism
}

func New() *Store {
	return &Store{
		m: make(map[string]string),
	}
}

func (s *Store) Open() error {
	// Setup Raft configuration.
	config := raft.DefaultConfig()

	// Experiment with single-node to start.
	config.EnableSingleNode = true
	config.DisableBootstrapAfterElect = false

	// Setup Raft communication.
	addr, err := net.ResolveTCPAddr("tcp", s.RaftBind)
	if err != nil {
		return err
	}
	transport, err := raft.NewTCPTransport(s.RaftBind, addr, 3, 10*time.Second, os.Stderr)
	if err != nil {
		return err
	}

	// Create peer storage.
	peerStore := raft.NewJSONPeers(filepath.Join(s.RaftDir, "peers.json"), transport)

	// Create the log store and stable store.
	logStore, err := raftboltdb.NewBoltStore(filepath.Join(s.RaftDir, "raft.db"))
	if err != nil {
		return fmt.Errorf("new bolt store: %s", err)
	}

	// Create the snapshot store.
	snapshots, err := raft.NewFileSnapshotStore(s.RaftDir, retainSnapshotCount, os.Stderr)
	if err != nil {
		return fmt.Errorf("file snapshot store: %s", err)
	}

	// Create raft log.
	ra, err := raft.NewRaft(config, (*fsm)(s), logStore, logStore, snapshots, peerStore, transport)
	if err != nil {
		return fmt.Errorf("new raft: %s", err)
	}
	s.raft = ra
	return nil
}

func (s *Store) Get(key string) (string, error) {
	s.mu.Lock()
	defer s.mu.Unlock()
	return s.m[key], nil
}

func (s *Store) Set(key, value string) error {
	if s.raft.State() != raft.Leader {
		return fmt.Errorf("not leader")
	}

	c := &command{
		Op:    "set",
		Key:   key,
		Value: value,
	}
	b, err := json.Marshal(c)
	if err != nil {
		return err
	}

	f := s.raft.Apply(b, raftTimeout)
	if err, ok := f.(error); ok {
		return err
	}

	return nil
}

func (s *Store) Delete(key string) error {
	return nil
}

type fsm Store

func (f *fsm) Apply(l *raft.Log) interface{} {
	var c command
	if err := json.Unmarshal(l.Data, &c); err != nil {
		panic(fmt.Sprintf("failed to unmarshal command: %s", err.Error()))
	}

	switch c.Op {
	case "set":
		return f.applySet(c.Key, c.Value)
	case "delete":
		return f.applyDelete(c.Key)
	default:
		panic(fmt.Sprintf("unrecognized command op: %s", c.Op))
	}
}

func (f *fsm) Snapshot() (raft.FSMSnapshot, error) {
	return nil, nil
}

func (f *fsm) Restore(rc io.ReadCloser) error {
	return nil
}

func (f *fsm) applySet(key, value string) interface{} {
	f.mu.Lock()
	defer f.mu.Unlock()
	f.m[key] = value
	return nil
}

func (f *fsm) applyDelete(key string) interface{} {
	f.mu.Lock()
	defer f.mu.Unlock()
	delete(f.m, key)
	return nil
}
<|endoftext|>


<commit_before>package stripe_test

import (
	"context"
	"encoding/json"
	"net/http"
	"regexp"
	"runtime"
	"sync"
	"testing"

	assert "github.com/stretchr/testify/require"
	stripe "github.com/stripe/stripe-go"
	. "github.com/stripe/stripe-go/testing"
)

func TestBearerAuth(t *testing.T) {
	c := &stripe.BackendConfiguration{URL: stripe.APIURL}
	key := "apiKey"

	req, err := c.NewRequest("", "", key, "", nil, nil)
	assert.NoError(t, err)

	assert.Equal(t, "Bearer "+key, req.Header.Get("Authorization"))
}

func TestContext(t *testing.T) {
	c := &stripe.BackendConfiguration{URL: stripe.APIURL}
	p := &stripe.Params{Context: context.Background()}

	req, err := c.NewRequest("", "", "", "", nil, p)
	assert.NoError(t, err)

	assert.Equal(t, p.Context, req.Context())
}

func TestContext_Cancel(t *testing.T) {
	c := &stripe.BackendConfiguration{
		HTTPClient: &http.Client{},
		URL:        stripe.APIURL,
	}
	ctx, cancel := context.WithCancel(context.Background())
	p := &stripe.Params{Context: ctx}

	req, err := c.NewRequest("", "", "", "", nil, p)
	assert.NoError(t, err)

	assert.Equal(t, ctx, req.Context())

	// Cancel the context before we even try to start the request. This will
	// cause it to immediately return an error and also avoid any kind of race
	// condition.
	cancel()

	var v interface{}
	err = c.Do(req, &v)

	// Go 1.7 will produce an error message like:
	//
	//     Get https://api.stripe.com/v1/: net/http: request canceled while waiting for connection
	//
	// 1.8 and later produce something like:
	//
	//     Get https://api.stripe.com/v1/: context canceled
	//
	// When we drop support for 1.7 we can remove the first case of this
	// expression.
	assert.Regexp(t, regexp.MustCompile(`(request canceled|context canceled\z)`), err.Error())
}

func TestFormatURLPath(t *testing.T) {
	assert.Equal(t, "/resources/1/subresources/2",
		stripe.FormatURLPath("/resources/%s/subresources/%s", "1", "2"))

	// Tests that each parameter is escaped for use in URLs
	assert.Equal(t, "/resources/%25",
		stripe.FormatURLPath("/resources/%s", "%"))
}

func TestParseID(t *testing.T) {
	// JSON string
	{
		id, ok := stripe.ParseID([]byte(`"ch_123"`))
		assert.Equal(t, "ch_123", id)
		assert.True(t, ok)
	}

	// JSON object
	{
		id, ok := stripe.ParseID([]byte(`{"id":"ch_123"}`))
		assert.Equal(t, "", id)
		assert.False(t, ok)
	}

	// Other JSON scalar (this should never be used, but check the results anyway)
	{
		id, ok := stripe.ParseID([]byte(`123`))
		assert.Equal(t, "", id)
		assert.False(t, ok)
	}
}

// TestMultipleAPICalls will fail the test run if a race condition is thrown while running multiple NewRequest calls.
func TestMultipleAPICalls(t *testing.T) {
	wg := &sync.WaitGroup{}
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			c := &stripe.BackendConfiguration{URL: stripe.APIURL}
			key := "apiKey"

			req, err := c.NewRequest("", "", key, "", nil, nil)
			assert.NoError(t, err)

			assert.Equal(t, "Bearer "+key, req.Header.Get("Authorization"))
		}()
	}
	wg.Wait()
}

func TestIdempotencyKey(t *testing.T) {
	c := &stripe.BackendConfiguration{URL: stripe.APIURL}
	p := &stripe.Params{IdempotencyKey: stripe.String("idempotency-key")}

	req, err := c.NewRequest("", "", "", "", nil, p)
	assert.NoError(t, err)

	assert.Equal(t, "idempotency-key", req.Header.Get("Idempotency-Key"))
}

func TestStripeAccount(t *testing.T) {
	c := &stripe.BackendConfiguration{URL: stripe.APIURL}
	p := &stripe.Params{}
	p.SetStripeAccount(TestMerchantID)

	req, err := c.NewRequest("", "", "", "", nil, p)
	assert.NoError(t, err)

	assert.Equal(t, TestMerchantID, req.Header.Get("Stripe-Account"))
}

func TestUserAgent(t *testing.T) {
	c := &stripe.BackendConfiguration{URL: stripe.APIURL}

	req, err := c.NewRequest("", "", "", "", nil, nil)
	assert.NoError(t, err)

	// We keep out version constant private to the package, so use a regexp
	// match instead.
	expectedPattern := regexp.MustCompile(`^Stripe/v1 GoBindings/[1-9][0-9.]+[0-9]$`)

	match := expectedPattern.MatchString(req.Header.Get("User-Agent"))
	assert.True(t, match)
}

func TestUserAgentWithAppInfo(t *testing.T) {
	appInfo := &stripe.AppInfo{
		Name:      "MyAwesomePlugin",
		PartnerID: "partner_1234",
		URL:       "https://myawesomeplugin.info",
		Version:   "1.2.34",
	}
	stripe.SetAppInfo(appInfo)
	defer stripe.SetAppInfo(nil)

	c := &stripe.BackendConfiguration{URL: stripe.APIURL}

	req, err := c.NewRequest("", "", "", "", nil, nil)
	assert.NoError(t, err)

	//
	// User-Agent
	//

	// We keep out version constant private to the package, so use a regexp
	// match instead.
	expectedPattern := regexp.MustCompile(`^Stripe/v1 GoBindings/[1-9][0-9.]+[0-9] MyAwesomePlugin/1.2.34 \(https://myawesomeplugin.info\)$`)

	match := expectedPattern.MatchString(req.Header.Get("User-Agent"))
	assert.True(t, match)

	//
	// X-Stripe-Client-User-Agent
	//

	encodedUserAgent := req.Header.Get("X-Stripe-Client-User-Agent")
	assert.NotEmpty(t, encodedUserAgent)

	var userAgent map[string]interface{}
	err = json.Unmarshal([]byte(encodedUserAgent), &userAgent)
	assert.NoError(t, err)

	application := userAgent["application"].(map[string]interface{})

	assert.Equal(t, "MyAwesomePlugin", application["name"])
	assert.Equal(t, "https://myawesomeplugin.info", application["url"])
	assert.Equal(t, "1.2.34", application["version"])
	assert.Equal(t, "partner_1234", application["partner_id"])
}

func TestStripeClientUserAgent(t *testing.T) {
	c := &stripe.BackendConfiguration{URL: stripe.APIURL}

	req, err := c.NewRequest("", "", "", "", nil, nil)
	assert.NoError(t, err)

	encodedUserAgent := req.Header.Get("X-Stripe-Client-User-Agent")
	assert.NotEmpty(t, encodedUserAgent)

	var userAgent map[string]string
	err = json.Unmarshal([]byte(encodedUserAgent), &userAgent)
	assert.NoError(t, err)

	//
	// Just test a few headers that we know to be stable.
	//

	assert.Empty(t, userAgent["application"])
	assert.Equal(t, "go", userAgent["lang"])
	assert.Equal(t, runtime.Version(), userAgent["lang_version"])

	// Anywhere these tests are running can reasonable be expected to have a
	// `uname` to run, so do this basic check.
	assert.NotEqual(t, stripe.UnknownPlatform, userAgent["lang_version"])
}

func TestStripeClientUserAgentWithAppInfo(t *testing.T) {
	appInfo := &stripe.AppInfo{
		Name:    "MyAwesomePlugin",
		URL:     "https://myawesomeplugin.info",
		Version: "1.2.34",
	}
	stripe.SetAppInfo(appInfo)
	defer stripe.SetAppInfo(nil)

	c := &stripe.BackendConfiguration{URL: stripe.APIURL}

	req, err := c.NewRequest("", "", "", "", nil, nil)
	assert.NoError(t, err)

	encodedUserAgent := req.Header.Get("X-Stripe-Client-User-Agent")
	assert.NotEmpty(t, encodedUserAgent)

	var userAgent map[string]interface{}
	err = json.Unmarshal([]byte(encodedUserAgent), &userAgent)
	assert.NoError(t, err)

	decodedAppInfo := userAgent["application"].(map[string]interface{})
	assert.Equal(t, appInfo.Name, decodedAppInfo["name"])
	assert.Equal(t, appInfo.URL, decodedAppInfo["url"])
	assert.Equal(t, appInfo.Version, decodedAppInfo["version"])
}

func TestResponseToError(t *testing.T) {
	c := &stripe.BackendConfiguration{URL: stripe.APIURL}

	// A test response that includes a status code and request ID.
	res := &http.Response{
		Header: http.Header{
			"Request-Id": []string{"request-id"},
		},
		StatusCode: 402,
	}

	// An error that contains expected fields which we're going to serialize to
	// JSON and inject into our conversion function.
	expectedErr := &stripe.Error{
		Code:  stripe.ErrorCodeMissing,
		Msg:   "That card was declined",
		Param: "expiry_date",
		Type:  stripe.ErrorTypeCard,
	}
	bytes, err := json.Marshal(expectedErr)
	assert.NoError(t, err)

	// Unpack the error that we just serialized so that we can inject a
	// type-specific field into it ("decline_code"). This will show up in a
	// field on a special stripe.CardError type which is attached to the common
	// stripe.Error.
	var raw map[string]string
	err = json.Unmarshal(bytes, &raw)
	assert.NoError(t, err)

	expectedDeclineCode := "decline-code"
	raw["decline_code"] = expectedDeclineCode
	bytes, err = json.Marshal(raw)
	assert.NoError(t, err)

	// A generic Golang error.
	err = c.ResponseToError(res, wrapError(bytes))

	// An error containing Stripe-specific fields that we cast back from the
	// generic Golang error.
	stripeErr := err.(*stripe.Error)

	assert.Equal(t, expectedErr.Code, stripeErr.Code)
	assert.Equal(t, expectedErr.Msg, stripeErr.Msg)
	assert.Equal(t, expectedErr.Param, stripeErr.Param)
	assert.Equal(t, res.Header.Get("Request-Id"), stripeErr.RequestID)
	assert.Equal(t, res.StatusCode, stripeErr.HTTPStatusCode)
	assert.Equal(t, expectedErr.Type, stripeErr.Type)

	// Just a bogus type coercion to demonstrate how this code might be
	// written. Because we've assigned ErrorTypeCard as the error's type, Err
	// should always come out as a CardError.
	_, ok := stripeErr.Err.(*stripe.InvalidRequestError)
	assert.False(t, ok)

	cardErr, ok := stripeErr.Err.(*stripe.CardError)
	assert.True(t, ok)
	assert.Equal(t, expectedDeclineCode, cardErr.DeclineCode)
}

//
// ---
//

// A simple function that allows us to represent an error response from Stripe
// which comes wrapper in a JSON object with a single field of "error".
func wrapError(serialized []byte) []byte {
	return []byte(`{"error":` + string(serialized) + `}`)
}
<commit_msg>Pedantic reordering: order assertions alphabetically<commit_after>package stripe_test

import (
	"context"
	"encoding/json"
	"net/http"
	"regexp"
	"runtime"
	"sync"
	"testing"

	assert "github.com/stretchr/testify/require"
	stripe "github.com/stripe/stripe-go"
	. "github.com/stripe/stripe-go/testing"
)

func TestBearerAuth(t *testing.T) {
	c := &stripe.BackendConfiguration{URL: stripe.APIURL}
	key := "apiKey"

	req, err := c.NewRequest("", "", key, "", nil, nil)
	assert.NoError(t, err)

	assert.Equal(t, "Bearer "+key, req.Header.Get("Authorization"))
}

func TestContext(t *testing.T) {
	c := &stripe.BackendConfiguration{URL: stripe.APIURL}
	p := &stripe.Params{Context: context.Background()}

	req, err := c.NewRequest("", "", "", "", nil, p)
	assert.NoError(t, err)

	assert.Equal(t, p.Context, req.Context())
}

func TestContext_Cancel(t *testing.T) {
	c := &stripe.BackendConfiguration{
		HTTPClient: &http.Client{},
		URL:        stripe.APIURL,
	}
	ctx, cancel := context.WithCancel(context.Background())
	p := &stripe.Params{Context: ctx}

	req, err := c.NewRequest("", "", "", "", nil, p)
	assert.NoError(t, err)

	assert.Equal(t, ctx, req.Context())

	// Cancel the context before we even try to start the request. This will
	// cause it to immediately return an error and also avoid any kind of race
	// condition.
	cancel()

	var v interface{}
	err = c.Do(req, &v)

	// Go 1.7 will produce an error message like:
	//
	//     Get https://api.stripe.com/v1/: net/http: request canceled while waiting for connection
	//
	// 1.8 and later produce something like:
	//
	//     Get https://api.stripe.com/v1/: context canceled
	//
	// When we drop support for 1.7 we can remove the first case of this
	// expression.
	assert.Regexp(t, regexp.MustCompile(`(request canceled|context canceled\z)`), err.Error())
}

func TestFormatURLPath(t *testing.T) {
	assert.Equal(t, "/resources/1/subresources/2",
		stripe.FormatURLPath("/resources/%s/subresources/%s", "1", "2"))

	// Tests that each parameter is escaped for use in URLs
	assert.Equal(t, "/resources/%25",
		stripe.FormatURLPath("/resources/%s", "%"))
}

func TestParseID(t *testing.T) {
	// JSON string
	{
		id, ok := stripe.ParseID([]byte(`"ch_123"`))
		assert.Equal(t, "ch_123", id)
		assert.True(t, ok)
	}

	// JSON object
	{
		id, ok := stripe.ParseID([]byte(`{"id":"ch_123"}`))
		assert.Equal(t, "", id)
		assert.False(t, ok)
	}

	// Other JSON scalar (this should never be used, but check the results anyway)
	{
		id, ok := stripe.ParseID([]byte(`123`))
		assert.Equal(t, "", id)
		assert.False(t, ok)
	}
}

// TestMultipleAPICalls will fail the test run if a race condition is thrown while running multiple NewRequest calls.
func TestMultipleAPICalls(t *testing.T) {
	wg := &sync.WaitGroup{}
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			c := &stripe.BackendConfiguration{URL: stripe.APIURL}
			key := "apiKey"

			req, err := c.NewRequest("", "", key, "", nil, nil)
			assert.NoError(t, err)

			assert.Equal(t, "Bearer "+key, req.Header.Get("Authorization"))
		}()
	}
	wg.Wait()
}

func TestIdempotencyKey(t *testing.T) {
	c := &stripe.BackendConfiguration{URL: stripe.APIURL}
	p := &stripe.Params{IdempotencyKey: stripe.String("idempotency-key")}

	req, err := c.NewRequest("", "", "", "", nil, p)
	assert.NoError(t, err)

	assert.Equal(t, "idempotency-key", req.Header.Get("Idempotency-Key"))
}

func TestStripeAccount(t *testing.T) {
	c := &stripe.BackendConfiguration{URL: stripe.APIURL}
	p := &stripe.Params{}
	p.SetStripeAccount(TestMerchantID)

	req, err := c.NewRequest("", "", "", "", nil, p)
	assert.NoError(t, err)

	assert.Equal(t, TestMerchantID, req.Header.Get("Stripe-Account"))
}

func TestUserAgent(t *testing.T) {
	c := &stripe.BackendConfiguration{URL: stripe.APIURL}

	req, err := c.NewRequest("", "", "", "", nil, nil)
	assert.NoError(t, err)

	// We keep out version constant private to the package, so use a regexp
	// match instead.
	expectedPattern := regexp.MustCompile(`^Stripe/v1 GoBindings/[1-9][0-9.]+[0-9]$`)

	match := expectedPattern.MatchString(req.Header.Get("User-Agent"))
	assert.True(t, match)
}

func TestUserAgentWithAppInfo(t *testing.T) {
	appInfo := &stripe.AppInfo{
		Name:      "MyAwesomePlugin",
		PartnerID: "partner_1234",
		URL:       "https://myawesomeplugin.info",
		Version:   "1.2.34",
	}
	stripe.SetAppInfo(appInfo)
	defer stripe.SetAppInfo(nil)

	c := &stripe.BackendConfiguration{URL: stripe.APIURL}

	req, err := c.NewRequest("", "", "", "", nil, nil)
	assert.NoError(t, err)

	//
	// User-Agent
	//

	// We keep out version constant private to the package, so use a regexp
	// match instead.
	expectedPattern := regexp.MustCompile(`^Stripe/v1 GoBindings/[1-9][0-9.]+[0-9] MyAwesomePlugin/1.2.34 \(https://myawesomeplugin.info\)$`)

	match := expectedPattern.MatchString(req.Header.Get("User-Agent"))
	assert.True(t, match)

	//
	// X-Stripe-Client-User-Agent
	//

	encodedUserAgent := req.Header.Get("X-Stripe-Client-User-Agent")
	assert.NotEmpty(t, encodedUserAgent)

	var userAgent map[string]interface{}
	err = json.Unmarshal([]byte(encodedUserAgent), &userAgent)
	assert.NoError(t, err)

	application := userAgent["application"].(map[string]interface{})

	assert.Equal(t, "MyAwesomePlugin", application["name"])
	assert.Equal(t, "partner_1234", application["partner_id"])
	assert.Equal(t, "https://myawesomeplugin.info", application["url"])
	assert.Equal(t, "1.2.34", application["version"])
}

func TestStripeClientUserAgent(t *testing.T) {
	c := &stripe.BackendConfiguration{URL: stripe.APIURL}

	req, err := c.NewRequest("", "", "", "", nil, nil)
	assert.NoError(t, err)

	encodedUserAgent := req.Header.Get("X-Stripe-Client-User-Agent")
	assert.NotEmpty(t, encodedUserAgent)

	var userAgent map[string]string
	err = json.Unmarshal([]byte(encodedUserAgent), &userAgent)
	assert.NoError(t, err)

	//
	// Just test a few headers that we know to be stable.
	//

	assert.Empty(t, userAgent["application"])
	assert.Equal(t, "go", userAgent["lang"])
	assert.Equal(t, runtime.Version(), userAgent["lang_version"])

	// Anywhere these tests are running can reasonable be expected to have a
	// `uname` to run, so do this basic check.
	assert.NotEqual(t, stripe.UnknownPlatform, userAgent["lang_version"])
}

func TestStripeClientUserAgentWithAppInfo(t *testing.T) {
	appInfo := &stripe.AppInfo{
		Name:    "MyAwesomePlugin",
		URL:     "https://myawesomeplugin.info",
		Version: "1.2.34",
	}
	stripe.SetAppInfo(appInfo)
	defer stripe.SetAppInfo(nil)

	c := &stripe.BackendConfiguration{URL: stripe.APIURL}

	req, err := c.NewRequest("", "", "", "", nil, nil)
	assert.NoError(t, err)

	encodedUserAgent := req.Header.Get("X-Stripe-Client-User-Agent")
	assert.NotEmpty(t, encodedUserAgent)

	var userAgent map[string]interface{}
	err = json.Unmarshal([]byte(encodedUserAgent), &userAgent)
	assert.NoError(t, err)

	decodedAppInfo := userAgent["application"].(map[string]interface{})
	assert.Equal(t, appInfo.Name, decodedAppInfo["name"])
	assert.Equal(t, appInfo.URL, decodedAppInfo["url"])
	assert.Equal(t, appInfo.Version, decodedAppInfo["version"])
}

func TestResponseToError(t *testing.T) {
	c := &stripe.BackendConfiguration{URL: stripe.APIURL}

	// A test response that includes a status code and request ID.
	res := &http.Response{
		Header: http.Header{
			"Request-Id": []string{"request-id"},
		},
		StatusCode: 402,
	}

	// An error that contains expected fields which we're going to serialize to
	// JSON and inject into our conversion function.
	expectedErr := &stripe.Error{
		Code:  stripe.ErrorCodeMissing,
		Msg:   "That card was declined",
		Param: "expiry_date",
		Type:  stripe.ErrorTypeCard,
	}
	bytes, err := json.Marshal(expectedErr)
	assert.NoError(t, err)

	// Unpack the error that we just serialized so that we can inject a
	// type-specific field into it ("decline_code"). This will show up in a
	// field on a special stripe.CardError type which is attached to the common
	// stripe.Error.
	var raw map[string]string
	err = json.Unmarshal(bytes, &raw)
	assert.NoError(t, err)

	expectedDeclineCode := "decline-code"
	raw["decline_code"] = expectedDeclineCode
	bytes, err = json.Marshal(raw)
	assert.NoError(t, err)

	// A generic Golang error.
	err = c.ResponseToError(res, wrapError(bytes))

	// An error containing Stripe-specific fields that we cast back from the
	// generic Golang error.
	stripeErr := err.(*stripe.Error)

	assert.Equal(t, expectedErr.Code, stripeErr.Code)
	assert.Equal(t, expectedErr.Msg, stripeErr.Msg)
	assert.Equal(t, expectedErr.Param, stripeErr.Param)
	assert.Equal(t, res.Header.Get("Request-Id"), stripeErr.RequestID)
	assert.Equal(t, res.StatusCode, stripeErr.HTTPStatusCode)
	assert.Equal(t, expectedErr.Type, stripeErr.Type)

	// Just a bogus type coercion to demonstrate how this code might be
	// written. Because we've assigned ErrorTypeCard as the error's type, Err
	// should always come out as a CardError.
	_, ok := stripeErr.Err.(*stripe.InvalidRequestError)
	assert.False(t, ok)

	cardErr, ok := stripeErr.Err.(*stripe.CardError)
	assert.True(t, ok)
	assert.Equal(t, expectedDeclineCode, cardErr.DeclineCode)
}

//
// ---
//

// A simple function that allows us to represent an error response from Stripe
// which comes wrapper in a JSON object with a single field of "error".
func wrapError(serialized []byte) []byte {
	return []byte(`{"error":` + string(serialized) + `}`)
}
<|endoftext|>


<commit_before>package gedis

import (
	"strings"
	"testing"
)

func TestReadNumber(t *testing.T) {
	var n int64
	var err error

	a := Asserter{t, 1}

	n, err = ReadNumber(strings.NewReader("1234\r\n"))
	a.Nil(err)
	a.IntegerEq(1234, n)

	n, err = ReadNumber(strings.NewReader("-1234\r\n"))
	a.Nil(err)
	a.IntegerEq(-1234, n)

	_, err = ReadNumber(strings.NewReader("abc\r\n"))
	a.NotNil(err)
	_, err = ReadNumber(strings.NewReader("12ab34\r\n"))
	a.NotNil(err)
}

func BenchmarkReadNumber(b *testing.B) {
	for i := 0; i < b.N; i++ {
		b.StopTimer()
		line := strings.NewReader("1234\r\n")
		b.StartTimer()
		ReadNumber(line)
	}
}

func Test_readLine(t *testing.T) {
	var res string
	var err error

	a := Asserter{t, 1}

	res, err = readLine(strings.NewReader("Lorem ipsum\r\n"))
	a.Nil(err)
	a.StringEq("Lorem ipsum", res)

	res, err = readLine(strings.NewReader("Lorem\ripsum\ndolor\r\n"))
	a.Nil(err)
	a.StringEq("Lorem\ripsum\ndolor", res)

	res, err = readLine(strings.NewReader("Lorem ipsum\r\ndolor sit amet"))

	a.Nil(err)
	a.StringEq("Lorem ipsum", res)
}

func Benchmark_readLine(b *testing.B) {
	for i := 0; i < b.N; i++ {
		b.StopTimer()
		line := strings.NewReader("Lorem ipsum\rdolor sit amet\r\n")
		b.StartTimer()
		readLine(line)
	}
}

func Test_readBulk(t *testing.T) {
	a := Asserter{t, 1}

	res, err := readBulk(strings.NewReader("6\r\nlipsum\r\n"))
	a.Nil(err)
	a.StringEq("lipsum", res)

	res, err = readBulk(strings.NewReader("-1\r\n"))
	a.Nil(err)
	a.Nil(res)

	res, err = readBulk(strings.NewReader("12\r\nlorem\r\nipsum\r\n"))
	a.Nil(err)
	a.StringEq("lorem\r\nipsum", res)

	res, err = readBulk(strings.NewReader("PONG"))
	a.NotNil(err)
	a.Nil(res)

	res, err = readBulk(strings.NewReader("6\r\nlorem\r\n"))
	a.NotNil(err)
	a.Nil(res)

	res, err = readBulk(strings.NewReader("6\r\nlor\r\n"))
	a.NotNil(err)
	a.Nil(res)
}

func Benchmark_readBulk(b *testing.B) {
	for i := 0; i < b.N; i++ {
		b.StopTimer()
		reader := strings.NewReader("12\r\nlorem\r\nipsum\r\n")
		b.StartTimer()
		readBulk(reader)
	}
}

func TestRead_status(t *testing.T) {
	a := Asserter{t, 1}

	res, err := Read(strings.NewReader("+OK\r\n"))
	a.Nil(err)
	a.StringEq("OK", res)
}

func TestRead_error(t *testing.T) {
	a := Asserter{t, 1}

	res, err := Read(strings.NewReader("-ERR unknown\r\n"))
	a.NotNil(err)
	a.Nil(res)
}

func TestRead_integer(t *testing.T) {
	a := Asserter{t, 1}

	res, err := Read(strings.NewReader(":1234\r\n"))
	a.Nil(err)
	a.IntegerEq(1234, res)

	res, err = Read(strings.NewReader(":-1234\r\n"))
	a.Nil(err)
	a.IntegerEq(-1234, res)

	_, err = Read(strings.NewReader(":lorem\r\n"))
	a.NotNil(err)
}

func TestRead_bulk(t *testing.T) {
	var res interface{}
	var err error

	a := Asserter{t, 1}

	res, err = Read(strings.NewReader("$5\r\nlorem\r\n"))
	a.Nil(err)
	a.StringEq("lorem", res)

	res, err = Read(strings.NewReader("$12\r\nlorem\r\nipsum\r\n"))
	a.Nil(err)
	a.StringEq("lorem\r\nipsum", res)

	res, err = Read(strings.NewReader("MUST FAIL"))
	a.NotNil(err)
	a.Nil(res)

	res, err = Read(strings.NewReader("$-1\r\n"))
	a.Nil(err)
	a.Nil(res)
}

func TestRead_multiBulk(t *testing.T) {
	a := Asserter{t, 1}

	input := "*4\r\n$5\r\nlorem\r\n$-1\r\n*2\r\n$5\r\nipsum\r\n$5\r\ndolor\r\n:-1234\r\n"
	reader := strings.NewReader(input)

	res, err := Read(reader)

	a.Nil(err)

	data, ok := res.([]interface{})

	if !ok {
		t.Errorf("Read() can't convert multi-bulk to []interface{}: %#v", res)
		t.FailNow()
	}

	a.StringEq("lorem", data[0])

	a.Nil(data[1])

	if bulks, ok := data[2].([]interface{}); ok {
		a.StringEq("ipsum", bulks[0])
		a.StringEq("dolor", bulks[1])
	} else {
		t.Errorf("can't convert to []interface{}: %#v", data[2])
		t.FailNow()
	}

	a.IntegerEq(-1234, data[3])
}
<commit_msg>Add test for Reading a sequence of replies<commit_after>package gedis

import (
	"strings"
	"testing"
)

func TestReadNumber(t *testing.T) {
	var n int64
	var err error

	a := Asserter{t, 1}

	n, err = ReadNumber(strings.NewReader("1234\r\n"))
	a.Nil(err)
	a.IntegerEq(1234, n)

	n, err = ReadNumber(strings.NewReader("-1234\r\n"))
	a.Nil(err)
	a.IntegerEq(-1234, n)

	_, err = ReadNumber(strings.NewReader("abc\r\n"))
	a.NotNil(err)
	_, err = ReadNumber(strings.NewReader("12ab34\r\n"))
	a.NotNil(err)
}

func BenchmarkReadNumber(b *testing.B) {
	for i := 0; i < b.N; i++ {
		b.StopTimer()
		line := strings.NewReader("1234\r\n")
		b.StartTimer()
		ReadNumber(line)
	}
}

func Test_readLine(t *testing.T) {
	var res string
	var err error

	a := Asserter{t, 1}

	res, err = readLine(strings.NewReader("Lorem ipsum\r\n"))
	a.Nil(err)
	a.StringEq("Lorem ipsum", res)

	res, err = readLine(strings.NewReader("Lorem\ripsum\ndolor\r\n"))
	a.Nil(err)
	a.StringEq("Lorem\ripsum\ndolor", res)

	res, err = readLine(strings.NewReader("Lorem ipsum\r\ndolor sit amet"))

	a.Nil(err)
	a.StringEq("Lorem ipsum", res)
}

func Benchmark_readLine(b *testing.B) {
	for i := 0; i < b.N; i++ {
		b.StopTimer()
		line := strings.NewReader("Lorem ipsum\rdolor sit amet\r\n")
		b.StartTimer()
		readLine(line)
	}
}

func Test_readBulk(t *testing.T) {
	a := Asserter{t, 1}

	res, err := readBulk(strings.NewReader("6\r\nlipsum\r\n"))
	a.Nil(err)
	a.StringEq("lipsum", res)

	res, err = readBulk(strings.NewReader("-1\r\n"))
	a.Nil(err)
	a.Nil(res)

	res, err = readBulk(strings.NewReader("12\r\nlorem\r\nipsum\r\n"))
	a.Nil(err)
	a.StringEq("lorem\r\nipsum", res)

	res, err = readBulk(strings.NewReader("PONG"))
	a.NotNil(err)
	a.Nil(res)

	res, err = readBulk(strings.NewReader("6\r\nlorem\r\n"))
	a.NotNil(err)
	a.Nil(res)

	res, err = readBulk(strings.NewReader("6\r\nlor\r\n"))
	a.NotNil(err)
	a.Nil(res)
}

func Benchmark_readBulk(b *testing.B) {
	for i := 0; i < b.N; i++ {
		b.StopTimer()
		reader := strings.NewReader("12\r\nlorem\r\nipsum\r\n")
		b.StartTimer()
		readBulk(reader)
	}
}

func TestRead_status(t *testing.T) {
	a := Asserter{t, 1}

	res, err := Read(strings.NewReader("+OK\r\n"))
	a.Nil(err)
	a.StringEq("OK", res)
}

func TestRead_error(t *testing.T) {
	a := Asserter{t, 1}

	res, err := Read(strings.NewReader("-ERR unknown\r\n"))
	a.NotNil(err)
	a.Nil(res)
}

func TestRead_integer(t *testing.T) {
	a := Asserter{t, 1}

	res, err := Read(strings.NewReader(":1234\r\n"))
	a.Nil(err)
	a.IntegerEq(1234, res)

	res, err = Read(strings.NewReader(":-1234\r\n"))
	a.Nil(err)
	a.IntegerEq(-1234, res)

	_, err = Read(strings.NewReader(":lorem\r\n"))
	a.NotNil(err)
}

func TestRead_bulk(t *testing.T) {
	var res interface{}
	var err error

	a := Asserter{t, 1}

	res, err = Read(strings.NewReader("$5\r\nlorem\r\n"))
	a.Nil(err)
	a.StringEq("lorem", res)

	res, err = Read(strings.NewReader("$12\r\nlorem\r\nipsum\r\n"))
	a.Nil(err)
	a.StringEq("lorem\r\nipsum", res)

	res, err = Read(strings.NewReader("MUST FAIL"))
	a.NotNil(err)
	a.Nil(res)

	res, err = Read(strings.NewReader("$-1\r\n"))
	a.Nil(err)
	a.Nil(res)
}

func TestRead_multiBulk(t *testing.T) {
	a := Asserter{t, 1}

	input := "*4\r\n$5\r\nlorem\r\n$-1\r\n*2\r\n$5\r\nipsum\r\n$5\r\ndolor\r\n:-1234\r\n"
	reader := strings.NewReader(input)

	res, err := Read(reader)

	a.Nil(err)

	data, ok := res.([]interface{})

	if !ok {
		t.Errorf("Read() can't convert multi-bulk to []interface{}: %#v", res)
		t.FailNow()
	}

	a.StringEq("lorem", data[0])

	a.Nil(data[1])

	if bulks, ok := data[2].([]interface{}); ok {
		a.StringEq("ipsum", bulks[0])
		a.StringEq("dolor", bulks[1])
	} else {
		t.Errorf("can't convert to []interface{}: %#v", data[2])
		t.FailNow()
	}

	a.IntegerEq(-1234, data[3])
}

func TestRead(t *testing.T) {
	a := Asserter{t, 1}

	replies := "+OK\r\n" +
		"-ERR unknown\r\n" +
		":1234\r\n" +
		":-1234\r\n" +
		"$5\r\nlorem\r\n"
	input := replies + "*7\r\n$-1\r\n" + replies + "*1\r\n$2\r\nOK\r\n"
	reader := strings.NewReader(input)

	t.Logf("Using %q as input", input)

	var err error

	status, err := Read(reader)
	a.Nil(err)
	a.StringEq("OK", status)

	rerr, err := Read(reader)
	a.NotNil(err)
	a.Nil(rerr)
	if err.Error() != "ERR unknown" {
		t.Errorf("Unexpected: %q", err)
	}

	n, err := Read(reader)
	a.Nil(err)
	a.IntegerEq(1234, n)

	n, err = Read(reader)
	a.Nil(err)
	a.IntegerEq(-1234, n)

	bulk, err := Read(reader)
	a.Nil(err)
	a.StringEq("lorem", bulk)

	mbulk, err := Read(reader)

	a.Nil(err)

	data, ok := mbulk.([]interface{})

	if !ok {
		t.Errorf("Can't convert to []interface{}: %#v", mbulk)
		t.FailNow()
	}

	a.Nil(data[0])

	a.StringEq("OK", data[1])

	if err, ok = data[2].(error); ok {
		if err.Error() != "ERR unknown" {
			t.Errorf("Unexpected: %q", err)
		}
	} else {
		t.Errorf("Can't convert to error: %#v", data[2])
	}

	a.IntegerEq(1234, data[3])
	a.IntegerEq(-1234, data[4])
	a.StringEq("lorem", data[5])

	if bulks, ok := data[6].([]interface{}); ok {
		a.StringEq("OK", bulks[0])
	} else {
		t.Errorf("Can't convert to []interface{}: %#v", data[6])
	}
}
<|endoftext|>


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

package istiocontrolplane

import (
	"github.com/spf13/cobra"
)

// Options represents the details used to configure the controller.
type Options struct {
	// BaseChartPath is the abosolute path used as the base path when a relative path is specified in
	// IstioOperator.Spec.ChartPath
	BaseChartPath string
	// DefaultChartPath is the relative path used added to BaseChartPath when no value is specified in
	// IstioOperator.Spec.ChartPath
	DefaultChartPath string
}

// ControllerOptions represents the options used by the controller
var controllerOptions = &Options{
	// XXX: update this once we add charts to the operator
	BaseChartPath:    "/etc/istio-operator/helm",
	DefaultChartPath: "istio",
}

// AttachCobraFlags attaches a set of Cobra flags to the given Cobra command.
//
// Cobra is the command-line processor that Istio uses. This command attaches
// the set of flags used to configure the IstioOperator reconciler
func AttachCobraFlags(cmd *cobra.Command) {
	cmd.PersistentFlags().StringVar(&controllerOptions.BaseChartPath, "base-chart-path", "",
		"The absolute path to a directory containing nested charts, e.g. /etc/istio-operator/helm.  "+
			"This will be used as the base path for any IstioOperator instances specifying a relative ChartPath.")
	cmd.PersistentFlags().StringVar(&controllerOptions.BaseChartPath, "default-chart-path", "",
		"A path relative to base-chart-path containing charts to be used when no ChartPath is specified by an IstioOperator resource, e.g. 1.1.0/istio")
}
<commit_msg>fix typo (#21973)<commit_after>// Copyright 2019 Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package istiocontrolplane

import (
	"github.com/spf13/cobra"
)

// Options represents the details used to configure the controller.
type Options struct {
	// BaseChartPath is the absolute path used as the base path when a relative path is specified in
	// IstioOperator.Spec.ChartPath
	BaseChartPath string
	// DefaultChartPath is the relative path used added to BaseChartPath when no value is specified in
	// IstioOperator.Spec.ChartPath
	DefaultChartPath string
}

// ControllerOptions represents the options used by the controller
var controllerOptions = &Options{
	// XXX: update this once we add charts to the operator
	BaseChartPath:    "/etc/istio-operator/helm",
	DefaultChartPath: "istio",
}

// AttachCobraFlags attaches a set of Cobra flags to the given Cobra command.
//
// Cobra is the command-line processor that Istio uses. This command attaches
// the set of flags used to configure the IstioOperator reconciler
func AttachCobraFlags(cmd *cobra.Command) {
	cmd.PersistentFlags().StringVar(&controllerOptions.BaseChartPath, "base-chart-path", "",
		"The absolute path to a directory containing nested charts, e.g. /etc/istio-operator/helm.  "+
			"This will be used as the base path for any IstioOperator instances specifying a relative ChartPath.")
	cmd.PersistentFlags().StringVar(&controllerOptions.BaseChartPath, "default-chart-path", "",
		"A path relative to base-chart-path containing charts to be used when no ChartPath is specified by an IstioOperator resource, e.g. 1.1.0/istio")
}
<|endoftext|>


<commit_before>package basichost

import (
	"net"
	"strconv"
	"sync"

	goprocess "github.com/jbenet/goprocess"
	goprocessctx "github.com/jbenet/goprocess/context"
	inat "github.com/libp2p/go-libp2p-nat"
	inet "github.com/libp2p/go-libp2p-net"
	ma "github.com/multiformats/go-multiaddr"
)

// A simple interface to manage NAT devices.
type NATManager interface {

	// Get the NAT device managed by the NAT manager.
	NAT() *inat.NAT

	// Receive a notification when the NAT device is ready for use.
	Ready() <-chan struct{}

	// Close all resources associated with a NAT manager.
	Close() error
}

// Create a NAT manager.
func NewNATManager(net inet.Network) NATManager {
	return newNatManager(net)
}

// natManager takes care of adding + removing port mappings to the nat.
// Initialized with the host if it has a NATPortMap option enabled.
// natManager receives signals from the network, and check on nat mappings:
//  * natManager listens to the network and adds or closes port mappings
//    as the network signals Listen() or ListenClose().
//  * closing the natManager closes the nat and its mappings.
type natManager struct {
	net   inet.Network
	natmu sync.RWMutex
	nat   *inat.NAT

	ready chan struct{} // closed once the nat is ready to process port mappings

	refreshMu sync.Mutex

	proc goprocess.Process // natManager has a process + children. can be closed.
}

func newNatManager(net inet.Network) *natManager {
	nmgr := &natManager{
		net:   net,
		ready: make(chan struct{}),
	}

	nmgr.proc = goprocess.WithTeardown(func() error {
		// on closing, unregister from network notifications.
		net.StopNotify((*nmgrNetNotifiee)(nmgr))
		return nil
	})

	// discover the nat.
	nmgr.discoverNAT()
	return nmgr
}

// Close closes the natManager, closing the underlying nat
// and unregistering from network events.
func (nmgr *natManager) Close() error {
	return nmgr.proc.Close()
}

// Ready returns a channel which will be closed when the NAT has been found
// and is ready to be used, or the search process is done.
func (nmgr *natManager) Ready() <-chan struct{} {
	return nmgr.ready
}

func (nmgr *natManager) discoverNAT() {
	nmgr.proc.Go(func(worker goprocess.Process) {
		// inat.DiscoverNAT blocks until the nat is found or a timeout
		// is reached. we unfortunately cannot specify timeouts-- the
		// library we're using just blocks.
		//
		// Note: on early shutdown, there may be a case where we're trying
		// to close before DiscoverNAT() returns. Since we cant cancel it
		// (library) we can choose to (1) drop the result and return early,
		// or (2) wait until it times out to exit. For now we choose (2),
		// to avoid leaking resources in a non-obvious way. the only case
		// this affects is when the daemon is being started up and _immediately_
		// asked to close. other services are also starting up, so ok to wait.

		natInstance, err := inat.DiscoverNAT(goprocessctx.OnClosingContext(worker))
		if err != nil {
			log.Error("DiscoverNAT error:", err)
			close(nmgr.ready)
			return
		}

		nmgr.natmu.Lock()
		nmgr.nat = natInstance
		nmgr.natmu.Unlock()
		close(nmgr.ready)

		// wire up the nat to close when nmgr closes.
		// nmgr.proc is our parent, and waiting for us.
		nmgr.proc.AddChild(nmgr.nat.Process())

		// sign natManager up for network notifications
		// we need to sign up here to avoid missing some notifs
		// before the NAT has been found.
		nmgr.net.Notify((*nmgrNetNotifiee)(nmgr))
		nmgr.refresh()
	})
}

func (nmgr *natManager) refresh() {
	nat := nmgr.NAT()
	if nat == nil {
		// Nothing to do.
		return
	}

	nmgr.proc.Go(func(_ goprocess.Process) {
		nmgr.refreshMu.Lock()
		defer nmgr.refreshMu.Unlock()

		ports := map[string]map[int]bool{
			"tcp": map[int]bool{},
			"udp": map[int]bool{},
		}
		for _, maddr := range nmgr.net.ListenAddresses() {
			// Strip the IP
			maIP, rest := ma.SplitFirst(maddr)
			if maIP == nil || rest == nil {
				continue
			}

			switch maIP.Protocol().Code {
			case ma.P_IP6, ma.P_IP4:
			default:
				continue
			}

			// Only bother if we're listening on a
			// unicast/unspecified IP.
			ip := net.IP(maIP.RawValue())
			if !(ip.IsGlobalUnicast() || ip.IsUnspecified()) {
				continue
			}

			// Extract the port/protocol
			proto, _ := ma.SplitFirst(rest)
			if proto == nil {
				continue
			}

			var protocol string
			switch proto.Protocol().Code {
			case ma.P_TCP:
				protocol = "tcp"
			case ma.P_UDP:
				protocol = "udp"
			default:
				continue
			}

			port, err := strconv.ParseUint(proto.Value(), 10, 16)
			if err != nil {
				// bug in multiaddr
				panic(err)
			}
			ports[protocol][int(port)] = false
		}

		var wg sync.WaitGroup
		defer wg.Wait()

		// Close old mappings
		for _, m := range nat.Mappings() {
			mappedPort := m.InternalPort()
			if _, ok := ports[m.Protocol()][mappedPort]; !ok {
				// No longer need this mapping.
				wg.Add(1)
				go func(m inat.Mapping) {
					defer wg.Done()
					m.Close()
				}(m)
			} else {
				// already mapped
				ports[m.Protocol()][mappedPort] = true
			}
		}

		// Create new mappings.
		for proto, pports := range ports {
			for port, mapped := range pports {
				if mapped {
					continue
				}
				wg.Add(1)
				go func(proto string, port int) {
					defer wg.Done()
					_, err := nat.NewMapping(proto, port)
					if err != nil {
						log.Errorf("failed to port-map %s port %d: %s", proto, port, err)
					}
				}(proto, port)
			}
		}
	})
}

// NAT returns the natManager's nat object. this may be nil, if
// (a) the search process is still ongoing, or (b) the search process
// found no nat. Clients must check whether the return value is nil.
func (nmgr *natManager) NAT() *inat.NAT {
	nmgr.natmu.Lock()
	defer nmgr.natmu.Unlock()
	return nmgr.nat
}

type nmgrNetNotifiee natManager

func (nn *nmgrNetNotifiee) natManager() *natManager {
	return (*natManager)(nn)
}

func (nn *nmgrNetNotifiee) Listen(n inet.Network, addr ma.Multiaddr) {
	nn.natManager().refresh()
}

func (nn *nmgrNetNotifiee) ListenClose(n inet.Network, addr ma.Multiaddr) {
	nn.natManager().refresh()
}

func (nn *nmgrNetNotifiee) Connected(inet.Network, inet.Conn)      {}
func (nn *nmgrNetNotifiee) Disconnected(inet.Network, inet.Conn)   {}
func (nn *nmgrNetNotifiee) OpenedStream(inet.Network, inet.Stream) {}
func (nn *nmgrNetNotifiee) ClosedStream(inet.Network, inet.Stream) {}
<commit_msg>natmgr: rename refresh to sync<commit_after>package basichost

import (
	"net"
	"strconv"
	"sync"

	goprocess "github.com/jbenet/goprocess"
	goprocessctx "github.com/jbenet/goprocess/context"
	inat "github.com/libp2p/go-libp2p-nat"
	inet "github.com/libp2p/go-libp2p-net"
	ma "github.com/multiformats/go-multiaddr"
)

// A simple interface to manage NAT devices.
type NATManager interface {

	// Get the NAT device managed by the NAT manager.
	NAT() *inat.NAT

	// Receive a notification when the NAT device is ready for use.
	Ready() <-chan struct{}

	// Close all resources associated with a NAT manager.
	Close() error
}

// Create a NAT manager.
func NewNATManager(net inet.Network) NATManager {
	return newNatManager(net)
}

// natManager takes care of adding + removing port mappings to the nat.
// Initialized with the host if it has a NATPortMap option enabled.
// natManager receives signals from the network, and check on nat mappings:
//  * natManager listens to the network and adds or closes port mappings
//    as the network signals Listen() or ListenClose().
//  * closing the natManager closes the nat and its mappings.
type natManager struct {
	net   inet.Network
	natmu sync.RWMutex
	nat   *inat.NAT

	ready chan struct{} // closed once the nat is ready to process port mappings

	syncMu sync.Mutex

	proc goprocess.Process // natManager has a process + children. can be closed.
}

func newNatManager(net inet.Network) *natManager {
	nmgr := &natManager{
		net:   net,
		ready: make(chan struct{}),
	}

	nmgr.proc = goprocess.WithTeardown(func() error {
		// on closing, unregister from network notifications.
		net.StopNotify((*nmgrNetNotifiee)(nmgr))
		return nil
	})

	// discover the nat.
	nmgr.discoverNAT()
	return nmgr
}

// Close closes the natManager, closing the underlying nat
// and unregistering from network events.
func (nmgr *natManager) Close() error {
	return nmgr.proc.Close()
}

// Ready returns a channel which will be closed when the NAT has been found
// and is ready to be used, or the search process is done.
func (nmgr *natManager) Ready() <-chan struct{} {
	return nmgr.ready
}

func (nmgr *natManager) discoverNAT() {
	nmgr.proc.Go(func(worker goprocess.Process) {
		// inat.DiscoverNAT blocks until the nat is found or a timeout
		// is reached. we unfortunately cannot specify timeouts-- the
		// library we're using just blocks.
		//
		// Note: on early shutdown, there may be a case where we're trying
		// to close before DiscoverNAT() returns. Since we cant cancel it
		// (library) we can choose to (1) drop the result and return early,
		// or (2) wait until it times out to exit. For now we choose (2),
		// to avoid leaking resources in a non-obvious way. the only case
		// this affects is when the daemon is being started up and _immediately_
		// asked to close. other services are also starting up, so ok to wait.

		natInstance, err := inat.DiscoverNAT(goprocessctx.OnClosingContext(worker))
		if err != nil {
			log.Error("DiscoverNAT error:", err)
			close(nmgr.ready)
			return
		}

		nmgr.natmu.Lock()
		nmgr.nat = natInstance
		nmgr.natmu.Unlock()
		close(nmgr.ready)

		// wire up the nat to close when nmgr closes.
		// nmgr.proc is our parent, and waiting for us.
		nmgr.proc.AddChild(nmgr.nat.Process())

		// sign natManager up for network notifications
		// we need to sign up here to avoid missing some notifs
		// before the NAT has been found.
		nmgr.net.Notify((*nmgrNetNotifiee)(nmgr))
		nmgr.sync()
	})
}

// syncs the current NAT mappings, removing any outdated mappings and adding any
// new mappings.
func (nmgr *natManager) sync() {
	nat := nmgr.NAT()
	if nat == nil {
		// Nothing to do.
		return
	}

	nmgr.proc.Go(func(_ goprocess.Process) {
		nmgr.syncMu.Lock()
		defer nmgr.syncMu.Unlock()

		ports := map[string]map[int]bool{
			"tcp": map[int]bool{},
			"udp": map[int]bool{},
		}
		for _, maddr := range nmgr.net.ListenAddresses() {
			// Strip the IP
			maIP, rest := ma.SplitFirst(maddr)
			if maIP == nil || rest == nil {
				continue
			}

			switch maIP.Protocol().Code {
			case ma.P_IP6, ma.P_IP4:
			default:
				continue
			}

			// Only bother if we're listening on a
			// unicast/unspecified IP.
			ip := net.IP(maIP.RawValue())
			if !(ip.IsGlobalUnicast() || ip.IsUnspecified()) {
				continue
			}

			// Extract the port/protocol
			proto, _ := ma.SplitFirst(rest)
			if proto == nil {
				continue
			}

			var protocol string
			switch proto.Protocol().Code {
			case ma.P_TCP:
				protocol = "tcp"
			case ma.P_UDP:
				protocol = "udp"
			default:
				continue
			}

			port, err := strconv.ParseUint(proto.Value(), 10, 16)
			if err != nil {
				// bug in multiaddr
				panic(err)
			}
			ports[protocol][int(port)] = false
		}

		var wg sync.WaitGroup
		defer wg.Wait()

		// Close old mappings
		for _, m := range nat.Mappings() {
			mappedPort := m.InternalPort()
			if _, ok := ports[m.Protocol()][mappedPort]; !ok {
				// No longer need this mapping.
				wg.Add(1)
				go func(m inat.Mapping) {
					defer wg.Done()
					m.Close()
				}(m)
			} else {
				// already mapped
				ports[m.Protocol()][mappedPort] = true
			}
		}

		// Create new mappings.
		for proto, pports := range ports {
			for port, mapped := range pports {
				if mapped {
					continue
				}
				wg.Add(1)
				go func(proto string, port int) {
					defer wg.Done()
					_, err := nat.NewMapping(proto, port)
					if err != nil {
						log.Errorf("failed to port-map %s port %d: %s", proto, port, err)
					}
				}(proto, port)
			}
		}
	})
}

// NAT returns the natManager's nat object. this may be nil, if
// (a) the search process is still ongoing, or (b) the search process
// found no nat. Clients must check whether the return value is nil.
func (nmgr *natManager) NAT() *inat.NAT {
	nmgr.natmu.Lock()
	defer nmgr.natmu.Unlock()
	return nmgr.nat
}

type nmgrNetNotifiee natManager

func (nn *nmgrNetNotifiee) natManager() *natManager {
	return (*natManager)(nn)
}

func (nn *nmgrNetNotifiee) Listen(n inet.Network, addr ma.Multiaddr) {
	nn.natManager().sync()
}

func (nn *nmgrNetNotifiee) ListenClose(n inet.Network, addr ma.Multiaddr) {
	nn.natManager().sync()
}

func (nn *nmgrNetNotifiee) Connected(inet.Network, inet.Conn)      {}
func (nn *nmgrNetNotifiee) Disconnected(inet.Network, inet.Conn)   {}
func (nn *nmgrNetNotifiee) OpenedStream(inet.Network, inet.Stream) {}
func (nn *nmgrNetNotifiee) ClosedStream(inet.Network, inet.Stream) {}
<|endoftext|>


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

package ssa

// Simple block optimizations to simplify the control flow graph.

// TODO(adonovan): opt: instead of creating several "unreachable" blocks
// per function in the Builder, reuse a single one (e.g. at Blocks[1])
// to reduce garbage.

import (
	"fmt"
	"os"
)

// If true, perform sanity checking and show progress at each
// successive iteration of optimizeBlocks.  Very verbose.
const debugBlockOpt = false

// markReachable sets Index=-1 for all blocks reachable from b.
func markReachable(b *BasicBlock) {
	b.Index = -1
	for _, succ := range b.Succs {
		if succ.Index == 0 {
			markReachable(succ)
		}
	}
}

// deleteUnreachableBlocks marks all reachable blocks of f and
// eliminates (nils) all others, including possibly cyclic subgraphs.
//
func deleteUnreachableBlocks(f *Function) {
	const white, black = 0, -1
	// We borrow b.Index temporarily as the mark bit.
	for _, b := range f.Blocks {
		b.Index = white
	}
	markReachable(f.Blocks[0])
	for i, b := range f.Blocks {
		if b.Index == white {
			for _, c := range b.Succs {
				if c.Index == black {
					c.removePred(b) // delete white->black edge
				}
			}
			if debugBlockOpt {
				fmt.Fprintln(os.Stderr, "unreachable", b)
			}
			f.Blocks[i] = nil // delete b
		}
	}
	f.removeNilBlocks()
}

// jumpThreading attempts to apply simple jump-threading to block b,
// in which a->b->c become a->c if b is just a Jump.
// The result is true if the optimization was applied.
//
func jumpThreading(f *Function, b *BasicBlock) bool {
	if b.Index == 0 {
		return false // don't apply to entry block
	}
	if b.Instrs == nil {
		return false
	}
	if _, ok := b.Instrs[0].(*Jump); !ok {
		return false // not just a jump
	}
	c := b.Succs[0]
	if c == b {
		return false // don't apply to degenerate jump-to-self.
	}
	if c.hasPhi() {
		return false // not sound without more effort
	}
	for j, a := range b.Preds {
		a.replaceSucc(b, c)

		// If a now has two edges to c, replace its degenerate If by Jump.
		if len(a.Succs) == 2 && a.Succs[0] == c && a.Succs[1] == c {
			jump := new(Jump)
			jump.setBlock(a)
			a.Instrs[len(a.Instrs)-1] = jump
			a.Succs = a.Succs[:1]
			c.removePred(b)
		} else {
			if j == 0 {
				c.replacePred(b, a)
			} else {
				c.Preds = append(c.Preds, a)
			}
		}

		if debugBlockOpt {
			fmt.Fprintln(os.Stderr, "jumpThreading", a, b, c)
		}
	}
	f.Blocks[b.Index] = nil // delete b
	return true
}

// fuseBlocks attempts to apply the block fusion optimization to block
// a, in which a->b becomes ab if len(a.Succs)==len(b.Preds)==1.
// The result is true if the optimization was applied.
//
func fuseBlocks(f *Function, a *BasicBlock) bool {
	if len(a.Succs) != 1 {
		return false
	}
	b := a.Succs[0]
	if len(b.Preds) != 1 {
		return false
	}
	if _, ok := a.Instrs[len(a.Instrs)-1].(*Panic); ok {
		// panics aren't simple jumps, they have side effects.
		return false
	}

	// Degenerate &&/|| ops may result in a straight-line CFG
	// containing φ-nodes. (Ideally we'd replace such them with
	// their sole operand but that requires Referrers, built later.)
	if b.hasPhi() {
		return false // not sound without further effort
	}

	// Eliminate jump at end of A, then copy all of B across.
	a.Instrs = append(a.Instrs[:len(a.Instrs)-1], b.Instrs...)
	for _, instr := range b.Instrs {
		instr.setBlock(a)
	}

	// A inherits B's successors
	a.Succs = append(a.succs2[:0], b.Succs...)

	// Fix up Preds links of all successors of B.
	for _, c := range b.Succs {
		c.replacePred(b, a)
	}

	if debugBlockOpt {
		fmt.Fprintln(os.Stderr, "fuseBlocks", a, b)
	}

	f.Blocks[b.Index] = nil // delete b
	return true
}

// optimizeBlocks() performs some simple block optimizations on a
// completed function: dead block elimination, block fusion, jump
// threading.
//
func optimizeBlocks(f *Function) {
	deleteUnreachableBlocks(f)

	// Loop until no further progress.
	changed := true
	for changed {
		changed = false

		if debugBlockOpt {
			f.WriteTo(os.Stderr)
			mustSanityCheck(f, nil)
		}

		for _, b := range f.Blocks {
			// f.Blocks will temporarily contain nils to indicate
			// deleted blocks; we remove them at the end.
			if b == nil {
				continue
			}

			// Fuse blocks.  b->c becomes bc.
			if fuseBlocks(f, b) {
				changed = true
			}

			// a->b->c becomes a->c if b contains only a Jump.
			if jumpThreading(f, b) {
				changed = true
				continue // (b was disconnected)
			}
		}
	}
	f.removeNilBlocks()
}
<commit_msg>ssa: don't fuse away the exit block<commit_after>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ssa

// Simple block optimizations to simplify the control flow graph.

// TODO(adonovan): opt: instead of creating several "unreachable" blocks
// per function in the Builder, reuse a single one (e.g. at Blocks[1])
// to reduce garbage.

import (
	"fmt"
	"os"
)

// If true, perform sanity checking and show progress at each
// successive iteration of optimizeBlocks.  Very verbose.
const debugBlockOpt = false

// markReachable sets Index=-1 for all blocks reachable from b.
func markReachable(b *BasicBlock) {
	b.Index = -1
	for _, succ := range b.Succs {
		if succ.Index == 0 {
			markReachable(succ)
		}
	}
}

// deleteUnreachableBlocks marks all reachable blocks of f and
// eliminates (nils) all others, including possibly cyclic subgraphs.
//
func deleteUnreachableBlocks(f *Function) {
	const white, black = 0, -1
	// We borrow b.Index temporarily as the mark bit.
	for _, b := range f.Blocks {
		b.Index = white
	}
	markReachable(f.Blocks[0])
	for i, b := range f.Blocks {
		if b.Index == white {
			for _, c := range b.Succs {
				if c.Index == black {
					c.removePred(b) // delete white->black edge
				}
			}
			if debugBlockOpt {
				fmt.Fprintln(os.Stderr, "unreachable", b)
			}
			f.Blocks[i] = nil // delete b
		}
	}
	f.removeNilBlocks()
}

// jumpThreading attempts to apply simple jump-threading to block b,
// in which a->b->c become a->c if b is just a Jump.
// The result is true if the optimization was applied.
//
func jumpThreading(f *Function, b *BasicBlock) bool {
	if b.Index == 0 {
		return false // don't apply to entry block
	}
	if b.Instrs == nil {
		return false
	}
	if _, ok := b.Instrs[0].(*Jump); !ok {
		return false // not just a jump
	}
	c := b.Succs[0]
	if c == b {
		return false // don't apply to degenerate jump-to-self.
	}
	if c.hasPhi() {
		return false // not sound without more effort
	}
	for j, a := range b.Preds {
		a.replaceSucc(b, c)

		// If a now has two edges to c, replace its degenerate If by Jump.
		if len(a.Succs) == 2 && a.Succs[0] == c && a.Succs[1] == c {
			jump := new(Jump)
			jump.setBlock(a)
			a.Instrs[len(a.Instrs)-1] = jump
			a.Succs = a.Succs[:1]
			c.removePred(b)
		} else {
			if j == 0 {
				c.replacePred(b, a)
			} else {
				c.Preds = append(c.Preds, a)
			}
		}

		if debugBlockOpt {
			fmt.Fprintln(os.Stderr, "jumpThreading", a, b, c)
		}
	}
	f.Blocks[b.Index] = nil // delete b
	return true
}

// fuseBlocks attempts to apply the block fusion optimization to block
// a, in which a->b becomes ab if len(a.Succs)==len(b.Preds)==1.
// The result is true if the optimization was applied.
//
func fuseBlocks(f *Function, a *BasicBlock) bool {
	if len(a.Succs) != 1 {
		return false
	}
	if a.Succs[0] == f.Exit {
		return false
	}
	b := a.Succs[0]
	if len(b.Preds) != 1 {
		return false
	}
	if _, ok := a.Instrs[len(a.Instrs)-1].(*Panic); ok {
		// panics aren't simple jumps, they have side effects.
		return false
	}

	// Degenerate &&/|| ops may result in a straight-line CFG
	// containing φ-nodes. (Ideally we'd replace such them with
	// their sole operand but that requires Referrers, built later.)
	if b.hasPhi() {
		return false // not sound without further effort
	}

	// Eliminate jump at end of A, then copy all of B across.
	a.Instrs = append(a.Instrs[:len(a.Instrs)-1], b.Instrs...)
	for _, instr := range b.Instrs {
		instr.setBlock(a)
	}

	// A inherits B's successors
	a.Succs = append(a.succs2[:0], b.Succs...)

	// Fix up Preds links of all successors of B.
	for _, c := range b.Succs {
		c.replacePred(b, a)
	}

	if debugBlockOpt {
		fmt.Fprintln(os.Stderr, "fuseBlocks", a, b)
	}

	f.Blocks[b.Index] = nil // delete b
	return true
}

// optimizeBlocks() performs some simple block optimizations on a
// completed function: dead block elimination, block fusion, jump
// threading.
//
func optimizeBlocks(f *Function) {
	deleteUnreachableBlocks(f)

	// Loop until no further progress.
	changed := true
	for changed {
		changed = false

		if debugBlockOpt {
			f.WriteTo(os.Stderr)
			mustSanityCheck(f, nil)
		}

		for _, b := range f.Blocks {
			// f.Blocks will temporarily contain nils to indicate
			// deleted blocks; we remove them at the end.
			if b == nil {
				continue
			}

			// Fuse blocks.  b->c becomes bc.
			if fuseBlocks(f, b) {
				changed = true
			}

			// a->b->c becomes a->c if b contains only a Jump.
			if jumpThreading(f, b) {
				changed = true
				continue // (b was disconnected)
			}
		}
	}
	f.removeNilBlocks()
}
<|endoftext|>


<commit_before>package echo

import (
	"encoding/json"
	"net/http"

	"github.com/labstack/echo"
	"github.com/open-gtd/server/sse"
)

func NewSseRegisterer(g *echo.Group) sse.SseRegisterer {
	return &sseRegisterer{
		group:   g,
		channel: make(chan interface{}),
	}
}

type sseRegisterer struct {
	group   *echo.Group
	channel chan interface{}
}

func (sr sseRegisterer) CreatePushDataFunc(prefix sse.Prefix, closeNotify sse.ClientClosedNotificationFunc) sse.PushDataToSseFunc {
	sr.group.GET("/"+string(prefix), func(c echo.Context) error {
		c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
		c.Response().WriteHeader(http.StatusOK)

		notify := c.Response().CloseNotify()

		go func() {
			<-notify
			closeNotify()
		}()

		for {
			v := <-sr.channel
			if err := json.NewEncoder(c.Response()).Encode(v); err != nil {
				return err
			}
			c.Response().Flush()
		}

		closeNotify()

		return nil
	})

	return func(topic sse.Topic, v interface{}) {
		sr.channel <- sse.Envelope{Topic: topic, Data: v}
	}
}
<commit_msg>sse - exiting http stream writing loop on stream close<commit_after>package echo

import (
	"encoding/json"
	"net/http"

	"fmt"

	"github.com/labstack/echo"
	"github.com/open-gtd/server/sse"
)

func NewSseRegisterer(g *echo.Group) sse.SseRegisterer {
	return &sseRegisterer{
		group:   g,
		channel: make(chan interface{}),
		exit:    make(chan bool),
	}
}

type sseRegisterer struct {
	group   *echo.Group
	channel chan interface{}
	exit    chan bool
}

func (sr sseRegisterer) CreatePushDataFunc(prefix sse.Prefix, closeNotify sse.ClientClosedNotificationFunc) sse.PushDataToSseFunc {
	sr.group.GET("/"+string(prefix), func(c echo.Context) error {
		c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
		c.Response().WriteHeader(http.StatusOK)

		notify := c.Response().CloseNotify()

		go func() {
			<-notify
			fmt.Println("notify")

			sr.exit <- true
			closeNotify()
		}()

		for {
			fmt.Println("new loop iteratinon")
			select {
			case <-sr.exit:
				fmt.Println("exit")
				return nil
			case v := <-sr.channel:
				if err := json.NewEncoder(c.Response()).Encode(v); err != nil {
					return err
				}
				c.Response().Flush()
			}
		}

		fmt.Println("exit")
		closeNotify()

		return nil
	})

	return func(topic sse.Topic, v interface{}) {
		sr.channel <- sse.Envelope{Topic: topic, Data: v}
	}
}
<|endoftext|>