<commit_before>package bitswap

import (
	"sync"
	"time"

	context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
	engine "github.com/ipfs/go-ipfs/exchange/bitswap/decision"
	bsmsg "github.com/ipfs/go-ipfs/exchange/bitswap/message"
	bsnet "github.com/ipfs/go-ipfs/exchange/bitswap/network"
	wantlist "github.com/ipfs/go-ipfs/exchange/bitswap/wantlist"
	peer "github.com/ipfs/go-ipfs/p2p/peer"
	u "github.com/ipfs/go-ipfs/util"
)

type WantManager struct {
	receiver bsnet.Receiver

	incoming chan []*bsmsg.Entry

	// notification channel for new peers connecting
	connect chan peer.ID

	// notification channel for peers disconnecting
	disconnect chan peer.ID

	peers map[peer.ID]*msgQueue

	wl *wantlist.Wantlist

	network bsnet.BitSwapNetwork

	ctx context.Context
}

func NewWantManager(ctx context.Context, network bsnet.BitSwapNetwork) *WantManager {
	return &WantManager{
		incoming:   make(chan []*bsmsg.Entry, 10),
		connect:    make(chan peer.ID, 10),
		disconnect: make(chan peer.ID, 10),
		peers:      make(map[peer.ID]*msgQueue),
		wl:         wantlist.New(),
		network:    network,
		ctx:        ctx,
	}
}

type msgPair struct {
	to  peer.ID
	msg bsmsg.BitSwapMessage
}

type cancellation struct {
	who peer.ID
	blk u.Key
}

type msgQueue struct {
	p peer.ID

	outlk sync.Mutex
	out   bsmsg.BitSwapMessage

	work chan struct{}
	done chan struct{}
}

func (pm *WantManager) WantBlocks(ks []u.Key) {
	log.Infof("want blocks: %s", ks)
	pm.addEntries(ks, false)
}

func (pm *WantManager) CancelWants(ks []u.Key) {
	pm.addEntries(ks, true)
}

func (pm *WantManager) addEntries(ks []u.Key, cancel bool) {
	var entries []*bsmsg.Entry
	for i, k := range ks {
		entries = append(entries, &bsmsg.Entry{
			Cancel: cancel,
			Entry: wantlist.Entry{
				Key:      k,
				Priority: kMaxPriority - i,
			},
		})
	}
	select {
	case pm.incoming <- entries:
	case <-pm.ctx.Done():
	}
}

func (pm *WantManager) SendBlock(ctx context.Context, env *engine.Envelope) {
	// Blocks need to be sent synchronously to maintain proper backpressure
	// throughout the network stack
	defer env.Sent()

	msg := bsmsg.New(false)
	msg.AddBlock(env.Block)
	log.Infof("Sending block %s to %s", env.Peer, env.Block)
	err := pm.network.SendMessage(ctx, env.Peer, msg)
	if err != nil {
		log.Error(err)
	}
}

func (pm *WantManager) startPeerHandler(p peer.ID) *msgQueue {
	_, ok := pm.peers[p]
	if ok {
		// TODO: log an error?
		return nil
	}

	mq := newMsgQueue(p)

	// new peer, we will want to give them our full wantlist
	fullwantlist := bsmsg.New(true)
	for _, e := range pm.wl.Entries() {
		fullwantlist.AddEntry(e.Key, e.Priority)
	}
	mq.out = fullwantlist
	mq.work <- struct{}{}

	pm.peers[p] = mq
	go pm.runQueue(mq)
	return mq
}

func (pm *WantManager) stopPeerHandler(p peer.ID) {
	pq, ok := pm.peers[p]
	if !ok {
		// TODO: log error?
		return
	}

	close(pq.done)
	delete(pm.peers, p)
}

func (pm *WantManager) runQueue(mq *msgQueue) {
	for {
		select {
		case <-mq.work: // there is work to be done

			err := pm.network.ConnectTo(pm.ctx, mq.p)
			if err != nil {
				log.Errorf("cant connect to peer %s: %s", mq.p, err)
				// TODO: cant connect, what now?
				continue
			}

			// grab outgoing message
			mq.outlk.Lock()
			wlm := mq.out
			if wlm == nil || wlm.Empty() {
				mq.outlk.Unlock()
				continue
			}
			mq.out = nil
			mq.outlk.Unlock()

			// send wantlist updates
			err = pm.network.SendMessage(pm.ctx, mq.p, wlm)
			if err != nil {
				log.Error("bitswap send error: ", err)
				// TODO: what do we do if this fails?
			}
		case <-mq.done:
			return
		}
	}
}

func (pm *WantManager) Connected(p peer.ID) {
	pm.connect <- p
}

func (pm *WantManager) Disconnected(p peer.ID) {
	pm.disconnect <- p
}

// TODO: use goprocess here once i trust it
func (pm *WantManager) Run() {
	tock := time.NewTicker(rebroadcastDelay.Get())
	for {
		select {
		case entries := <-pm.incoming:

			// add changes to our wantlist
			for _, e := range entries {
				if e.Cancel {
					pm.wl.Remove(e.Key)
				} else {
					pm.wl.Add(e.Key, e.Priority)
				}
			}

			// broadcast those wantlist changes
			for _, p := range pm.peers {
				p.addMessage(entries)
			}

		case <-tock.C:
			// resend entire wantlist every so often (REALLY SHOULDNT BE NECESSARY)
			var es []*bsmsg.Entry
			for _, e := range pm.wl.Entries() {
				es = append(es, &bsmsg.Entry{Entry: e})
			}
			for _, p := range pm.peers {
				p.outlk.Lock()
				p.out = bsmsg.New(true)
				p.outlk.Unlock()

				p.addMessage(es)
			}
		case p := <-pm.connect:
			pm.startPeerHandler(p)
		case p := <-pm.disconnect:
			pm.stopPeerHandler(p)
		case <-pm.ctx.Done():
			return
		}
	}
}

func newMsgQueue(p peer.ID) *msgQueue {
	mq := new(msgQueue)
	mq.done = make(chan struct{})
	mq.work = make(chan struct{}, 1)
	mq.p = p

	return mq
}

func (mq *msgQueue) addMessage(entries []*bsmsg.Entry) {
	mq.outlk.Lock()
	defer func() {
		mq.outlk.Unlock()
		select {
		case mq.work <- struct{}{}:
		default:
		}
	}()

	// if we have no message held, or the one we are given is full
	// overwrite the one we are holding
	if mq.out == nil {
		mq.out = bsmsg.New(false)
	}

	// TODO: add a msg.Combine(...) method
	// otherwise, combine the one we are holding with the
	// one passed in
	for _, e := range entries {
		if e.Cancel {
			mq.out.Cancel(e.Key)
		} else {
			mq.out.AddEntry(e.Key, e.Priority)
		}
	}
}
<commit_msg>clarify synhronization constructs<commit_after>package bitswap

import (
	"sync"
	"time"

	context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
	engine "github.com/ipfs/go-ipfs/exchange/bitswap/decision"
	bsmsg "github.com/ipfs/go-ipfs/exchange/bitswap/message"
	bsnet "github.com/ipfs/go-ipfs/exchange/bitswap/network"
	wantlist "github.com/ipfs/go-ipfs/exchange/bitswap/wantlist"
	peer "github.com/ipfs/go-ipfs/p2p/peer"
	u "github.com/ipfs/go-ipfs/util"
)

type WantManager struct {
	// sync channels for Run loop
	incoming   chan []*bsmsg.Entry
	connect    chan peer.ID // notification channel for new peers connecting
	disconnect chan peer.ID // notification channel for peers disconnecting

	// synchronized by Run loop, only touch inside there
	peers map[peer.ID]*msgQueue
	wl    *wantlist.Wantlist

	network bsnet.BitSwapNetwork
	ctx     context.Context
}

func NewWantManager(ctx context.Context, network bsnet.BitSwapNetwork) *WantManager {
	return &WantManager{
		incoming:   make(chan []*bsmsg.Entry, 10),
		connect:    make(chan peer.ID, 10),
		disconnect: make(chan peer.ID, 10),
		peers:      make(map[peer.ID]*msgQueue),
		wl:         wantlist.New(),
		network:    network,
		ctx:        ctx,
	}
}

type msgPair struct {
	to  peer.ID
	msg bsmsg.BitSwapMessage
}

type cancellation struct {
	who peer.ID
	blk u.Key
}

type msgQueue struct {
	p peer.ID

	outlk   sync.Mutex
	out     bsmsg.BitSwapMessage
	network bsnet.BitSwapNetwork

	work chan struct{}
	done chan struct{}
}

func (pm *WantManager) WantBlocks(ks []u.Key) {
	log.Infof("want blocks: %s", ks)
	pm.addEntries(ks, false)
}

func (pm *WantManager) CancelWants(ks []u.Key) {
	pm.addEntries(ks, true)
}

func (pm *WantManager) addEntries(ks []u.Key, cancel bool) {
	var entries []*bsmsg.Entry
	for i, k := range ks {
		entries = append(entries, &bsmsg.Entry{
			Cancel: cancel,
			Entry: wantlist.Entry{
				Key:      k,
				Priority: kMaxPriority - i,
			},
		})
	}
	select {
	case pm.incoming <- entries:
	case <-pm.ctx.Done():
	}
}

func (pm *WantManager) SendBlock(ctx context.Context, env *engine.Envelope) {
	// Blocks need to be sent synchronously to maintain proper backpressure
	// throughout the network stack
	defer env.Sent()

	msg := bsmsg.New(false)
	msg.AddBlock(env.Block)
	log.Infof("Sending block %s to %s", env.Peer, env.Block)
	err := pm.network.SendMessage(ctx, env.Peer, msg)
	if err != nil {
		log.Error(err)
	}
}

func (pm *WantManager) startPeerHandler(p peer.ID) *msgQueue {
	_, ok := pm.peers[p]
	if ok {
		// TODO: log an error?
		return nil
	}

	mq := pm.newMsgQueue(p)

	// new peer, we will want to give them our full wantlist
	fullwantlist := bsmsg.New(true)
	for _, e := range pm.wl.Entries() {
		fullwantlist.AddEntry(e.Key, e.Priority)
	}
	mq.out = fullwantlist
	mq.work <- struct{}{}

	pm.peers[p] = mq
	go mq.runQueue(pm.ctx)
	return mq
}

func (pm *WantManager) stopPeerHandler(p peer.ID) {
	pq, ok := pm.peers[p]
	if !ok {
		// TODO: log error?
		return
	}

	close(pq.done)
	delete(pm.peers, p)
}

func (mq *msgQueue) runQueue(ctx context.Context) {
	for {
		select {
		case <-mq.work: // there is work to be done

			err := mq.network.ConnectTo(ctx, mq.p)
			if err != nil {
				log.Errorf("cant connect to peer %s: %s", mq.p, err)
				// TODO: cant connect, what now?
				continue
			}

			// grab outgoing message
			mq.outlk.Lock()
			wlm := mq.out
			if wlm == nil || wlm.Empty() {
				mq.outlk.Unlock()
				continue
			}
			mq.out = nil
			mq.outlk.Unlock()

			// send wantlist updates
			err = mq.network.SendMessage(ctx, mq.p, wlm)
			if err != nil {
				log.Error("bitswap send error: ", err)
				// TODO: what do we do if this fails?
			}
		case <-mq.done:
			return
		}
	}
}

func (pm *WantManager) Connected(p peer.ID) {
	pm.connect <- p
}

func (pm *WantManager) Disconnected(p peer.ID) {
	pm.disconnect <- p
}

// TODO: use goprocess here once i trust it
func (pm *WantManager) Run() {
	tock := time.NewTicker(rebroadcastDelay.Get())
	for {
		select {
		case entries := <-pm.incoming:

			// add changes to our wantlist
			for _, e := range entries {
				if e.Cancel {
					pm.wl.Remove(e.Key)
				} else {
					pm.wl.Add(e.Key, e.Priority)
				}
			}

			// broadcast those wantlist changes
			for _, p := range pm.peers {
				p.addMessage(entries)
			}

		case <-tock.C:
			// resend entire wantlist every so often (REALLY SHOULDNT BE NECESSARY)
			var es []*bsmsg.Entry
			for _, e := range pm.wl.Entries() {
				es = append(es, &bsmsg.Entry{Entry: e})
			}
			for _, p := range pm.peers {
				p.outlk.Lock()
				p.out = bsmsg.New(true)
				p.outlk.Unlock()

				p.addMessage(es)
			}
		case p := <-pm.connect:
			pm.startPeerHandler(p)
		case p := <-pm.disconnect:
			pm.stopPeerHandler(p)
		case <-pm.ctx.Done():
			return
		}
	}
}

func (wm *WantManager) newMsgQueue(p peer.ID) *msgQueue {
	mq := new(msgQueue)
	mq.done = make(chan struct{})
	mq.work = make(chan struct{}, 1)
	mq.network = wm.network
	mq.p = p

	return mq
}

func (mq *msgQueue) addMessage(entries []*bsmsg.Entry) {
	mq.outlk.Lock()
	defer func() {
		mq.outlk.Unlock()
		select {
		case mq.work <- struct{}{}:
		default:
		}
	}()

	// if we have no message held, or the one we are given is full
	// overwrite the one we are holding
	if mq.out == nil {
		mq.out = bsmsg.New(false)
	}

	// TODO: add a msg.Combine(...) method
	// otherwise, combine the one we are holding with the
	// one passed in
	for _, e := range entries {
		if e.Cancel {
			mq.out.Cancel(e.Key)
		} else {
			mq.out.AddEntry(e.Key, e.Priority)
		}
	}
}
<|endoftext|>


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

// Package fd provides functions to approximate derivatives using finite differences.
package fd

import (
	"math"
	"runtime"
	"sync"

	"github.com/gonum/floats"
)

// A Point is a stencil location in a finite difference formula.
type Point struct {
	Loc   float64
	Coeff float64
}

// Formula represents a finite difference formula that approximates
// the derivative of order k of a function f at x as
//  d^k f(x) ≅ (1 / h^k) * \sum_i Coeff_i * f(x + h * Loc_i),
// where h is a small positive step.
type Formula struct {
	// Stencil is the set of sampling Points which are used to estimate the
	// derivative. The locations will be scaled by Step and are relative to x.
	Stencil []Point
	Order   int     // The order of the approximated derivative.
	Step    float64 // Default step size for the formula.
}

// Settings is the settings structure for computing finite differences.
type Settings struct {
	OriginKnown bool    // Flag that the value at the origin x is known
	OriginValue float64 // Value at the origin (only used if OriginKnown is true)
	Concurrent  bool    // Should the function calls be executed concurrently.
	Formula     Formula // Finite difference formula to use
}

// DefaultSettings is a basic set of settings for computing finite differences.
// Computes a central difference approximation for the first derivative
// of the function.
func DefaultSettings() *Settings {
	return &Settings{
		Formula: Central,
	}
}

// Derivative estimates the derivative of the function f at the given location.
// The order of the derivative, sample locations, and other options are
// specified by settings. If settings is nil, default settings will be used.
func Derivative(f func(float64) float64, x float64, settings *Settings) float64 {
	if settings == nil {
		settings = DefaultSettings()
	}
	step := settings.Formula.Step
	var deriv float64
	formula := settings.Formula
	if !settings.Concurrent {
		for _, pt := range formula.Stencil {
			if settings.OriginKnown && pt.Loc == 0 {
				deriv += pt.Coeff * settings.OriginValue
				continue
			}
			deriv += pt.Coeff * f(x+step*pt.Loc)
		}
		return deriv / math.Pow(step, float64(formula.Order))
	}

	wg := &sync.WaitGroup{}
	mux := &sync.Mutex{}
	for _, pt := range formula.Stencil {
		if settings.OriginKnown && pt.Loc == 0 {
			mux.Lock()
			deriv += pt.Coeff * settings.OriginValue
			mux.Unlock()
			continue
		}
		wg.Add(1)
		go func(pt Point) {
			defer wg.Done()
			fofx := f(x + step*pt.Loc)
			mux.Lock()
			defer mux.Unlock()
			deriv += pt.Coeff * fofx
		}(pt)
	}
	wg.Wait()
	return deriv / math.Pow(step, float64(formula.Order))
}

// Gradient estimates the gradient of the multivariate function f at the
// location x. The result is stored in-place into dst if dst is not nil,
// otherwise a new slice will be allocated and returned. Finite difference
// kernel and other options are specified by settings. If settings is nil,
// default settings will be used.
// Gradient panics if the length of dst and x is not equal.
func Gradient(dst []float64, f func([]float64) float64, x []float64, settings *Settings) []float64 {
	if dst == nil {
		dst = make([]float64, len(x))
	}
	if len(dst) != len(x) {
		panic("fd: slice length mismatch")
	}
	if settings == nil {
		settings = DefaultSettings()
	}
	step := settings.Formula.Step
	if !settings.Concurrent {
		xcopy := make([]float64, len(x)) // So that x is not modified during the call
		copy(xcopy, x)
		for i := range xcopy {
			var deriv float64
			for _, pt := range settings.Formula.Stencil {
				if settings.OriginKnown && pt.Loc == 0 {
					deriv += pt.Coeff * settings.OriginValue
					continue
				}
				xcopy[i] += pt.Loc * step
				deriv += pt.Coeff * f(xcopy)
				xcopy[i] = x[i]
			}
			dst[i] = deriv / math.Pow(step, float64(settings.Formula.Order))
		}
		return dst
	}

	quit := make(chan struct{})
	defer close(quit)

	expect := len(settings.Formula.Stencil) * len(x)
	sendChan := make(chan fdrun, expect)
	ansChan := make(chan fdrun, expect)

	// Launch workers. Workers receive an index and a step, and compute the answer
	nWorkers := runtime.NumCPU()
	if nWorkers > expect {
		nWorkers = expect
	}
	for i := 0; i < nWorkers; i++ {
		go func(sendChan <-chan fdrun, ansChan chan<- fdrun, quit <-chan struct{}) {
			xcopy := make([]float64, len(x))
			copy(xcopy, x)
			for {
				select {
				case <-quit:
					return
				case run := <-sendChan:
					xcopy[run.idx] += run.pt.Loc * step
					run.result = f(xcopy)
					xcopy[run.idx] = x[run.idx]
					ansChan <- run
				}
			}
		}(sendChan, ansChan, quit)
	}

	// Launch the distributor. Distributor sends the cases to be computed
	go func(sendChan chan<- fdrun, ansChan chan<- fdrun) {
		for i := range x {
			for _, pt := range settings.Formula.Stencil {
				if settings.OriginKnown && pt.Loc == 0 {
					// Answer already known. Send the answer on the answer channel
					ansChan <- fdrun{
						idx:    i,
						pt:     pt,
						result: settings.OriginValue,
					}
					continue
				}
				// Answer not known, send the answer to be computed
				sendChan <- fdrun{
					idx: i,
					pt:  pt,
				}
			}
		}
	}(sendChan, ansChan)

	for i := range dst {
		dst[i] = 0
	}
	// Read in all of the results
	for i := 0; i < expect; i++ {
		run := <-ansChan
		dst[run.idx] += run.pt.Coeff * run.result
	}
	floats.Scale(1/math.Pow(step, float64(settings.Formula.Order)), dst)
	return dst
}

type fdrun struct {
	idx    int
	pt     Point
	result float64
}

// Forward represents a first-order forward difference.
var Forward = Formula{
	Stencil: []Point{{Loc: 0, Coeff: -1}, {Loc: 1, Coeff: 1}},
	Order:   1,
	Step:    1e-6,
}

// Backward represents a first-order backward difference.
var Backward = Formula{
	Stencil: []Point{{Loc: -1, Coeff: -1}, {Loc: 0, Coeff: 1}},
	Order:   1,
	Step:    1e-6,
}

// Central represents a first-order central difference.
var Central = Formula{
	Stencil: []Point{{Loc: -1, Coeff: -0.5}, {Loc: 1, Coeff: 0.5}},
	Order:   1,
	Step:    1e-6,
}

// Central2nd represents a secord-order central difference.
var Central2nd = Formula{
	Stencil: []Point{{Loc: -1, Coeff: 1}, {Loc: 0, Coeff: -2}, {Loc: 1, Coeff: 1}},
	Order:   2,
	Step:    1e-3,
}
<commit_msg>fd: add user-settable step size to Settings<commit_after>// Copyright ©2014 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package fd provides functions to approximate derivatives using finite differences.
package fd

import (
	"math"
	"runtime"
	"sync"

	"github.com/gonum/floats"
)

// A Point is a stencil location in a finite difference formula.
type Point struct {
	Loc   float64
	Coeff float64
}

// Formula represents a finite difference formula that approximates
// the derivative of order k of a function f at x as
//  d^k f(x) ≅ (1 / Step^k) * \sum_i Coeff_i * f(x + Step * Loc_i).
type Formula struct {
	// Stencil is the set of sampling Points which are used to estimate the
	// derivative. The locations will be scaled by Step and are relative to x.
	Stencil []Point
	Order   int     // The order of the approximated derivative.
	Step    float64 // Default step size for the formula.
}

// Settings is the settings structure for computing finite differences.
type Settings struct {
	// Formula is the finite difference formula used
	// for approximating the derivative.
	Formula Formula
	// Step is the distance between points of the stencil.
	// If equal to 0, formula's default step will be used.
	Step float64

	OriginKnown bool    // Flag that the value at the origin x is known
	OriginValue float64 // Value at the origin (only used if OriginKnown is true)
	Concurrent  bool    // Should the function calls be executed concurrently.
}

// DefaultSettings is a basic set of settings for computing finite differences.
// Computes a central difference approximation for the first derivative
// of the function.
func DefaultSettings() *Settings {
	return &Settings{
		Formula: Central,
	}
}

// Derivative estimates the derivative of the function f at the given location.
// The order of the derivative, sample locations, and other options are
// specified by settings. If settings is nil, default settings will be used.
func Derivative(f func(float64) float64, x float64, settings *Settings) float64 {
	if settings == nil {
		settings = DefaultSettings()
	}
	formula := settings.Formula
	step := settings.Step
	if step == 0 {
		step = formula.Step
	}

	var deriv float64
	if !settings.Concurrent {
		for _, pt := range formula.Stencil {
			if settings.OriginKnown && pt.Loc == 0 {
				deriv += pt.Coeff * settings.OriginValue
				continue
			}
			deriv += pt.Coeff * f(x+step*pt.Loc)
		}
		return deriv / math.Pow(step, float64(formula.Order))
	}

	wg := &sync.WaitGroup{}
	mux := &sync.Mutex{}
	for _, pt := range formula.Stencil {
		if settings.OriginKnown && pt.Loc == 0 {
			mux.Lock()
			deriv += pt.Coeff * settings.OriginValue
			mux.Unlock()
			continue
		}
		wg.Add(1)
		go func(pt Point) {
			defer wg.Done()
			fofx := f(x + step*pt.Loc)
			mux.Lock()
			defer mux.Unlock()
			deriv += pt.Coeff * fofx
		}(pt)
	}
	wg.Wait()
	return deriv / math.Pow(step, float64(formula.Order))
}

// Gradient estimates the gradient of the multivariate function f at the
// location x. The result is stored in-place into dst if dst is not nil,
// otherwise a new slice will be allocated and returned. Finite difference
// kernel and other options are specified by settings. If settings is nil,
// default settings will be used.
// Gradient panics if the length of dst and x is not equal.
func Gradient(dst []float64, f func([]float64) float64, x []float64, settings *Settings) []float64 {
	if dst == nil {
		dst = make([]float64, len(x))
	}
	if len(dst) != len(x) {
		panic("fd: slice length mismatch")
	}
	if settings == nil {
		settings = DefaultSettings()
	}
	formula := settings.Formula
	step := settings.Step
	if step == 0 {
		step = formula.Step
	}

	if !settings.Concurrent {
		xcopy := make([]float64, len(x)) // So that x is not modified during the call
		copy(xcopy, x)
		for i := range xcopy {
			var deriv float64
			for _, pt := range formula.Stencil {
				if settings.OriginKnown && pt.Loc == 0 {
					deriv += pt.Coeff * settings.OriginValue
					continue
				}
				xcopy[i] += pt.Loc * step
				deriv += pt.Coeff * f(xcopy)
				xcopy[i] = x[i]
			}
			dst[i] = deriv / math.Pow(step, float64(formula.Order))
		}
		return dst
	}

	quit := make(chan struct{})
	defer close(quit)

	expect := len(settings.Formula.Stencil) * len(x)
	sendChan := make(chan fdrun, expect)
	ansChan := make(chan fdrun, expect)

	// Launch workers. Workers receive an index and a step, and compute the answer
	nWorkers := runtime.NumCPU()
	if nWorkers > expect {
		nWorkers = expect
	}
	for i := 0; i < nWorkers; i++ {
		go func(sendChan <-chan fdrun, ansChan chan<- fdrun, quit <-chan struct{}) {
			xcopy := make([]float64, len(x))
			copy(xcopy, x)
			for {
				select {
				case <-quit:
					return
				case run := <-sendChan:
					xcopy[run.idx] += run.pt.Loc * step
					run.result = f(xcopy)
					xcopy[run.idx] = x[run.idx]
					ansChan <- run
				}
			}
		}(sendChan, ansChan, quit)
	}

	// Launch the distributor. Distributor sends the cases to be computed
	go func(sendChan chan<- fdrun, ansChan chan<- fdrun) {
		for i := range x {
			for _, pt := range formula.Stencil {
				if settings.OriginKnown && pt.Loc == 0 {
					// Answer already known. Send the answer on the answer channel
					ansChan <- fdrun{
						idx:    i,
						pt:     pt,
						result: settings.OriginValue,
					}
					continue
				}
				// Answer not known, send the answer to be computed
				sendChan <- fdrun{
					idx: i,
					pt:  pt,
				}
			}
		}
	}(sendChan, ansChan)

	for i := range dst {
		dst[i] = 0
	}
	// Read in all of the results
	for i := 0; i < expect; i++ {
		run := <-ansChan
		dst[run.idx] += run.pt.Coeff * run.result
	}
	floats.Scale(1/math.Pow(step, float64(formula.Order)), dst)
	return dst
}

type fdrun struct {
	idx    int
	pt     Point
	result float64
}

// Forward represents a first-order forward difference.
var Forward = Formula{
	Stencil: []Point{{Loc: 0, Coeff: -1}, {Loc: 1, Coeff: 1}},
	Order:   1,
	Step:    1e-6,
}

// Backward represents a first-order backward difference.
var Backward = Formula{
	Stencil: []Point{{Loc: -1, Coeff: -1}, {Loc: 0, Coeff: 1}},
	Order:   1,
	Step:    1e-6,
}

// Central represents a first-order central difference.
var Central = Formula{
	Stencil: []Point{{Loc: -1, Coeff: -0.5}, {Loc: 1, Coeff: 0.5}},
	Order:   1,
	Step:    1e-6,
}

// Central2nd represents a secord-order central difference.
var Central2nd = Formula{
	Stencil: []Point{{Loc: -1, Coeff: 1}, {Loc: 0, Coeff: -2}, {Loc: 1, Coeff: 1}},
	Order:   2,
	Step:    1e-3,
}
<|endoftext|>


<commit_before>package varys

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

// Fetcher interface
type Fetcher interface {
	Fetch(url string) (body []byte, err error)
}

type URLFetcher struct {
	client *http.Client
}

func NewURLFetcher() *URLFetcher {
	cfg := &tls.Config{InsecureSkipVerify: true}
	transport := &http.Transport{TLSClientConfig: cfg}
	client := &http.Client{Transport: transport}
	return &URLFetcher{client: client}
}

// Fetch web page from url.
func (f *URLFetcher) Fetch(url string) (body []byte, err error) {
	resp, err := f.client.Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("HTTP error: %d", resp.StatusCode)
	}
	return ioutil.ReadAll(resp.Body)
}
<commit_msg>Added SmartURLFetcher<commit_after>package varys

import (
	"container/ring"
	"crypto/tls"
	"fmt"
	"io/ioutil"
	"net/http"
	"sync"
)

// Fetcher interface
type Fetcher interface {
	Fetch(url string) (body []byte, err error)
}

type URLFetcher struct {
	client  *http.Client
	prepare func(*http.Request)
}

func NewURLFetcher(prepare func(*http.Request)) Fetcher {
	cfg := &tls.Config{InsecureSkipVerify: true}
	transport := &http.Transport{TLSClientConfig: cfg}
	client := &http.Client{Transport: transport}
	return &URLFetcher{client: client, prepare: prepare}
}

// Fetch web page from url.
func (f *URLFetcher) Fetch(url string) (body []byte, err error) {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}
	if f.prepare != nil {
		f.prepare(req)
	}
	resp, err := f.client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("HTTP error: %d", resp.StatusCode)
	}
	return ioutil.ReadAll(resp.Body)
}

type SmartURLFetcher struct {
	Fetcher
	userAgents *ring.Ring
	mu         sync.Mutex
}

func NewSmartURLFetcher(prepare func(*http.Request), userAgents ...string) Fetcher {
	f := &SmartURLFetcher{}
	if len(userAgents) == 0 {
		f.Fetcher = NewURLFetcher(prepare)
		return f
	}
	f.userAgents = ring.New(len(userAgents))
	for _, ua := range userAgents {
		f.userAgents.Value = ua
		f.userAgents = f.userAgents.Next()
	}
	f.Fetcher = NewURLFetcher(func(req *http.Request) {
		req.Header.Set("User-Agent", f.nextUserAgent())
		prepare(req)
	})
	return f
}

func (f *SmartURLFetcher) nextUserAgent() string {
	f.mu.Lock()
	ua := f.userAgents.Value.(string)
	f.userAgents = f.userAgents.Next()
	f.mu.Unlock()
	return ua
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"strings"

	"gopkg.in/jackc/pgx.v2"

	"github.com/golang/groupcache"

	"github.com/LeKovr/dbrpc/workman"
	"github.com/LeKovr/go-base/logger"
)

// -----------------------------------------------------------------------------

// Processor gets value from cache and converts it into Result struct
func cacheFetcher(log *logger.Log, cacheGroup *groupcache.Group) workman.WorkerFunc {
	// https://github.com/capotej/groupcache-db-experiment
	return func(payload string) workman.Result {
		var data []byte
		log.Printf("asked for %s from groupcache", payload)
		err := cacheGroup.Get(nil, payload,
			groupcache.AllocatingByteSliceSink(&data))
		var res workman.Result
		if err != nil {
			res = workman.Result{Success: false, Error: err.Error()}
		} else {
			d := data[1:]
			if data[0] == 1 { // First byte stores success state (1: true, 0: false)
				raw := json.RawMessage(d)
				res = workman.Result{Success: true, Result: &raw}
			} else {
				res = workman.Result{Success: false, Error: string(d)}
			}
		}
		return res
	}
}

// -----------------------------------------------------------------------------

func dbFetcher(cfg *AplFlags, log *logger.Log, db *pgx.Conn) groupcache.GetterFunc {
	return func(ctx groupcache.Context, key string, dest groupcache.Sink) error {
		log.Printf("asking for %s from dbserver", key)

		var args []string
		var data []byte

		//err := json.Unmarshal(key, &args)
		json.Unmarshal([]byte(key), &args)

		if args[0] == cfg.ArgDefFunc {

			q := fmt.Sprintf("select * from %s.%s($1)", cfg.Schema, args[0])

			rows, err := db.Query(q, args[1])
			if err != nil {
				return err
			}
			defer rows.Close()

			var res []ArgDef
			for rows.Next() {
				var a ArgDef
				err = rows.Scan(&a.ID, &a.Name, &a.Type, &a.Default, &a.AllowNull)
				if err != nil {
					log.Printf("Func err: (%+v)", rows)
					return err
				}
				res = append(res, a)
			}
			if rows.Err() != nil {
				return err
			}
			log.Printf("Func def: %s (%+v)", args[1], res)

			data, err = json.Marshal(res)
			if err != nil {
				return err
			}

		} else {
			q, vals := PrepareFuncSQL(cfg, args)
			log.Printf("Query: %s (%+v / %+v)", q, args, vals)
			rows, err := db.Query(q, vals...)
			if err != nil {
				return err
			}

			data, err = FetchSQLResult(rows, log)
			defer rows.Close()
			if err != nil {
				return err
			}

		}
		result := []byte{1} // status: success
		result = append(result, data...)

		dd := result[1:]
		log.Printf("Save data: %s", dd)
		dest.SetBytes([]byte(result))
		return nil
	}
}

// -----------------------------------------------------------------------------

// PrepareFuncSQL prepares sql query with args placeholders
func PrepareFuncSQL(cfg *AplFlags, args []string) (string, []interface{}) {
	mtd := args[0]
	argVals := args[1:]

	argValPrep := make([]interface{}, len(argVals))
	argIDs := make([]string, len(argVals))

	for i, v := range argVals {
		argIDs[i] = fmt.Sprintf("$%d", i+1)
		argValPrep[i] = v
	}

	argIDStr := strings.Join(argIDs, ",")

	q := fmt.Sprintf("select * from %s.%s(%s)", cfg.Schema, mtd, argIDStr)

	return q, argValPrep
}

// -----------------------------------------------------------------------------

// FetchSQLResult fetches sql result and marshalls it into json
func FetchSQLResult(rows *pgx.Rows, log *logger.Log) (data []byte, err error) {
	// http://stackoverflow.com/a/29164115
	columnDefs := rows.FieldDescriptions()
	//log.Debugf("=========== %+v", columnDefs)
	columns := []string{}
	for _, c := range columnDefs {
		columns = append(columns, c.Name)
	}

	var tableData []map[string]interface{}
	for rows.Next() {
		values, err := rows.Values()
		if err != nil {
			log.Warningf("Value fetch error: %s", err.Error())
		}
		log.Debugf("Values: %+v", values)

		entry := make(map[string]interface{})
		for i, col := range columns {
			var v interface{}
			val := values[i]
			b, ok := val.([]byte)
			if ok {
				v = string(b)
			} else {
				v = val
			}
			entry[col] = v
		}
		tableData = append(tableData, entry)
	}
	data, err = json.Marshal(tableData)
	return
}
<commit_msg>fix: return json(b) correctly<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"strings"

	"gopkg.in/jackc/pgx.v2"

	"github.com/golang/groupcache"

	"github.com/LeKovr/dbrpc/workman"
	"github.com/LeKovr/go-base/logger"
)

// -----------------------------------------------------------------------------

// Processor gets value from cache and converts it into Result struct
func cacheFetcher(log *logger.Log, cacheGroup *groupcache.Group) workman.WorkerFunc {
	// https://github.com/capotej/groupcache-db-experiment
	return func(payload string) workman.Result {
		var data []byte
		log.Printf("asked for %s from groupcache", payload)
		err := cacheGroup.Get(nil, payload,
			groupcache.AllocatingByteSliceSink(&data))
		var res workman.Result
		if err != nil {
			res = workman.Result{Success: false, Error: err.Error()}
		} else {
			d := data[1:]
			if data[0] == 1 { // First byte stores success state (1: true, 0: false)
				raw := json.RawMessage(d)
				res = workman.Result{Success: true, Result: &raw}
			} else {
				res = workman.Result{Success: false, Error: string(d)}
			}
		}
		return res
	}
}

// -----------------------------------------------------------------------------

func dbFetcher(cfg *AplFlags, log *logger.Log, db *pgx.Conn) groupcache.GetterFunc {
	return func(ctx groupcache.Context, key string, dest groupcache.Sink) error {
		log.Printf("asking for %s from dbserver", key)

		var args []string
		var data []byte

		//err := json.Unmarshal(key, &args)
		json.Unmarshal([]byte(key), &args)

		if args[0] == cfg.ArgDefFunc {

			q := fmt.Sprintf("select * from %s.%s($1)", cfg.Schema, args[0])

			rows, err := db.Query(q, args[1])
			if err != nil {
				return err
			}
			defer rows.Close()

			var res []ArgDef
			for rows.Next() {
				var a ArgDef
				err = rows.Scan(&a.ID, &a.Name, &a.Type, &a.Default, &a.AllowNull)
				if err != nil {
					log.Printf("Func err: (%+v)", rows)
					return err
				}
				res = append(res, a)
			}
			if rows.Err() != nil {
				return err
			}
			log.Printf("Func def: %s (%+v)", args[1], res)

			data, err = json.Marshal(res)
			if err != nil {
				return err
			}

		} else {
			q, vals := PrepareFuncSQL(cfg, args)
			log.Printf("Query: %s (%+v / %+v)", q, vals)
			rows, err := db.Query(q, vals...)
			if err != nil {
				return err
			}

			data, err = FetchSQLResult(rows, log)
			defer rows.Close()
			if err != nil {
				return err
			}

		}
		result := []byte{1} // status: success
		result = append(result, data...)

		dd := result[1:]
		log.Printf("Save data: %s", dd)
		dest.SetBytes([]byte(result))
		return nil
	}
}

// -----------------------------------------------------------------------------

// PrepareFuncSQL prepares sql query with args placeholders
func PrepareFuncSQL(cfg *AplFlags, args []string) (string, []interface{}) {
	mtd := args[0]
	argVals := args[1:]

	argValPrep := make([]interface{}, len(argVals))
	argIDs := make([]string, len(argVals))

	for i, v := range argVals {
		argIDs[i] = fmt.Sprintf("$%d", i+1)
		argValPrep[i] = v
	}

	argIDStr := strings.Join(argIDs, ",")

	q := fmt.Sprintf("select * from %s.%s(%s)", cfg.Schema, mtd, argIDStr)

	return q, argValPrep
}

// -----------------------------------------------------------------------------

// FetchSQLResult fetches sql result and marshalls it into json
func FetchSQLResult(rows *pgx.Rows, log *logger.Log) (data []byte, err error) {
	// http://stackoverflow.com/a/29164115
	columnDefs := rows.FieldDescriptions()
	//log.Debugf("=========== %+v", columnDefs)
	columns := []string{}
	types := []string{}
	for _, c := range columnDefs {
		columns = append(columns, c.Name)
		types = append(types, c.DataTypeName)
	}

	var tableData []map[string]interface{}
	for rows.Next() {
		values, err := rows.Values()
		if err != nil {
			log.Warningf("Value fetch error: %s", err.Error())
		}
		log.Debugf("Values: %+v", values)

		entry := make(map[string]interface{})
		for i, col := range columns {
			var v interface{}
			val := values[i]
			if types[i] == "json" || types[i] == "jsonb" {
				raw := fmt.Sprintf("%s", val)
				ref := json.RawMessage(raw)
				entry[col] = &ref
			} else {
				v = val
				entry[col] = v
			}
		}
		tableData = append(tableData, entry)

	}
	data, err = json.Marshal(tableData)
	return
}
<|endoftext|>


<commit_before>package jsonrpc

import (
	"fmt"
	"log"
	"strconv"

	"github.com/nbusy/neptulon"
)

func authMiddleware(conn *neptulon.Conn, msg *Message) {
	if conn.Session.Get("userid") != 0 {
		return
	}

	// client certificate authorization: certificate is verified by the TLS listener instance so we trust it
	peerCerts := conn.ConnectionState().PeerCertificates
	if len(peerCerts) > 0 {
		idstr := peerCerts[0].Subject.CommonName
		uid64, err := strconv.ParseUint(idstr, 10, 32)
		if err != nil {
			conn.Session.Set("error", fmt.Errorf("Cannot parse client message or method mismatched: %v", err))
			return
		}
		userID := uint32(uid64)
		log.Printf("Client connected with client certificate subject: %+v", peerCerts[0].Subject)
		conn.Session.Set("userid", userID)
	}
}
<commit_msg>add certauth type<commit_after>package jsonrpc

import (
	"fmt"
	"log"
	"strconv"
)

// CertAuth is a TLS certificate authentication middleware for Neptulon JSON-RPC app.
type CertAuth struct {
}

// NewCertAuth creates and registers a new certificate authentication middleware instance with a Neptulon JSON-RPC app.
func NewCertAuth(app *App) (*CertAuth, error) {
	a := CertAuth{}
	app.Middleware(a.middleware)
	return &a, nil
}

func (a *CertAuth) middleware(ctx *Context) {
	if ctx.Conn.Session.Get("userid") != 0 {
		return
	}

	// possible responses:
	// cert revoked
	// cert expired
	// cert invalid

	// client certificate authorization: certificate is verified by the TLS listener instance so we trust it
	peerCerts := ctx.Conn.ConnectionState().PeerCertificates
	if len(peerCerts) > 0 {
		idstr := peerCerts[0].Subject.CommonName
		uid64, err := strconv.ParseUint(idstr, 10, 32)
		if err != nil {
			ctx.Conn.Session.Set("error", fmt.Errorf("Cannot parse client message or method mismatched: %v", err))
			return
		}
		userID := uint32(uid64)
		log.Printf("Client connected with client certificate subject: %+v", peerCerts[0].Subject)
		ctx.Conn.Session.Set("userid", userID)
	}
}
<|endoftext|>


<commit_before>// These will all be very flaky because they are dependent on actual
// filesystems.
package main

import (
	"crypto/rand"
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
	"time"
)

const waitForMsg = 2 * time.Second

// Slow in the success case
func TestNoWatchingCreation(t *testing.T) {
	fs := newFS(t)
	fs.Create("foobar")
	ch := make(chan time.Time, 10)
	cleanUp := watchTest(fs, []string{fs.Abs("foobar")}, []string{}, ch)
	defer cleanUp()
	fs.Create("baz")
	seeNothing(fs, ch, "creation of baz")
}

// Slow in the success case
func TestSimpleWatch(t *testing.T) {
	fs := newFS(t)
	fs.Create("foobar")
	ch := make(chan time.Time, 10)
	cleanUp := watchTest(fs, []string{fs.Abs("foobar")}, []string{fs.Abs("baz")}, ch)
	defer cleanUp()
	fs.ChangeContents("foobar")
	seeChangeContents(fs, ch, "foobar")
	fs.Create("baz")
	seeNothing(fs, ch, "creation of baz")
}

func TestSimpleDirWatch(t *testing.T) {
	fs := newFS(t)
	fs.MkdirAll("dir1")
	ch := make(chan time.Time, 10)
	cleanUp := watchTest(fs, []string{fs.Abs("dir1")}, []string{}, ch)
	defer cleanUp()
	fs.Create("dir1/foobar")
	seeCreation(fs, ch, "dir1/foobar")
}

func TestCurrentDirWorks(t *testing.T) {
	fs := newFS(t)
	fs.Create("foobar")
	ch := make(chan time.Time, 10)
	cleanUp := watchTest(fs, []string{fs.Abs(".")}, nil, ch)
	defer cleanUp()
	fs.ChangeContents("foobar")
	seeChangeContents(fs, ch, "foobar")
	fs.Create("baz")
	seeCreation(fs, ch, "baz")
}

// Slow in the success case
func TestIgnoredDir(t *testing.T) {
	fs := newFS(t)
	fs.Create("foobar")
	fs.MkdirAll("existdir/quuxdir")
	ch := make(chan time.Time, 10)
	cleanUp := watchTest(fs, []string{fs.Abs(".")},
		[]string{
			fs.Abs("bardir"),
			fs.Abs("existdir"),
		},
		ch)
	defer cleanUp()

	fs.MkdirAll("bardir")
	fs.Create("bardir/barfile")
	fs.RemoveAll("bardir")
	fs.Create("existdir/level1")
	fs.Create("existdir/quuxdir/level2")
	fs.ChangeContents("existdir/level1")
	fs.ChangeContents("existdir/quuxdir/level2")
	seeNothing(fs, ch, "some ignored operations")
}

// Slow in the success case
func TestIgnoredDirOverlap(t *testing.T) {
	fs := newFS(t)
	fs.Create("foobar")
	fs.MkdirAll("existdir/quuxdir")
	ch := make(chan time.Time, 10)
	// The existdir and existdir/quuxdir cases seem silly but can
	// happen accidentally in shell globbing. Better to be consistent
	// about it.
	cleanUp := watchTest(fs,
		[]string{
			fs.Abs("."),
			fs.Abs("bardir"),
			fs.Abs("existdir/quuxdir"),
		},
		[]string{
			fs.Abs("bardir"),
			fs.Abs("existdir/quuxdir"),
		},
		ch)
	defer cleanUp()

	fs.MkdirAll("bardir")
	fs.Create("bardir/barfile")
	fs.Create("existdir/level1")
	fs.Create("existdir/quuxdir/level2")
	fs.ChangeContents("existdir/level1")
	fs.ChangeContents("existdir/quuxdir/level2")

	seeNothing(fs, ch, "some ignored operations")
}

func TestNoSubdirRecursionWithoutGlobs(t *testing.T) {
	fs := newFS(t)
	fs.MkdirAll("some_dir")
	ch := make(chan time.Time, 10)
	cleanUp := watchTest(fs, []string{fs.Abs(".")}, nil, ch)
	defer cleanUp()

	fs.Create("some_dir/level1")
	seeNothing(fs, ch, "creation in level1")
}

func TestRenameFile(t *testing.T) {
	t.Skip()
	fs := newFS(t)

	fs.Create("foobar")
	ch := make(chan time.Time, 10)

	cleanUp := watchTest(fs, []string{fs.Abs("foobar")}, []string{}, ch)
	defer cleanUp()
	renameTest(fs, ch, "foobar", "baz")
	renameTest(fs, ch, "baz", "foobar")
}

func TestRenameDir(t *testing.T) {
	t.Skip()
	fs := newFS(t)

	fs.MkdirAll("foodir")
	fs.Create("foodir/foobar")
	ch := make(chan time.Time, 10)

	cleanUp := watchTest(fs, []string{fs.Abs("foodir/foobar")}, []string{}, ch)
	defer cleanUp()
	renameTest(fs, ch, "foodir/foobar", "baz")
	renameTest(fs, ch, "baz", "foodir/foobar")
	renameTest(fs, ch, "foodir", "bardir")
	// TODO(jmhodges): this requires a better rename system than
	// fsnotify provides or watching every dang directory in the
	// entiry absolute path.
	// renameTest(fs, ch, "bardir", "foodir")
}

func TestHiddenFilesHiddenByDefault(t *testing.T) {
	fs := newFS(t)
	fs.MkdirAll("hDir1")
	fs.Create("hDir1/.hidden")
	fs.MkdirAll("hDir2")
	fs.MkdirAll("hDir3")
	fs.Create("hDir3/.hiddenAndIgnored")
	ch := make(chan time.Time, 10)
	cleanUp := watchTest(fs,
		[]string{fs.Abs("hDir1/.hidden"), fs.Abs("hDir2")},
		[]string{fs.Abs("hDir3/.hiddenAndIgnored")},
		ch)
	defer cleanUp()

	fs.ChangeContents("hDir1/.hidden")
	seeChangeContents(fs, ch, "hDir1/.hidden")
	fs.Create("hDir2/.hidden")
	seeNothing(fs, ch, "no hidden file creation")
	fs.ChangeContents("hDir3/.hiddenAndIgnored")
	seeNothing(fs, ch, "no event for changes to hDir3/.hiddenAndIgnored")
}

func renameTest(fs *fileSystem, ch <-chan time.Time, oldpath, newpath string) {
	fs.Rename(oldpath, newpath)
	seeRename(fs, ch, oldpath, newpath)
}

func seeRename(fs *fileSystem, ch <-chan time.Time, oldpath, newpath string) {
	select {
	case <-ch:
		fs.t.Logf("successful catch of rename ('%s' -> '%s')", oldpath, newpath)
	case <-time.After(waitForMsg):
		fs.t.Errorf("did not see rename ('%s' -> '%s')", oldpath, newpath)
	}
}

func seeNothing(fs *fileSystem, ch <-chan time.Time, msg string) {
	select {
	case <-ch:
		fs.t.Errorf("should not have seen anything but saw: %s", msg)
	case <-time.After(waitForMsg):
		fs.t.Logf("successfully saw nothing for '%s'", msg)
	}
}

func seeCreation(fs *fileSystem, ch <-chan time.Time, path string) {
	select {
	case <-ch:
		fs.t.Logf("successful catch of creation of '%s'", path)

	case <-time.After(waitForMsg):
		fs.t.Errorf("did not see creation of '%s'", path)

	}
}

func seeChangeContents(fs *fileSystem, ch <-chan time.Time, path string) {
	select {
	case <-ch:
		fs.t.Logf("successful catch of first event (MODIFY|ATTRIB) for changing contents of '%s'", path)
	case <-time.After(waitForMsg):
		fs.t.Errorf("did not see content change of '%s'", path)
	}
	select {
	case <-ch:
		fs.t.Logf("successful catch of second event (MODIFY) for changing contents of '%s'", path)
	case <-time.After(waitForMsg):
		fs.t.Errorf("did not see content change of '%s'", path)
	}
}

func watchTest(fs *fileSystem, inputPaths, ignoredPaths []string, cmdCh chan<- time.Time) func() {
	w, err := watch(inputPaths, ignoredPaths, cmdCh)
	if err != nil {
		fs.t.Fatalf("unable to run watch: %#v", err)
		return func() {}
	}
	return func() {
		w.Close()
		fs.Close()
	}
}

func newFS(t *testing.T) *fileSystem {
	name, err := ioutil.TempDir("", "justrun_tests_")
	if err != nil {
		t.Fatalf("unable to create temporary directory")
	}
	return &fileSystem{name: name, t: t}
}

type fileSystem struct {
	name string
	t    *testing.T
}

func (fs *fileSystem) Create(path string) {
	fullName := filepath.Join(fs.name, path)
	// O_SYNC is important
	f, err := os.OpenFile(fullName, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_SYNC, 0666)
	if err != nil {
		fs.t.Fatalf("unable to create '%s' in '%s': %#v", path, fs.name, err)
	}
	f.Close()
}

func (fs *fileSystem) MkdirAll(path string) {
	fullName := filepath.Join(fs.name, path)
	err := os.MkdirAll(fullName, 0700)
	if err != nil {
		fs.t.Fatal("unable to create directory '%s' in '%s': %#v", path, fs.name, err)
	}
}

func (fs *fileSystem) Rename(oldpath, newpath string) {
	err := os.Rename(filepath.Join(fs.name, oldpath), filepath.Join(fs.name, newpath))
	if err != nil {
		fs.t.Fatalf("unable to rename '%s' to '%s' in '%s'", oldpath, newpath, fs.name)
	}
}

func (fs *fileSystem) Abs(path string) string {
	return filepath.Join(fs.name, path)
}

func (fs *fileSystem) RemoveAll(path string) {
	if err := os.RemoveAll(path); err != nil {
		fs.t.Fatalf("unable to delete '%s': %s", path, err)
	}
}

func (fs *fileSystem) ChangeContents(path string) {
	fullName := filepath.Join(fs.name, path)
	b := make([]byte, 16)
	_, err := rand.Read(b)
	if err != nil {
		fs.t.Fatalf("unable to get random data to change the contents of '%s': %s", path, err)
	}

	f, err := os.OpenFile(fullName, os.O_WRONLY|os.O_SYNC|os.O_TRUNC, 0666)
	if err != nil {
		fs.t.Fatalf("unable to open '%s' to change its contents: %s", path, err)
	}
	defer f.Close()
	n, err := f.Write(b)
	if err != nil {
		fs.t.Fatalf("unable to write new contents to '%s': %s", path, err)
	}
	if n < len(b) {
		fs.t.Fatalf("unable to write all contents to '%s'", path)
	}
}

func (fs *fileSystem) Close() {
	err := os.RemoveAll(fs.name)
	if err != nil {
		fs.t.Errorf("unable to delete directory '%s'", fs.name)
	}
}
<commit_msg>rename some test dirs for niceness<commit_after>// These will all be very flaky because they are dependent on actual
// filesystems.
package main

import (
	"crypto/rand"
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
	"time"
)

const waitForMsg = 2 * time.Second

// Slow in the success case
func TestNoWatchingCreation(t *testing.T) {
	fs := newFS(t)
	fs.Create("foobar")
	ch := make(chan time.Time, 10)
	cleanUp := watchTest(fs, []string{fs.Abs("foobar")}, []string{}, ch)
	defer cleanUp()
	fs.Create("baz")
	seeNothing(fs, ch, "creation of baz")
}

// Slow in the success case
func TestSimpleWatch(t *testing.T) {
	fs := newFS(t)
	fs.Create("foobar")
	ch := make(chan time.Time, 10)
	cleanUp := watchTest(fs, []string{fs.Abs("foobar")}, []string{fs.Abs("baz")}, ch)
	defer cleanUp()
	fs.ChangeContents("foobar")
	seeChangeContents(fs, ch, "foobar")
	fs.Create("baz")
	seeNothing(fs, ch, "creation of baz")
}

func TestSimpleDirWatch(t *testing.T) {
	fs := newFS(t)
	fs.MkdirAll("simpleDir1")
	ch := make(chan time.Time, 10)
	cleanUp := watchTest(fs, []string{fs.Abs("simpleDir1")}, []string{}, ch)
	defer cleanUp()

	fs.Create("simpleDir1/foobar")
	seeCreation(fs, ch, "simpleDir1/foobar")
}

func TestCurrentDirWorks(t *testing.T) {
	fs := newFS(t)
	fs.Create("foobar")
	ch := make(chan time.Time, 10)
	cleanUp := watchTest(fs, []string{fs.Abs(".")}, nil, ch)
	defer cleanUp()
	fs.ChangeContents("foobar")
	seeChangeContents(fs, ch, "foobar")
	fs.Create("baz")
	seeCreation(fs, ch, "baz")
}

// Slow in the success case
func TestIgnoredDir(t *testing.T) {
	fs := newFS(t)
	fs.Create("foobar")
	fs.MkdirAll("existdir/quuxdir")
	ch := make(chan time.Time, 10)
	cleanUp := watchTest(fs, []string{fs.Abs(".")},
		[]string{
			fs.Abs("bardir"),
			fs.Abs("existdir"),
		},
		ch)
	defer cleanUp()

	fs.MkdirAll("bardir")
	fs.Create("bardir/barfile")
	fs.RemoveAll("bardir")
	fs.Create("existdir/level1")
	fs.Create("existdir/quuxdir/level2")
	fs.ChangeContents("existdir/level1")
	fs.ChangeContents("existdir/quuxdir/level2")
	seeNothing(fs, ch, "some ignored operations")
}

// Slow in the success case
func TestIgnoredDirOverlap(t *testing.T) {
	fs := newFS(t)
	fs.Create("foobar")
	fs.MkdirAll("existdir/quuxdir")
	ch := make(chan time.Time, 10)
	// The existdir and existdir/quuxdir cases seem silly but can
	// happen accidentally in shell globbing. Better to be consistent
	// about it.
	cleanUp := watchTest(fs,
		[]string{
			fs.Abs("."),
			fs.Abs("bardir"),
			fs.Abs("existdir/quuxdir"),
		},
		[]string{
			fs.Abs("bardir"),
			fs.Abs("existdir/quuxdir"),
		},
		ch)
	defer cleanUp()

	fs.MkdirAll("bardir")
	fs.Create("bardir/barfile")
	fs.Create("existdir/level1")
	fs.Create("existdir/quuxdir/level2")
	fs.ChangeContents("existdir/level1")
	fs.ChangeContents("existdir/quuxdir/level2")

	seeNothing(fs, ch, "some ignored operations")
}

func TestNoSubdirRecursionWithoutGlobs(t *testing.T) {
	fs := newFS(t)
	fs.MkdirAll("some_dir")
	ch := make(chan time.Time, 10)
	cleanUp := watchTest(fs, []string{fs.Abs(".")}, nil, ch)
	defer cleanUp()

	fs.Create("some_dir/level1")
	seeNothing(fs, ch, "creation in level1")
}

func TestRenameFile(t *testing.T) {
	t.Skip()
	fs := newFS(t)

	fs.Create("foobar")
	ch := make(chan time.Time, 10)

	cleanUp := watchTest(fs, []string{fs.Abs("foobar")}, []string{}, ch)
	defer cleanUp()
	renameTest(fs, ch, "foobar", "baz")
	renameTest(fs, ch, "baz", "foobar")
}

func TestRenameDir(t *testing.T) {
	t.Skip()
	fs := newFS(t)

	fs.MkdirAll("foodir")
	fs.Create("foodir/foobar")
	ch := make(chan time.Time, 10)

	cleanUp := watchTest(fs, []string{fs.Abs("foodir/foobar")}, []string{}, ch)
	defer cleanUp()
	renameTest(fs, ch, "foodir/foobar", "baz")
	renameTest(fs, ch, "baz", "foodir/foobar")
	renameTest(fs, ch, "foodir", "bardir")
	// TODO(jmhodges): this requires a better rename system than
	// fsnotify provides or watching every dang directory in the
	// entiry absolute path.
	// renameTest(fs, ch, "bardir", "foodir")
}

func TestHiddenFilesHiddenByDefault(t *testing.T) {
	fs := newFS(t)
	fs.MkdirAll("hDir1")
	fs.Create("hDir1/.hidden")
	fs.MkdirAll("hDir2")
	fs.MkdirAll("hDir3")
	fs.Create("hDir3/.hiddenAndIgnored")
	ch := make(chan time.Time, 10)
	cleanUp := watchTest(fs,
		[]string{fs.Abs("hDir1/.hidden"), fs.Abs("hDir2")},
		[]string{fs.Abs("hDir3/.hiddenAndIgnored")},
		ch)
	defer cleanUp()

	fs.ChangeContents("hDir1/.hidden")
	seeChangeContents(fs, ch, "hDir1/.hidden")
	fs.Create("hDir2/.hidden")
	seeNothing(fs, ch, "no hidden file creation")
	fs.ChangeContents("hDir3/.hiddenAndIgnored")
	seeNothing(fs, ch, "no event for changes to hDir3/.hiddenAndIgnored")
}

func renameTest(fs *fileSystem, ch <-chan time.Time, oldpath, newpath string) {
	fs.Rename(oldpath, newpath)
	seeRename(fs, ch, oldpath, newpath)
}

func seeRename(fs *fileSystem, ch <-chan time.Time, oldpath, newpath string) {
	select {
	case <-ch:
		fs.t.Logf("successful catch of rename ('%s' -> '%s')", oldpath, newpath)
	case <-time.After(waitForMsg):
		fs.t.Errorf("did not see rename ('%s' -> '%s')", oldpath, newpath)
	}
}

func seeNothing(fs *fileSystem, ch <-chan time.Time, msg string) {
	select {
	case <-ch:
		fs.t.Errorf("should not have seen anything but saw: %s", msg)
	case <-time.After(waitForMsg):
		fs.t.Logf("successfully saw nothing for '%s'", msg)
	}
}

func seeCreation(fs *fileSystem, ch <-chan time.Time, path string) {
	select {
	case <-ch:
		fs.t.Logf("successful catch of creation of '%s'", path)

	case <-time.After(waitForMsg):
		fs.t.Errorf("did not see creation of '%s'", path)

	}
}

func seeChangeContents(fs *fileSystem, ch <-chan time.Time, path string) {
	select {
	case <-ch:
		fs.t.Logf("successful catch of first event (MODIFY|ATTRIB) for changing contents of '%s'", path)
	case <-time.After(waitForMsg):
		fs.t.Errorf("did not see content change of '%s'", path)
	}
	select {
	case <-ch:
		fs.t.Logf("successful catch of second event (MODIFY) for changing contents of '%s'", path)
	case <-time.After(waitForMsg):
		fs.t.Errorf("did not see content change of '%s'", path)
	}
}

func watchTest(fs *fileSystem, inputPaths, ignoredPaths []string, cmdCh chan<- time.Time) func() {
	w, err := watch(inputPaths, ignoredPaths, cmdCh)
	if err != nil {
		fs.t.Fatalf("unable to run watch: %#v", err)
		return func() {}
	}
	return func() {
		w.Close()
		fs.Close()
	}
}

func newFS(t *testing.T) *fileSystem {
	name, err := ioutil.TempDir("", "justrun_tests_")
	if err != nil {
		t.Fatalf("unable to create temporary directory")
	}
	return &fileSystem{name: name, t: t}
}

type fileSystem struct {
	name string
	t    *testing.T
}

func (fs *fileSystem) Create(path string) {
	fullName := filepath.Join(fs.name, path)
	// O_SYNC is important
	f, err := os.OpenFile(fullName, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_SYNC, 0666)
	if err != nil {
		fs.t.Fatalf("unable to create '%s' in '%s': %#v", path, fs.name, err)
	}
	f.Close()
}

func (fs *fileSystem) MkdirAll(path string) {
	fullName := filepath.Join(fs.name, path)
	err := os.MkdirAll(fullName, 0700)
	if err != nil {
		fs.t.Fatal("unable to create directory '%s' in '%s': %#v", path, fs.name, err)
	}
}

func (fs *fileSystem) Rename(oldpath, newpath string) {
	err := os.Rename(filepath.Join(fs.name, oldpath), filepath.Join(fs.name, newpath))
	if err != nil {
		fs.t.Fatalf("unable to rename '%s' to '%s' in '%s'", oldpath, newpath, fs.name)
	}
}

func (fs *fileSystem) Abs(path string) string {
	return filepath.Join(fs.name, path)
}

func (fs *fileSystem) RemoveAll(path string) {
	if err := os.RemoveAll(path); err != nil {
		fs.t.Fatalf("unable to delete '%s': %s", path, err)
	}
}

func (fs *fileSystem) ChangeContents(path string) {
	fullName := filepath.Join(fs.name, path)
	b := make([]byte, 16)
	_, err := rand.Read(b)
	if err != nil {
		fs.t.Fatalf("unable to get random data to change the contents of '%s': %s", path, err)
	}

	f, err := os.OpenFile(fullName, os.O_WRONLY|os.O_SYNC|os.O_TRUNC, 0666)
	if err != nil {
		fs.t.Fatalf("unable to open '%s' to change its contents: %s", path, err)
	}
	defer f.Close()
	n, err := f.Write(b)
	if err != nil {
		fs.t.Fatalf("unable to write new contents to '%s': %s", path, err)
	}
	if n < len(b) {
		fs.t.Fatalf("unable to write all contents to '%s'", path)
	}
}

func (fs *fileSystem) Close() {
	err := os.RemoveAll(fs.name)
	if err != nil {
		fs.t.Errorf("unable to delete directory '%s'", fs.name)
	}
}
<|endoftext|>


<commit_before>package el_min_gae

import (
	"html/template"
	"net/http"
	"strings"
    "fmt"
)

var (
	templates = make(map[string]*template.Template)
)

func init() {
	templateInit()
	http.HandleFunc("/", rootHandler)
}

func templateInit() {
    load("demo")
}

func rootHandler(w http.ResponseWriter, r *http.Request) {
    if r.URL.Path == "/" {
	    t := get("demo")
	    t.ExecuteTemplate(w, "root", nil)
    } else {
        w.Write([]byte(fmt.Sprintf("I'd rather be at %s", r.URL.Path)))
    }
}

func get(name string) *template.Template {
	if template, ok := templates[name]; ok {
		return template
	}
	load(name)
	return templates[name]
}

func load(name string) {
	fields := strings.Fields(name)
	shortname := fields[len(fields) - 1]
	template := template.New(shortname)
	for _, name := range fields {
		if !strings.HasSuffix(name, ".html") {
			name += ".html"
		}
		if _, err := template.ParseFiles(name); err != nil {
			panic(err)
		}
	}
	templates[shortname] = template
}
<commit_msg>forgot to run :Fmt<commit_after>package el_min_gae

import (
	"fmt"
	"html/template"
	"net/http"
	"strings"
)

var (
	templates = make(map[string]*template.Template)
)

func init() {
	templateInit()
	http.HandleFunc("/", rootHandler)
}

func templateInit() {
	load("demo")
}

func rootHandler(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path == "/" {
		t := get("demo")
		t.ExecuteTemplate(w, "root", nil)
	} else {
		w.Write([]byte(fmt.Sprintf("I'd rather be at %s", r.URL.Path)))
	}
}

func get(name string) *template.Template {
	if template, ok := templates[name]; ok {
		return template
	}
	load(name)
	return templates[name]
}

func load(name string) {
	fields := strings.Fields(name)
	shortname := fields[len(fields)-1]
	template := template.New(shortname)
	for _, name := range fields {
		if !strings.HasSuffix(name, ".html") {
			name += ".html"
		}
		if _, err := template.ParseFiles(name); err != nil {
			panic(err)
		}
	}
	templates[shortname] = template
}
<|endoftext|>


<commit_before>package integration

import (
	"net/http/httptest"
	"os"
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	vegeta "github.com/tsenart/vegeta/lib"
)

const routerLatencyThreshold = 20 * time.Millisecond

var _ = Describe("Performance", func() {

	Context("two healthy backends", func() {
		var (
			backend1 *httptest.Server
			backend2 *httptest.Server
		)

		BeforeEach(func() {
			backend1 = startSimpleBackend("backend 1")
			backend2 = startSimpleBackend("backend 2")
			addBackend("backend-1", backend1.URL)
			addBackend("backend-2", backend2.URL)
			addBackendRoute("/one", "backend-1")
			addBackendRoute("/two", "backend-2")
			reloadRoutes()
		})
		AfterEach(func() {
			backend1.Close()
			backend2.Close()
		})

		It("should not significantly increase latency", func() {
			assertPerformantRouter(backend1, backend2)
		})

		Describe("when the routes are being reloaded repeatedly", func() {
			It("should not significantly increase latency", func() {
				stopCh := make(chan struct{})
				defer close(stopCh)
				go func() {
					ticker := time.NewTicker(100 * time.Millisecond)
					defer ticker.Stop()
					select {
					case <-stopCh:
						return
					case <-ticker.C:
						reloadRoutes()
					}
				}()

				assertPerformantRouter(backend1, backend2)
			})
		})

		Describe("one slow backend hit separately", func() {
			It("should not significantly increase latency", func() {
				slowBackend := startTarpitBackend(time.Second)
				defer slowBackend.Close()
				addBackend("backend-slow", slowBackend.URL)
				addBackendRoute("/slow", "backend-slow")
				reloadRoutes()

				attacker := startVegetaLoad(routerURL("/slow"))
				defer attacker.Stop()

				assertPerformantRouter(backend1, backend2)
			})
		})

		Describe("one downed backend hit separately", func() {
			It("should not significantly increase latency", func() {
				addBackend("backend-down", "http://localhost:3162/")
				addBackendRoute("/down", "backend-down")
				reloadRoutes()

				attacker := startVegetaLoad(routerURL("/down"))
				defer attacker.Stop()

				assertPerformantRouter(backend1, backend2)
			})
		})

		if os.Getenv("RUN_ULIMIT_DEPENDENT_TESTS") != "" {
			Describe("high request throughput", func() {
				It("should not significantly increase latency", func() {
					assertPerformantRouter(backend1, backend2, 3000)
				})
			})
		}
	})

	Describe("many concurrent (slow) connectons", func() {
		if os.Getenv("RUN_ULIMIT_DEPENDENT_TESTS") != "" {
			var (
				backend1 *httptest.Server
				backend2 *httptest.Server
			)

			BeforeEach(func() {
				backend1 = startTarpitBackend(time.Second)
				backend2 = startTarpitBackend(time.Second)
				addBackend("backend-1", backend1.URL)
				addBackend("backend-2", backend2.URL)
				addBackendRoute("/one", "backend-1")
				addBackendRoute("/two", "backend-2")
				reloadRoutes()
			})
			AfterEach(func() {
				backend1.Close()
				backend2.Close()
			})

			It("should not significantly increase latency", func() {
				assertPerformantRouter(backend1, backend2, 1000)
			})
		} else {
			PIt("high throughput requires elevated ulimit")
		}
	})
})

func assertPerformantRouter(backend1, backend2 *httptest.Server, optionalRate ...uint64) {
	var rate uint64 = 50
	if len(optionalRate) > 0 {
		rate = optionalRate[0]
	}
	directResultsCh := startVegetaAttack([]string{backend1.URL + "/one", backend2.URL + "/two"}, rate)
	routerResultsCh := startVegetaAttack([]string{routerURL("/one"), routerURL("/two")}, rate)

	directResults := <-directResultsCh
	routerResults := <-routerResultsCh

	Expect(routerResults.Requests).To(Equal(directResults.Requests))
	Expect(routerResults.Success).To(Equal(1.0)) // 100% success rate
	Expect(directResults.Success).To(Equal(1.0)) // 100% success rate

	Expect(routerResults.Latencies.Mean).To(BeNumerically("~", directResults.Latencies.Mean, routerLatencyThreshold))
	Expect(routerResults.Latencies.P95).To(BeNumerically("~", directResults.Latencies.P95, routerLatencyThreshold))
	Expect(routerResults.Latencies.P99).To(BeNumerically("~", directResults.Latencies.P99, routerLatencyThreshold*2))
	Expect(routerResults.Latencies.Max).To(BeNumerically("~", directResults.Latencies.Max, routerLatencyThreshold*2))
}

func startVegetaAttack(targetURLs []string, rate uint64) chan *vegeta.Metrics {
	targets := make([]*vegeta.Target, 0, len(targetURLs))
	for _, url := range targetURLs {
		targets = append(targets, &vegeta.Target{
			Method: "GET",
			URL:    url,
		})
	}
	targeter := vegeta.NewStaticTargeter(targets...)
	metricsChan := make(chan *vegeta.Metrics, 1)
	go vegetaAttack(targeter, rate, metricsChan)
	return metricsChan
}

func vegetaAttack(targeter vegeta.Targeter, rate uint64, metricsChan chan *vegeta.Metrics) {
	attacker := vegeta.NewAttacker()

	var results vegeta.Results
	for res := range attacker.Attack(targeter, rate, 10*time.Second) {
		results = append(results, res)
	}

	metrics := vegeta.NewMetrics(results)
	metricsChan <- metrics
}

func startVegetaLoad(targetURL string) *vegeta.Attacker {
	attacker := vegeta.NewAttacker()
	targetter := vegeta.NewStaticTargeter(&vegeta.Target{Method: "GET", URL: targetURL})
	resCh := attacker.Attack(targetter, 50, time.Minute)

	// Consume and discard results.  Without this, all the workers will block sending
	// to the channel - https://github.com/tsenart/vegeta/blob/v5.4.0/lib/attack.go#L143
	go func() {
		for _ = range resCh {
			//discard
		}
	}()
	return attacker
}
<commit_msg>Simplify `for range` block<commit_after>package integration

import (
	"net/http/httptest"
	"os"
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	vegeta "github.com/tsenart/vegeta/lib"
)

const routerLatencyThreshold = 20 * time.Millisecond

var _ = Describe("Performance", func() {

	Context("two healthy backends", func() {
		var (
			backend1 *httptest.Server
			backend2 *httptest.Server
		)

		BeforeEach(func() {
			backend1 = startSimpleBackend("backend 1")
			backend2 = startSimpleBackend("backend 2")
			addBackend("backend-1", backend1.URL)
			addBackend("backend-2", backend2.URL)
			addBackendRoute("/one", "backend-1")
			addBackendRoute("/two", "backend-2")
			reloadRoutes()
		})
		AfterEach(func() {
			backend1.Close()
			backend2.Close()
		})

		It("should not significantly increase latency", func() {
			assertPerformantRouter(backend1, backend2)
		})

		Describe("when the routes are being reloaded repeatedly", func() {
			It("should not significantly increase latency", func() {
				stopCh := make(chan struct{})
				defer close(stopCh)
				go func() {
					ticker := time.NewTicker(100 * time.Millisecond)
					defer ticker.Stop()
					select {
					case <-stopCh:
						return
					case <-ticker.C:
						reloadRoutes()
					}
				}()

				assertPerformantRouter(backend1, backend2)
			})
		})

		Describe("one slow backend hit separately", func() {
			It("should not significantly increase latency", func() {
				slowBackend := startTarpitBackend(time.Second)
				defer slowBackend.Close()
				addBackend("backend-slow", slowBackend.URL)
				addBackendRoute("/slow", "backend-slow")
				reloadRoutes()

				attacker := startVegetaLoad(routerURL("/slow"))
				defer attacker.Stop()

				assertPerformantRouter(backend1, backend2)
			})
		})

		Describe("one downed backend hit separately", func() {
			It("should not significantly increase latency", func() {
				addBackend("backend-down", "http://localhost:3162/")
				addBackendRoute("/down", "backend-down")
				reloadRoutes()

				attacker := startVegetaLoad(routerURL("/down"))
				defer attacker.Stop()

				assertPerformantRouter(backend1, backend2)
			})
		})

		if os.Getenv("RUN_ULIMIT_DEPENDENT_TESTS") != "" {
			Describe("high request throughput", func() {
				It("should not significantly increase latency", func() {
					assertPerformantRouter(backend1, backend2, 3000)
				})
			})
		}
	})

	Describe("many concurrent (slow) connectons", func() {
		if os.Getenv("RUN_ULIMIT_DEPENDENT_TESTS") != "" {
			var (
				backend1 *httptest.Server
				backend2 *httptest.Server
			)

			BeforeEach(func() {
				backend1 = startTarpitBackend(time.Second)
				backend2 = startTarpitBackend(time.Second)
				addBackend("backend-1", backend1.URL)
				addBackend("backend-2", backend2.URL)
				addBackendRoute("/one", "backend-1")
				addBackendRoute("/two", "backend-2")
				reloadRoutes()
			})
			AfterEach(func() {
				backend1.Close()
				backend2.Close()
			})

			It("should not significantly increase latency", func() {
				assertPerformantRouter(backend1, backend2, 1000)
			})
		} else {
			PIt("high throughput requires elevated ulimit")
		}
	})
})

func assertPerformantRouter(backend1, backend2 *httptest.Server, optionalRate ...uint64) {
	var rate uint64 = 50
	if len(optionalRate) > 0 {
		rate = optionalRate[0]
	}
	directResultsCh := startVegetaAttack([]string{backend1.URL + "/one", backend2.URL + "/two"}, rate)
	routerResultsCh := startVegetaAttack([]string{routerURL("/one"), routerURL("/two")}, rate)

	directResults := <-directResultsCh
	routerResults := <-routerResultsCh

	Expect(routerResults.Requests).To(Equal(directResults.Requests))
	Expect(routerResults.Success).To(Equal(1.0)) // 100% success rate
	Expect(directResults.Success).To(Equal(1.0)) // 100% success rate

	Expect(routerResults.Latencies.Mean).To(BeNumerically("~", directResults.Latencies.Mean, routerLatencyThreshold))
	Expect(routerResults.Latencies.P95).To(BeNumerically("~", directResults.Latencies.P95, routerLatencyThreshold))
	Expect(routerResults.Latencies.P99).To(BeNumerically("~", directResults.Latencies.P99, routerLatencyThreshold*2))
	Expect(routerResults.Latencies.Max).To(BeNumerically("~", directResults.Latencies.Max, routerLatencyThreshold*2))
}

func startVegetaAttack(targetURLs []string, rate uint64) chan *vegeta.Metrics {
	targets := make([]*vegeta.Target, 0, len(targetURLs))
	for _, url := range targetURLs {
		targets = append(targets, &vegeta.Target{
			Method: "GET",
			URL:    url,
		})
	}
	targeter := vegeta.NewStaticTargeter(targets...)
	metricsChan := make(chan *vegeta.Metrics, 1)
	go vegetaAttack(targeter, rate, metricsChan)
	return metricsChan
}

func vegetaAttack(targeter vegeta.Targeter, rate uint64, metricsChan chan *vegeta.Metrics) {
	attacker := vegeta.NewAttacker()

	var results vegeta.Results
	for res := range attacker.Attack(targeter, rate, 10*time.Second) {
		results = append(results, res)
	}

	metrics := vegeta.NewMetrics(results)
	metricsChan <- metrics
}

func startVegetaLoad(targetURL string) *vegeta.Attacker {
	attacker := vegeta.NewAttacker()
	targetter := vegeta.NewStaticTargeter(&vegeta.Target{Method: "GET", URL: targetURL})
	resCh := attacker.Attack(targetter, 50, time.Minute)

	// Consume and discard results.  Without this, all the workers will block sending
	// to the channel - https://github.com/tsenart/vegeta/blob/v5.4.0/lib/attack.go#L143
	go func() {
		for range resCh {
			//discard
		}
	}()
	return attacker
}
<|endoftext|>


<commit_before>// Code generated by 'yaegi extract github.com/kenshaw/snaker'. DO NOT EDIT.

package internal

import (
	"github.com/kenshaw/snaker"
	"reflect"
)

func init() {
	Symbols["github.com/kenshaw/snaker/snaker"] = map[string]reflect.Value{
		// function, constant and variable definitions
		"CamelToSnake":              reflect.ValueOf(snaker.CamelToSnake),
		"CamelToSnakeIdentifier":    reflect.ValueOf(snaker.CamelToSnakeIdentifier),
		"CommonInitialisms":         reflect.ValueOf(snaker.CommonInitialisms),
		"DefaultInitialisms":        reflect.ValueOf(&snaker.DefaultInitialisms).Elem(),
		"ForceCamelIdentifier":      reflect.ValueOf(snaker.ForceCamelIdentifier),
		"ForceLowerCamelIdentifier": reflect.ValueOf(snaker.ForceLowerCamelIdentifier),
		"IsIdentifierChar":          reflect.ValueOf(snaker.IsIdentifierChar),
		"IsInitialism":              reflect.ValueOf(snaker.IsInitialism),
		"New":                       reflect.ValueOf(snaker.New),
		"Peek":                      reflect.ValueOf(snaker.Peek),
		"SnakeToCamel":              reflect.ValueOf(snaker.SnakeToCamel),
		"SnakeToCamelIdentifier":    reflect.ValueOf(snaker.SnakeToCamelIdentifier),
		"ToIdentifier":              reflect.ValueOf(snaker.ToIdentifier),

		// type definitions
		"Initialisms": reflect.ValueOf((*snaker.Initialisms)(nil)),
	}
}
<commit_msg>Updating yaegi internals<commit_after>// Code generated by 'yaegi extract github.com/kenshaw/snaker'. DO NOT EDIT.

package internal

import (
	"github.com/kenshaw/snaker"
	"reflect"
)

func init() {
	Symbols["github.com/kenshaw/snaker/snaker"] = map[string]reflect.Value{
		// function, constant and variable definitions
		"CamelToSnake":              reflect.ValueOf(snaker.CamelToSnake),
		"CamelToSnakeIdentifier":    reflect.ValueOf(snaker.CamelToSnakeIdentifier),
		"CommonInitialisms":         reflect.ValueOf(snaker.CommonInitialisms),
		"DefaultInitialisms":        reflect.ValueOf(&snaker.DefaultInitialisms).Elem(),
		"ForceCamelIdentifier":      reflect.ValueOf(snaker.ForceCamelIdentifier),
		"ForceLowerCamelIdentifier": reflect.ValueOf(snaker.ForceLowerCamelIdentifier),
		"IsIdentifierChar":          reflect.ValueOf(snaker.IsIdentifierChar),
		"IsInitialism":              reflect.ValueOf(snaker.IsInitialism),
		"New":                       reflect.ValueOf(snaker.New),
		"NewDefaultInitialisms":     reflect.ValueOf(snaker.NewDefaultInitialisms),
		"Peek":                      reflect.ValueOf(snaker.Peek),
		"SnakeToCamel":              reflect.ValueOf(snaker.SnakeToCamel),
		"SnakeToCamelIdentifier":    reflect.ValueOf(snaker.SnakeToCamelIdentifier),
		"ToIdentifier":              reflect.ValueOf(snaker.ToIdentifier),

		// type definitions
		"Initialisms": reflect.ValueOf((*snaker.Initialisms)(nil)),
	}
}
<|endoftext|>


<commit_before>/*
	Example REST server

	When run can be opened in a webbrowser:
	http://localhost:3000/wd/ for index, showing all entries as logic of the Index function specifies
	http://localhost:3000/wd/We get full string for index We (other indices from map also possible)
*/
package main

import (
	"fmt"
	"http"
	"log"
	"github.com/Kissaki/rest.go"
)

var wdmap = map[string]string{
			"Mo":"Monday",
			"Tu":"Tuesday",
			"We": "Wednesday",
			"Th": "Thursday",
			"Fr": "Friday",
			"Sa": "Saturday",
			"Su": "Sunday",

		}

type Weekdays struct {
	wd map[string]string
}
func (wd *Weekdays) Index(resp http.ResponseWriter) {
	for i, v := range wd.wd {
		fmt.Fprintf(resp, "%s: %s
\n", i, v)
	}
}
func (wd *Weekdays) Find(resp http.ResponseWriter, id string) {
	if full, ok := wd.wd[id]; ok {
		fmt.Fprintf(resp, full)
	}
}

func main() {
	log.Println("Starting Server")
	address := "127.0.0.1:3000"

	var wd = new(Weekdays)
	wd.wd = wdmap
	rest.Resource("wd", wd)

	if err := http.ListenAndServe(address, nil); err != nil {
		log.Fatalln(err)
	}
}

<commit_msg>gofmt<commit_after>/*
	Example REST server

	When run can be opened in a webbrowser:
	http://localhost:3000/wd/ for index, showing all entries as logic of the Index function specifies
	http://localhost:3000/wd/We get full string for index We (other indices from map also possible)
*/
package main

import (
	"fmt"
	"http"
	"log"
	"github.com/Kissaki/rest.go"
)

var wdmap = map[string]string{
	"Mo": "Monday",
	"Tu": "Tuesday",
	"We": "Wednesday",
	"Th": "Thursday",
	"Fr": "Friday",
	"Sa": "Saturday",
	"Su": "Sunday",
}

type Weekdays struct {
	wd map[string]string
}

func (wd *Weekdays) Index(resp http.ResponseWriter) {
	for i, v := range wd.wd {
		fmt.Fprintf(resp, "%s: %s
\n", i, v)
	}
}
func (wd *Weekdays) Find(resp http.ResponseWriter, id string) {
	if full, ok := wd.wd[id]; ok {
		fmt.Fprintf(resp, full)
	}
}

func main() {
	log.Println("Starting Server")
	address := "127.0.0.1:3000"

	var wd = new(Weekdays)
	wd.wd = wdmap
	rest.Resource("wd", wd)

	if err := http.ListenAndServe(address, nil); err != nil {
		log.Fatalln(err)
	}
}
<|endoftext|>


<commit_before>package daemon

import (
	"context"
	"net"
	"os"

	"github.com/pkg/errors"
	"google.golang.org/grpc"

	"github.com/datawire/ambassador/internal/pkg/edgectl"
	"github.com/datawire/ambassador/pkg/api/edgectl/rpc"
	"github.com/datawire/ambassador/pkg/supervisor"
)

var Help = `The Edge Control Daemon is a long-lived background component that manages
connections and network state.

Launch the Edge Control Daemon:
    sudo edgectl daemon

Examine the Daemon's log output in
    ` + edgectl.Logfile + `
to troubleshoot problems.
`

// daemon represents the state of the Edge Control Daemon
type daemon struct {
	network    Resource
	cluster    *KCluster
	bridge     Resource
	trafficMgr *TrafficManager
	intercepts []*Intercept
	dns        string
	fallback   string
}

// RunAsDaemon is the main function when executing as the daemon
func RunAsDaemon(dns, fallback string) error {
	if os.Geteuid() != 0 {
		return errors.New("edgectl daemon must run as root")
	}

	d := &daemon{dns: dns, fallback: fallback}

	sup := supervisor.WithContext(context.Background())
	sup.Logger = SetUpLogging()
	sup.Supervise(&supervisor.Worker{
		Name: "daemon",
		Work: d.runGRPCService,
	})
	sup.Supervise(&supervisor.Worker{
		Name:     "signal",
		Requires: []string{"daemon"},
		Work:     WaitForSignal,
	})
	sup.Supervise(&supervisor.Worker{
		Name:     "setup",
		Requires: []string{"daemon"},
		Work: func(p *supervisor.Process) error {
			if err := d.MakeNetOverride(p); err != nil {
				return err
			}
			p.Ready()
			return nil
		},
	})

	sup.Logger.Printf("---")
	sup.Logger.Printf("Edge Control daemon %s starting...", edgectl.DisplayVersion())
	sup.Logger.Printf("PID is %d", os.Getpid())
	runErrors := sup.Run()

	sup.Logger.Printf("")
	if len(runErrors) > 0 {
		sup.Logger.Printf("daemon has exited with %d error(s):", len(runErrors))
		for _, err := range runErrors {
			sup.Logger.Printf("- %v", err)
		}
	}
	sup.Logger.Printf("Edge Control daemon %s is done.", edgectl.DisplayVersion())
	return errors.New("edgectl daemon has exited")
}

type grcpService struct {
	s *grpc.Server
	d *daemon
	p *supervisor.Process
}

func (s *grcpService) Version(_ context.Context, _ *rpc.Empty) (*rpc.VersionResponse, error) {
	return &rpc.VersionResponse{
		APIVersion: edgectl.ApiVersion,
		Version:    edgectl.Version,
	}, nil
}

func (s *grcpService) Status(_ context.Context, _ *rpc.Empty) (*rpc.StatusResponse, error) {
	return s.d.status(s.p), nil
}

func (s *grcpService) Connect(_ context.Context, cr *rpc.ConnectRequest) (*rpc.ConnectResponse, error) {
	return s.d.connect(s.p, cr), nil
}

func (s *grcpService) Disconnect(_ context.Context, _ *rpc.Empty) (*rpc.DisconnectResponse, error) {
	return s.d.disconnect(s.p), nil
}

func (s *grcpService) AddIntercept(_ context.Context, ir *rpc.InterceptRequest) (*rpc.InterceptResponse, error) {
	return s.d.addIntercept(s.p, ir), nil
}

func (s *grcpService) RemoveIntercept(_ context.Context, rr *rpc.RemoveInterceptRequest) (*rpc.InterceptResponse, error) {
	return s.d.removeIntercept(s.p, rr.Name), nil
}

func (s *grcpService) AvailableIntercepts(_ context.Context, _ *rpc.Empty) (*rpc.AvailableInterceptsResponse, error) {
	return s.d.availableIntercepts(s.p), nil
}

func (s *grcpService) ListIntercepts(_ context.Context, _ *rpc.Empty) (*rpc.ListInterceptsResponse, error) {
	return s.d.listIntercepts(s.p), nil
}

func (s *grcpService) Pause(ctx context.Context, empty *rpc.Empty) (*rpc.PauseResponse, error) {
	return s.d.pause(s.p), nil
}

func (s *grcpService) Resume(ctx context.Context, empty *rpc.Empty) (*rpc.ResumeResponse, error) {
	return s.d.resume(s.p), nil
}

func (s *grcpService) Quit(ctx context.Context, empty *rpc.Empty) (*rpc.Empty, error) {
	// GracefulStop() must be called in a separate go routine since it will await the
	// client disconnect. That doesn't happen until this function returns.
	go s.s.GracefulStop()
	s.p.Supervisor().Shutdown()
	return &rpc.Empty{}, nil
}

func (d *daemon) runGRPCService(daemonProc *supervisor.Process) error {
	// Listen on unix domain socket
	unixListener, err := net.Listen("unix", edgectl.DaemonSocketName)
	if err != nil {
		return errors.Wrap(err, "listen")
	}
	err = os.Chmod(edgectl.DaemonSocketName, 0777)
	if err != nil {
		return errors.Wrap(err, "chmod")
	}

	grpcServer := grpc.NewServer()
	rpc.RegisterDaemonServer(grpcServer, &grcpService{
		s: grpcServer,
		d: d,
		p: daemonProc,
	})

	daemonProc.Ready()
	Notify(daemonProc, "Running")
	defer Notify(daemonProc, "Shutting down...")
	return daemonProc.DoClean(func() error {
		return errors.Wrap(grpcServer.Serve(unixListener), "gRCP server")
	}, func() error {
		grpcServer.Stop()
		return nil
	})
}

func (d *daemon) pause(p *supervisor.Process) *rpc.PauseResponse {
	r := rpc.PauseResponse{}
	switch {
	case d.network == nil:
		r.Error = rpc.PauseResponse_AlreadyPaused
	case d.cluster != nil:
		r.Error = rpc.PauseResponse_ConnectedToCluster
	default:
		if err := d.network.Close(); err != nil {
			r.Error = rpc.PauseResponse_UnexpectedPauseError
			r.ErrorText = err.Error()
			p.Logf("pause: %v", err)
		}
		d.network = nil
	}
	return &r
}

func (d *daemon) resume(p *supervisor.Process) *rpc.ResumeResponse {
	r := rpc.ResumeResponse{}
	if d.network != nil {
		if d.network.IsOkay() {
			r.Error = rpc.ResumeResponse_NotPaused
		} else {
			r.Error = rpc.ResumeResponse_ReEstablishing
		}
	} else if err := d.MakeNetOverride(p); err != nil {
		r.Error = rpc.ResumeResponse_UnexpectedResumeError
		r.ErrorText = err.Error()
		p.Logf("resume: %v", err)
	}
	return &r
}
<commit_msg>(from AES) Fix typo grcpcService => grpcService.<commit_after>package daemon

import (
	"context"
	"net"
	"os"

	"github.com/pkg/errors"
	"google.golang.org/grpc"

	"github.com/datawire/ambassador/internal/pkg/edgectl"
	"github.com/datawire/ambassador/pkg/api/edgectl/rpc"
	"github.com/datawire/ambassador/pkg/supervisor"
)

var Help = `The Edge Control Daemon is a long-lived background component that manages
connections and network state.

Launch the Edge Control Daemon:
    sudo edgectl daemon

Examine the Daemon's log output in
    ` + edgectl.Logfile + `
to troubleshoot problems.
`

// daemon represents the state of the Edge Control Daemon
type daemon struct {
	network    Resource
	cluster    *KCluster
	bridge     Resource
	trafficMgr *TrafficManager
	intercepts []*Intercept
	dns        string
	fallback   string
}

// RunAsDaemon is the main function when executing as the daemon
func RunAsDaemon(dns, fallback string) error {
	if os.Geteuid() != 0 {
		return errors.New("edgectl daemon must run as root")
	}

	d := &daemon{dns: dns, fallback: fallback}

	sup := supervisor.WithContext(context.Background())
	sup.Logger = SetUpLogging()
	sup.Supervise(&supervisor.Worker{
		Name: "daemon",
		Work: d.runGRPCService,
	})
	sup.Supervise(&supervisor.Worker{
		Name:     "signal",
		Requires: []string{"daemon"},
		Work:     WaitForSignal,
	})
	sup.Supervise(&supervisor.Worker{
		Name:     "setup",
		Requires: []string{"daemon"},
		Work: func(p *supervisor.Process) error {
			if err := d.MakeNetOverride(p); err != nil {
				return err
			}
			p.Ready()
			return nil
		},
	})

	sup.Logger.Printf("---")
	sup.Logger.Printf("Edge Control daemon %s starting...", edgectl.DisplayVersion())
	sup.Logger.Printf("PID is %d", os.Getpid())
	runErrors := sup.Run()

	sup.Logger.Printf("")
	if len(runErrors) > 0 {
		sup.Logger.Printf("daemon has exited with %d error(s):", len(runErrors))
		for _, err := range runErrors {
			sup.Logger.Printf("- %v", err)
		}
	}
	sup.Logger.Printf("Edge Control daemon %s is done.", edgectl.DisplayVersion())
	return errors.New("edgectl daemon has exited")
}

type grpcService struct {
	s *grpc.Server
	d *daemon
	p *supervisor.Process
}

func (s *grpcService) Version(_ context.Context, _ *rpc.Empty) (*rpc.VersionResponse, error) {
	return &rpc.VersionResponse{
		APIVersion: edgectl.ApiVersion,
		Version:    edgectl.Version,
	}, nil
}

func (s *grpcService) Status(_ context.Context, _ *rpc.Empty) (*rpc.StatusResponse, error) {
	return s.d.status(s.p), nil
}

func (s *grpcService) Connect(_ context.Context, cr *rpc.ConnectRequest) (*rpc.ConnectResponse, error) {
	return s.d.connect(s.p, cr), nil
}

func (s *grpcService) Disconnect(_ context.Context, _ *rpc.Empty) (*rpc.DisconnectResponse, error) {
	return s.d.disconnect(s.p), nil
}

func (s *grpcService) AddIntercept(_ context.Context, ir *rpc.InterceptRequest) (*rpc.InterceptResponse, error) {
	return s.d.addIntercept(s.p, ir), nil
}

func (s *grpcService) RemoveIntercept(_ context.Context, rr *rpc.RemoveInterceptRequest) (*rpc.InterceptResponse, error) {
	return s.d.removeIntercept(s.p, rr.Name), nil
}

func (s *grpcService) AvailableIntercepts(_ context.Context, _ *rpc.Empty) (*rpc.AvailableInterceptsResponse, error) {
	return s.d.availableIntercepts(s.p), nil
}

func (s *grpcService) ListIntercepts(_ context.Context, _ *rpc.Empty) (*rpc.ListInterceptsResponse, error) {
	return s.d.listIntercepts(s.p), nil
}

func (s *grpcService) Pause(ctx context.Context, empty *rpc.Empty) (*rpc.PauseResponse, error) {
	return s.d.pause(s.p), nil
}

func (s *grpcService) Resume(ctx context.Context, empty *rpc.Empty) (*rpc.ResumeResponse, error) {
	return s.d.resume(s.p), nil
}

func (s *grpcService) Quit(ctx context.Context, empty *rpc.Empty) (*rpc.Empty, error) {
	// GracefulStop() must be called in a separate go routine since it will await the
	// client disconnect. That doesn't happen until this function returns.
	go s.s.GracefulStop()
	s.p.Supervisor().Shutdown()
	return &rpc.Empty{}, nil
}

func (d *daemon) runGRPCService(daemonProc *supervisor.Process) error {
	// Listen on unix domain socket
	unixListener, err := net.Listen("unix", edgectl.DaemonSocketName)
	if err != nil {
		return errors.Wrap(err, "listen")
	}
	err = os.Chmod(edgectl.DaemonSocketName, 0777)
	if err != nil {
		return errors.Wrap(err, "chmod")
	}

	grpcServer := grpc.NewServer()
	rpc.RegisterDaemonServer(grpcServer, &grpcService{
		s: grpcServer,
		d: d,
		p: daemonProc,
	})

	daemonProc.Ready()
	Notify(daemonProc, "Running")
	defer Notify(daemonProc, "Shutting down...")
	return daemonProc.DoClean(func() error {
		return errors.Wrap(grpcServer.Serve(unixListener), "gRCP server")
	}, func() error {
		grpcServer.Stop()
		return nil
	})
}

func (d *daemon) pause(p *supervisor.Process) *rpc.PauseResponse {
	r := rpc.PauseResponse{}
	switch {
	case d.network == nil:
		r.Error = rpc.PauseResponse_AlreadyPaused
	case d.cluster != nil:
		r.Error = rpc.PauseResponse_ConnectedToCluster
	default:
		if err := d.network.Close(); err != nil {
			r.Error = rpc.PauseResponse_UnexpectedPauseError
			r.ErrorText = err.Error()
			p.Logf("pause: %v", err)
		}
		d.network = nil
	}
	return &r
}

func (d *daemon) resume(p *supervisor.Process) *rpc.ResumeResponse {
	r := rpc.ResumeResponse{}
	if d.network != nil {
		if d.network.IsOkay() {
			r.Error = rpc.ResumeResponse_NotPaused
		} else {
			r.Error = rpc.ResumeResponse_ReEstablishing
		}
	} else if err := d.MakeNetOverride(p); err != nil {
		r.Error = rpc.ResumeResponse_UnexpectedResumeError
		r.ErrorText = err.Error()
		p.Logf("resume: %v", err)
	}
	return &r
}
<|endoftext|>


<commit_before>package forth

// Source: exercism/problem-specifications
// Commit: 1b4165d Add test for Forth that an operator can be overridden.
// Problem Specifications Version: 1.2.0

type testGroup struct {
	group string
	tests []testCase
}

type testCase struct {
	description string
	input       []string
	expected    []int // nil slice indicates error expected.
}

var testGroups = []testGroup{
	{
		group: "parsing and numbers",
		tests: []testCase{
			{
				"empty input results in empty stack",
				[]string{},
				[]int{},
			},
			{
				"numbers just get pushed onto the stack",
				[]string{"1 2 3 4 5"},
				[]int{1, 2, 3, 4, 5},
			},
		},
	},
	{
		group: "addition",
		tests: []testCase{
			{
				"can add two numbers",
				[]string{"1 2 +"},
				[]int{3},
			},
			{
				"errors if there is nothing on the stack",
				[]string{"+"},
				[]int(nil),
			},
			{
				"errors if there is only one value on the stack",
				[]string{"1 +"},
				[]int(nil),
			},
		},
	},
	{
		group: "subtraction",
		tests: []testCase{
			{
				"can subtract two numbers",
				[]string{"3 4 -"},
				[]int{-1},
			},
			{
				"errors if there is nothing on the stack",
				[]string{"-"},
				[]int(nil),
			},
			{
				"errors if there is only one value on the stack",
				[]string{"1 -"},
				[]int(nil),
			},
		},
	},
	{
		group: "multiplication",
		tests: []testCase{
			{
				"can multiply two numbers",
				[]string{"2 4 *"},
				[]int{8},
			},
			{
				"errors if there is nothing on the stack",
				[]string{"*"},
				[]int(nil),
			},
			{
				"errors if there is only one value on the stack",
				[]string{"1 *"},
				[]int(nil),
			},
		},
	},
	{
		group: "division",
		tests: []testCase{
			{
				"can divide two numbers",
				[]string{"12 3 /"},
				[]int{4},
			},
			{
				"performs integer division",
				[]string{"8 3 /"},
				[]int{2},
			},
			{
				"errors if dividing by zero",
				[]string{"4 0 /"},
				[]int(nil),
			},
			{
				"errors if there is nothing on the stack",
				[]string{"/"},
				[]int(nil),
			},
			{
				"errors if there is only one value on the stack",
				[]string{"1 /"},
				[]int(nil),
			},
		},
	},
	{
		group: "combined arithmetic",
		tests: []testCase{
			{
				"addition and subtraction",
				[]string{"1 2 + 4 -"},
				[]int{-1},
			},
			{
				"multiplication and division",
				[]string{"2 4 * 3 /"},
				[]int{2},
			},
		},
	},
	{
		group: "dup",
		tests: []testCase{
			{
				"copies the top value on the stack",
				[]string{"1 DUP"},
				[]int{1, 1},
			},
			{
				"is case-insensitive",
				[]string{"1 2 Dup"},
				[]int{1, 2, 2},
			},
			{
				"errors if there is nothing on the stack",
				[]string{"dup"},
				[]int(nil),
			},
		},
	},
	{
		group: "drop",
		tests: []testCase{
			{
				"removes the top value on the stack if it is the only one",
				[]string{"1 drop"},
				[]int{},
			},
			{
				"removes the top value on the stack if it is not the only one",
				[]string{"1 2 drop"},
				[]int{1},
			},
			{
				"errors if there is nothing on the stack",
				[]string{"drop"},
				[]int(nil),
			},
		},
	},
	{
		group: "swap",
		tests: []testCase{
			{
				"swaps the top two values on the stack if they are the only ones",
				[]string{"1 2 swap"},
				[]int{2, 1},
			},
			{
				"swaps the top two values on the stack if they are not the only ones",
				[]string{"1 2 3 swap"},
				[]int{1, 3, 2},
			},
			{
				"errors if there is nothing on the stack",
				[]string{"swap"},
				[]int(nil),
			},
			{
				"errors if there is only one value on the stack",
				[]string{"1 swap"},
				[]int(nil),
			},
		},
	},
	{
		group: "over",
		tests: []testCase{
			{
				"copies the second element if there are only two",
				[]string{"1 2 over"},
				[]int{1, 2, 1},
			},
			{
				"copies the second element if there are more than two",
				[]string{"1 2 3 over"},
				[]int{1, 2, 3, 2},
			},
			{
				"errors if there is nothing on the stack",
				[]string{"over"},
				[]int(nil),
			},
			{
				"errors if there is only one value on the stack",
				[]string{"1 over"},
				[]int(nil),
			},
		},
	},
	{
		group: "user-defined words",
		tests: []testCase{
			{
				"can consist of built-in words",
				[]string{": dup-twice dup dup ;", "1 dup-twice"},
				[]int{1, 1, 1},
			},
			{
				"execute in the right order",
				[]string{": countup 1 2 3 ;", "countup"},
				[]int{1, 2, 3},
			},
			{
				"can override other user-defined words",
				[]string{": foo dup ;", ": foo dup dup ;", "1 foo"},
				[]int{1, 1, 1},
			},
			{
				"can override built-in words",
				[]string{": swap dup ;", "1 swap"},
				[]int{1, 1},
			},
			{
				"can override built-in operators",
				[]string{": + * ;", "3 4 +"},
				[]int{12},
			},
			{
				"cannot redefine numbers",
				[]string{": 1 2 ;"},
				[]int(nil),
			},
			{
				"errors if executing a non-existent word",
				[]string{"foo"},
				[]int(nil),
			},
		},
	},
}
<commit_msg>forth: remove test for empty input (#942)<commit_after>package forth

// Source: exercism/problem-specifications
// Commit: 3cb5e76 forth: Remove test for empty input (#976)
// Problem Specifications Version: 1.3.0

type testGroup struct {
	group string
	tests []testCase
}

type testCase struct {
	description string
	input       []string
	expected    []int // nil slice indicates error expected.
}

var testGroups = []testGroup{
	{
		group: "parsing and numbers",
		tests: []testCase{
			{
				"numbers just get pushed onto the stack",
				[]string{"1 2 3 4 5"},
				[]int{1, 2, 3, 4, 5},
			},
		},
	},
	{
		group: "addition",
		tests: []testCase{
			{
				"can add two numbers",
				[]string{"1 2 +"},
				[]int{3},
			},
			{
				"errors if there is nothing on the stack",
				[]string{"+"},
				[]int(nil),
			},
			{
				"errors if there is only one value on the stack",
				[]string{"1 +"},
				[]int(nil),
			},
		},
	},
	{
		group: "subtraction",
		tests: []testCase{
			{
				"can subtract two numbers",
				[]string{"3 4 -"},
				[]int{-1},
			},
			{
				"errors if there is nothing on the stack",
				[]string{"-"},
				[]int(nil),
			},
			{
				"errors if there is only one value on the stack",
				[]string{"1 -"},
				[]int(nil),
			},
		},
	},
	{
		group: "multiplication",
		tests: []testCase{
			{
				"can multiply two numbers",
				[]string{"2 4 *"},
				[]int{8},
			},
			{
				"errors if there is nothing on the stack",
				[]string{"*"},
				[]int(nil),
			},
			{
				"errors if there is only one value on the stack",
				[]string{"1 *"},
				[]int(nil),
			},
		},
	},
	{
		group: "division",
		tests: []testCase{
			{
				"can divide two numbers",
				[]string{"12 3 /"},
				[]int{4},
			},
			{
				"performs integer division",
				[]string{"8 3 /"},
				[]int{2},
			},
			{
				"errors if dividing by zero",
				[]string{"4 0 /"},
				[]int(nil),
			},
			{
				"errors if there is nothing on the stack",
				[]string{"/"},
				[]int(nil),
			},
			{
				"errors if there is only one value on the stack",
				[]string{"1 /"},
				[]int(nil),
			},
		},
	},
	{
		group: "combined arithmetic",
		tests: []testCase{
			{
				"addition and subtraction",
				[]string{"1 2 + 4 -"},
				[]int{-1},
			},
			{
				"multiplication and division",
				[]string{"2 4 * 3 /"},
				[]int{2},
			},
		},
	},
	{
		group: "dup",
		tests: []testCase{
			{
				"copies the top value on the stack",
				[]string{"1 DUP"},
				[]int{1, 1},
			},
			{
				"is case-insensitive",
				[]string{"1 2 Dup"},
				[]int{1, 2, 2},
			},
			{
				"errors if there is nothing on the stack",
				[]string{"dup"},
				[]int(nil),
			},
		},
	},
	{
		group: "drop",
		tests: []testCase{
			{
				"removes the top value on the stack if it is the only one",
				[]string{"1 drop"},
				[]int{},
			},
			{
				"removes the top value on the stack if it is not the only one",
				[]string{"1 2 drop"},
				[]int{1},
			},
			{
				"errors if there is nothing on the stack",
				[]string{"drop"},
				[]int(nil),
			},
		},
	},
	{
		group: "swap",
		tests: []testCase{
			{
				"swaps the top two values on the stack if they are the only ones",
				[]string{"1 2 swap"},
				[]int{2, 1},
			},
			{
				"swaps the top two values on the stack if they are not the only ones",
				[]string{"1 2 3 swap"},
				[]int{1, 3, 2},
			},
			{
				"errors if there is nothing on the stack",
				[]string{"swap"},
				[]int(nil),
			},
			{
				"errors if there is only one value on the stack",
				[]string{"1 swap"},
				[]int(nil),
			},
		},
	},
	{
		group: "over",
		tests: []testCase{
			{
				"copies the second element if there are only two",
				[]string{"1 2 over"},
				[]int{1, 2, 1},
			},
			{
				"copies the second element if there are more than two",
				[]string{"1 2 3 over"},
				[]int{1, 2, 3, 2},
			},
			{
				"errors if there is nothing on the stack",
				[]string{"over"},
				[]int(nil),
			},
			{
				"errors if there is only one value on the stack",
				[]string{"1 over"},
				[]int(nil),
			},
		},
	},
	{
		group: "user-defined words",
		tests: []testCase{
			{
				"can consist of built-in words",
				[]string{": dup-twice dup dup ;", "1 dup-twice"},
				[]int{1, 1, 1},
			},
			{
				"execute in the right order",
				[]string{": countup 1 2 3 ;", "countup"},
				[]int{1, 2, 3},
			},
			{
				"can override other user-defined words",
				[]string{": foo dup ;", ": foo dup dup ;", "1 foo"},
				[]int{1, 1, 1},
			},
			{
				"can override built-in words",
				[]string{": swap dup ;", "1 swap"},
				[]int{1, 1},
			},
			{
				"can override built-in operators",
				[]string{": + * ;", "3 4 +"},
				[]int{12},
			},
			{
				"cannot redefine numbers",
				[]string{": 1 2 ;"},
				[]int(nil),
			},
			{
				"errors if executing a non-existent word",
				[]string{"foo"},
				[]int(nil),
			},
		},
	},
}
<|endoftext|>


<commit_before>package provider

import (
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func resourceShuffle() *schema.Resource {
	return &schema.Resource{
		Description: "The resource `random_shuffle` generates a random permutation of a list of strings " +
			"given as an argument.",
		Create: CreateShuffle,
		Read:   schema.Noop,
		Delete: schema.RemoveFromState,

		Schema: map[string]*schema.Schema{
			"keepers": {
				Description: "Arbitrary map of values that, when changed, will trigger recreation of " +
					"resource. See [the main provider documentation](../index.html) for more information.",
				Type:     schema.TypeMap,
				Optional: true,
				ForceNew: true,
			},

			"seed": {
				Description: "Arbitrary string with which to seed the random number generator, in order to " +
					"produce less-volatile permutations of the list.\n" +
					"\n" +
					"**Important:** Even with an identical seed, it is not guaranteed that the same permutation " +
					"will be produced across different versions of Terraform. This argument causes the " +
					"result to be *less volatile*, but not fixed for all time.",
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"input": {
				Description: "The list of strings to shuffle.",
				Type:        schema.TypeList,
				Required:    true,
				ForceNew:    true,
				Elem: &schema.Schema{
					Type: schema.TypeString,
				},
			},

			"result_count": {
				Description: "The number of results to return. Defaults to the number of items in the " +
					"`input` list. If fewer items are requested, some elements will be excluded from the " +
					"result. If more items are requested, items will be repeated in the result but not more " +
					"frequently than the number of items in the input list.",
				Type:     schema.TypeInt,
				Optional: true,
				ForceNew: true,
			},

			"result": {
				Description: "Random permutation of the list of strings given in `input`.",
				Type:        schema.TypeList,
				Computed:    true,
				Elem: &schema.Schema{
					Type: schema.TypeString,
				},
			},

			"id": {
				Description: "A static value used internally by Terraform, this should not be referenced in configurations.",
				Type:        schema.TypeString,
				Computed:    true,
			},
		},
	}
}

func CreateShuffle(d *schema.ResourceData, _ interface{}) error {
	input := d.Get("input").([]interface{})
	seed := d.Get("seed").(string)

	resultCount := d.Get("result_count").(int)
	if resultCount == 0 {
		resultCount = len(input)
	}
	result := make([]interface{}, 0, resultCount)

	if len(input) > 0 {
		rand := NewRand(seed)

		// Keep producing permutations until we fill our result
	Batches:
		for {
			perm := rand.Perm(len(input))

			for _, i := range perm {
				result = append(result, input[i])

				if len(result) >= resultCount {
					break Batches
				}
			}
		}

	}

	d.SetId("-")
	d.Set("result", result)

	return nil
}
<commit_msg>Replace usage of Create, Read and Delete fields with CreateContext, ReadContext and DeleteContext in resource_shuffle (#230)<commit_after>package provider

import (
	"context"
	"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func resourceShuffle() *schema.Resource {
	return &schema.Resource{
		Description: "The resource `random_shuffle` generates a random permutation of a list of strings " +
			"given as an argument.",
		CreateContext: CreateShuffle,
		ReadContext:   schema.NoopContext,
		DeleteContext: DeleteShuffle,

		Schema: map[string]*schema.Schema{
			"keepers": {
				Description: "Arbitrary map of values that, when changed, will trigger recreation of " +
					"resource. See [the main provider documentation](../index.html) for more information.",
				Type:     schema.TypeMap,
				Optional: true,
				ForceNew: true,
			},

			"seed": {
				Description: "Arbitrary string with which to seed the random number generator, in order to " +
					"produce less-volatile permutations of the list.\n" +
					"\n" +
					"**Important:** Even with an identical seed, it is not guaranteed that the same permutation " +
					"will be produced across different versions of Terraform. This argument causes the " +
					"result to be *less volatile*, but not fixed for all time.",
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"input": {
				Description: "The list of strings to shuffle.",
				Type:        schema.TypeList,
				Required:    true,
				ForceNew:    true,
				Elem: &schema.Schema{
					Type: schema.TypeString,
				},
			},

			"result_count": {
				Description: "The number of results to return. Defaults to the number of items in the " +
					"`input` list. If fewer items are requested, some elements will be excluded from the " +
					"result. If more items are requested, items will be repeated in the result but not more " +
					"frequently than the number of items in the input list.",
				Type:     schema.TypeInt,
				Optional: true,
				ForceNew: true,
			},

			"result": {
				Description: "Random permutation of the list of strings given in `input`.",
				Type:        schema.TypeList,
				Computed:    true,
				Elem: &schema.Schema{
					Type: schema.TypeString,
				},
			},

			"id": {
				Description: "A static value used internally by Terraform, this should not be referenced in configurations.",
				Type:        schema.TypeString,
				Computed:    true,
			},
		},
	}
}

func CreateShuffle(_ context.Context, d *schema.ResourceData, _ interface{}) diag.Diagnostics {
	input := d.Get("input").([]interface{})
	seed := d.Get("seed").(string)

	resultCount := d.Get("result_count").(int)
	if resultCount == 0 {
		resultCount = len(input)
	}
	result := make([]interface{}, 0, resultCount)

	if len(input) > 0 {
		rand := NewRand(seed)

		// Keep producing permutations until we fill our result
	Batches:
		for {
			perm := rand.Perm(len(input))

			for _, i := range perm {
				result = append(result, input[i])

				if len(result) >= resultCount {
					break Batches
				}
			}
		}

	}

	d.SetId("-")
	d.Set("result", result)

	return nil
}

func DeleteShuffle(_ context.Context, d *schema.ResourceData, _ interface{}) diag.Diagnostics {
	d.SetId("")
	return nil
}
<|endoftext|>