<commit_before>package sm_test

import (
	"bytes"
	crand "crypto/rand"
	"fmt"
	"io"
	mrand "math/rand"
	"net"
	"os"
	"reflect"
	"runtime"
	"runtime/debug"
	"sync"
	"testing"
	"time"

	smux "github.com/jbenet/go-stream-muxer"
)

var randomness []byte

func init() {
	// read 1MB of randomness
	randomness = make([]byte, 1<<20)
	if _, err := crand.Read(randomness); err != nil {
		panic(err)
	}
}

type Options struct {
	tr        smux.Transport
	connNum   int
	streamNum int
	msgNum    int
	msgMin    int
	msgMax    int
}

func randBuf(size int) []byte {
	n := len(randomness) - size
	if size < 1 {
		panic(fmt.Errorf("requested too large buffer (%d). max is %d", size, len(randomness)))
	}

	start := mrand.Intn(n)
	return randomness[start : start+size]
}

func checkErr(t *testing.T, err error) {
	if err != nil {
		debug.PrintStack()
		t.Fatal(err)
	}
}

func log(s string, v ...interface{}) {
	if testing.Verbose() {
		fmt.Fprintf(os.Stderr, "> "+s+"\n", v...)
	}
}

func echoStream(s smux.Stream) {
	defer s.Close()
	log("accepted stream")
	io.Copy(&LogWriter{s}, s) // echo everything
	log("closing stream")
}

type LogWriter struct {
	W io.Writer
}

func (lw *LogWriter) Write(buf []byte) (int, error) {
	if testing.Verbose() {
		log("logwriter: writing %d bytes", len(buf))
	}
	return lw.W.Write(buf)
}

func GoServe(t *testing.T, tr smux.Transport, l net.Listener) (done func()) {
	closed := make(chan struct{}, 1)

	go func() {
		for {
			c1, err := l.Accept()
			if err != nil {
				select {
				case <-closed:
					return // closed naturally.
				default:
					checkErr(t, err)
				}
			}

			log("accepted connection")
			sc1, err := tr.NewConn(c1, true)
			checkErr(t, err)
			go sc1.Serve(echoStream)
		}
	}()

	return func() {
		closed <- struct{}{}
	}
}

func SubtestSimpleWrite(t *testing.T, tr smux.Transport) {
	l, err := net.Listen("tcp", "localhost:0")
	checkErr(t, err)
	log("listening at %s", l.Addr().String())
	done := GoServe(t, tr, l)
	defer done()

	log("dialing to %s", l.Addr().String())
	nc1, err := net.Dial("tcp", l.Addr().String())
	checkErr(t, err)
	defer nc1.Close()

	log("wrapping conn")
	c1, err := tr.NewConn(nc1, false)
	checkErr(t, err)
	defer c1.Close()

	// serve the outgoing conn, because some muxers assume
	// that we _always_ call serve. (this is an error?)
	go c1.Serve(smux.NoOpHandler)

	log("creating stream")
	s1, err := c1.OpenStream()
	checkErr(t, err)
	defer s1.Close()

	buf1 := randBuf(4096)
	log("writing %d bytes to stream", len(buf1))
	_, err = s1.Write(buf1)
	checkErr(t, err)

	buf2 := make([]byte, len(buf1))
	log("reading %d bytes from stream (echoed)", len(buf2))
	_, err = s1.Read(buf2)
	checkErr(t, err)

	if string(buf2) != string(buf1) {
		t.Error("buf1 and buf2 not equal: %s != %s", string(buf1), string(buf2))
	}
	log("done")
}

func SubtestStress(t *testing.T, opt Options) {

	msgsize := 1 << 11
	errs := make(chan error, 0) // dont block anything.

	rateLimitN := 5000 // max of 5k funcs, because -race has 8k max.
	rateLimitChan := make(chan struct{}, rateLimitN)
	for i := 0; i < rateLimitN; i++ {
		rateLimitChan <- struct{}{}
	}

	rateLimit := func(f func()) {
		<-rateLimitChan
		f()
		rateLimitChan <- struct{}{}
	}

	writeStream := func(s smux.Stream, bufs chan<- []byte) {
		log("writeStream %p, %d msgNum", s, opt.msgNum)

		for i := 0; i < opt.msgNum; i++ {
			buf := randBuf(msgsize)
			bufs <- buf
			log("%p writing %d bytes (message %d/%d #%x)", s, len(buf), i, opt.msgNum, buf[:3])
			if _, err := s.Write(buf); err != nil {
				errs <- fmt.Errorf("s.Write(buf): %s", err)
				continue
			}
		}
	}

	readStream := func(s smux.Stream, bufs <-chan []byte) {
		log("readStream %p, %d msgNum", s, opt.msgNum)

		buf2 := make([]byte, msgsize)
		i := 0
		for buf1 := range bufs {
			i++
			log("%p reading %d bytes (message %d/%d #%x)", s, len(buf1), i-1, opt.msgNum, buf1[:3])

			if _, err := io.ReadFull(s, buf2); err != nil {
				errs <- fmt.Errorf("io.ReadFull(s, buf2): %s", err)
				log("%p failed to read %d bytes (message %d/%d #%x)", s, len(buf1), i-1, opt.msgNum, buf1[:3])
				continue
			}
			if !bytes.Equal(buf1, buf2) {
				errs <- fmt.Errorf("buffers not equal (%x != %x)", buf1[:3], buf2[:3])
			}
		}
	}

	openStreamAndRW := func(c smux.Conn) {
		log("openStreamAndRW %p, %d opt.msgNum", c, opt.msgNum)

		s, err := c.OpenStream()
		if err != nil {
			errs <- fmt.Errorf("Failed to create NewStream: %s", err)
			return
		}

		bufs := make(chan []byte, opt.msgNum)
		go func() {
			writeStream(s, bufs)
			close(bufs)
		}()

		readStream(s, bufs)
		s.Close()
	}

	openConnAndRW := func() {
		log("openConnAndRW")

		l, err := net.Listen("tcp", "localhost:0")
		checkErr(t, err)
		done := GoServe(t, opt.tr, l)
		defer done()

		nla := l.Addr()
		nc, err := net.Dial(nla.Network(), nla.String())
		checkErr(t, err)
		if err != nil {
			t.Fatal(fmt.Errorf("net.Dial(%s, %s): %s", nla.Network(), nla.String(), err))
			return
		}

		c, err := opt.tr.NewConn(nc, false)
		if err != nil {
			t.Fatal(fmt.Errorf("a.AddConn(%s <--> %s): %s", nc.LocalAddr(), nc.RemoteAddr(), err))
			return
		}

		// serve the outgoing conn, because some muxers assume
		// that we _always_ call serve. (this is an error?)
		go c.Serve(func(s smux.Stream) {
			log("serving connection")
			echoStream(s)
			s.Close()
		})

		var wg sync.WaitGroup
		for i := 0; i < opt.streamNum; i++ {
			wg.Add(1)
			go rateLimit(func() {
				defer wg.Done()
				openStreamAndRW(c)
			})
		}
		wg.Wait()
		c.Close()
	}

	openConnsAndRW := func() {
		log("openConnsAndRW, %d conns", opt.connNum)

		var wg sync.WaitGroup
		for i := 0; i < opt.connNum; i++ {
			wg.Add(1)
			go rateLimit(func() {
				defer wg.Done()
				openConnAndRW()
			})
		}
		wg.Wait()
	}

	go func() {
		openConnsAndRW()
		close(errs) // done
	}()

	for err := range errs {
		t.Error(err)
	}

}

func tcpPipe(t *testing.T) (net.Conn, net.Conn) {
	list, err := net.Listen("tcp", "0.0.0.0:0")
	if err != nil {
		t.Fatal(err)
	}

	con1, err := net.Dial("tcp", list.Addr().String())
	if err != nil {
		t.Fatal(err)
	}

	con2, err := list.Accept()
	if err != nil {
		t.Fatal(err)
	}

	return con1, con2
}

func SubtestStreamOpenStress(t *testing.T, tr smux.Transport) {
	a, b := tcpPipe(t)
	defer a.Close()
	defer b.Close()

	count := 10000
	go func() {
		muxa, err := tr.NewConn(a, true)
		if err != nil {
			t.Fatal(err)
		}
		stress := func() {
			for i := 0; i < count; i++ {
				s, err := muxa.OpenStream()
				if err != nil {
					panic(err)
				}
				s.Close()
			}
		}

		go stress()
		go stress()
		go stress()
		go stress()
		go stress()
	}()

	muxb, err := tr.NewConn(b, false)
	if err != nil {
		t.Fatal(err)
	}

	time.Sleep(time.Millisecond * 50)

	recv := make(chan struct{})
	go muxb.Serve(func(s smux.Stream) {
		recv <- struct{}{}
		s.Close()
	})

	limit := time.After(time.Second * 10)
	for i := 0; i < count*5; i++ {
		select {
		case <-recv:
		case <-limit:
			t.Fatal("timed out receiving streams")
		}
	}
}

func SubtestStress1Conn1Stream1Msg(t *testing.T, tr smux.Transport) {
	SubtestStress(t, Options{
		tr:        tr,
		connNum:   1,
		streamNum: 1,
		msgNum:    1,
		msgMax:    100,
		msgMin:    100,
	})
}

func SubtestStress1Conn1Stream100Msg(t *testing.T, tr smux.Transport) {
	SubtestStress(t, Options{
		tr:        tr,
		connNum:   1,
		streamNum: 1,
		msgNum:    100,
		msgMax:    100,
		msgMin:    100,
	})
}

func SubtestStress1Conn100Stream100Msg(t *testing.T, tr smux.Transport) {
	SubtestStress(t, Options{
		tr:        tr,
		connNum:   1,
		streamNum: 100,
		msgNum:    100,
		msgMax:    100,
		msgMin:    100,
	})
}

func SubtestStress50Conn10Stream50Msg(t *testing.T, tr smux.Transport) {
	SubtestStress(t, Options{
		tr:        tr,
		connNum:   50,
		streamNum: 10,
		msgNum:    50,
		msgMax:    100,
		msgMin:    100,
	})
}

func SubtestStress1Conn1000Stream10Msg(t *testing.T, tr smux.Transport) {
	SubtestStress(t, Options{
		tr:        tr,
		connNum:   1,
		streamNum: 1000,
		msgNum:    10,
		msgMax:    100,
		msgMin:    100,
	})
}

func SubtestStress1Conn100Stream100Msg10MB(t *testing.T, tr smux.Transport) {
	SubtestStress(t, Options{
		tr:        tr,
		connNum:   1,
		streamNum: 100,
		msgNum:    100,
		msgMax:    10000,
		msgMin:    1000,
	})
}

func SubtestAll(t *testing.T, tr smux.Transport) {

	tests := []TransportTest{
		SubtestSimpleWrite,
		SubtestStress1Conn1Stream1Msg,
		SubtestStress1Conn1Stream100Msg,
		SubtestStress1Conn100Stream100Msg,
		SubtestStress50Conn10Stream50Msg,
		SubtestStress1Conn1000Stream10Msg,
		SubtestStress1Conn100Stream100Msg10MB,
		SubtestStreamOpenStress,
	}

	for _, f := range tests {
		if testing.Verbose() {
			fmt.Fprintf(os.Stderr, "==== RUN %s\n", GetFunctionName(f))
		}
		f(t, tr)
	}
}

type TransportTest func(t *testing.T, tr smux.Transport)

func TestNoOp(t *testing.T) {}

func GetFunctionName(i interface{}) string {
	return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
}
<commit_msg>add new test to stress write/closes<commit_after>package sm_test

import (
	"bytes"
	crand "crypto/rand"
	"fmt"
	"io"
	mrand "math/rand"
	"net"
	"os"
	"reflect"
	"runtime"
	"runtime/debug"
	"sync"
	"testing"
	"time"

	smux "github.com/jbenet/go-stream-muxer"
)

var randomness []byte

func init() {
	// read 1MB of randomness
	randomness = make([]byte, 1<<20)
	if _, err := crand.Read(randomness); err != nil {
		panic(err)
	}
}

type Options struct {
	tr        smux.Transport
	connNum   int
	streamNum int
	msgNum    int
	msgMin    int
	msgMax    int
}

func randBuf(size int) []byte {
	n := len(randomness) - size
	if size < 1 {
		panic(fmt.Errorf("requested too large buffer (%d). max is %d", size, len(randomness)))
	}

	start := mrand.Intn(n)
	return randomness[start : start+size]
}

func checkErr(t *testing.T, err error) {
	if err != nil {
		debug.PrintStack()
		t.Fatal(err)
	}
}

func log(s string, v ...interface{}) {
	if testing.Verbose() {
		fmt.Fprintf(os.Stderr, "> "+s+"\n", v...)
	}
}

func echoStream(s smux.Stream) {
	defer s.Close()
	log("accepted stream")
	io.Copy(&LogWriter{s}, s) // echo everything
	log("closing stream")
}

type LogWriter struct {
	W io.Writer
}

func (lw *LogWriter) Write(buf []byte) (int, error) {
	if testing.Verbose() {
		log("logwriter: writing %d bytes", len(buf))
	}
	return lw.W.Write(buf)
}

func GoServe(t *testing.T, tr smux.Transport, l net.Listener) (done func()) {
	closed := make(chan struct{}, 1)

	go func() {
		for {
			c1, err := l.Accept()
			if err != nil {
				select {
				case <-closed:
					return // closed naturally.
				default:
					checkErr(t, err)
				}
			}

			log("accepted connection")
			sc1, err := tr.NewConn(c1, true)
			checkErr(t, err)
			go sc1.Serve(echoStream)
		}
	}()

	return func() {
		closed <- struct{}{}
	}
}

func SubtestSimpleWrite(t *testing.T, tr smux.Transport) {
	l, err := net.Listen("tcp", "localhost:0")
	checkErr(t, err)
	log("listening at %s", l.Addr().String())
	done := GoServe(t, tr, l)
	defer done()

	log("dialing to %s", l.Addr().String())
	nc1, err := net.Dial("tcp", l.Addr().String())
	checkErr(t, err)
	defer nc1.Close()

	log("wrapping conn")
	c1, err := tr.NewConn(nc1, false)
	checkErr(t, err)
	defer c1.Close()

	// serve the outgoing conn, because some muxers assume
	// that we _always_ call serve. (this is an error?)
	go c1.Serve(smux.NoOpHandler)

	log("creating stream")
	s1, err := c1.OpenStream()
	checkErr(t, err)
	defer s1.Close()

	buf1 := randBuf(4096)
	log("writing %d bytes to stream", len(buf1))
	_, err = s1.Write(buf1)
	checkErr(t, err)

	buf2 := make([]byte, len(buf1))
	log("reading %d bytes from stream (echoed)", len(buf2))
	_, err = s1.Read(buf2)
	checkErr(t, err)

	if string(buf2) != string(buf1) {
		t.Error("buf1 and buf2 not equal: %s != %s", string(buf1), string(buf2))
	}
	log("done")
}

func SubtestWriteCloses(t *testing.T, tr smux.Transport) {
	a, b := net.Pipe()

	c1, err := tr.NewConn(a, true)
	if err != nil {
		t.Fatal(err)
	}

	c2, err := tr.NewConn(b, false)
	if err != nil {
		t.Fatal(err)
	}

	count := 1000
	runners := 10

	stress := func() {
		for i := 0; i < count; i++ {
			s, err := c2.OpenStream()
			if err != nil {
				t.Error(err)
			}

			s.Write([]byte("hello"))
			s.Write([]byte("world"))
			s.Close()
		}
	}

	for i := 0; i < runners; i++ {
		go stress()
	}

	wg := sync.WaitGroup{}
	buf := make([]byte, 20)
	for i := 0; i < runners*count; i++ {
		s, err := c1.AcceptStream()
		if err != nil {
			t.Fatal(err)
		}

		wg.Add(1)
		go func(s smux.Stream) {
			defer wg.Done()
			n, _ := io.ReadFull(s, buf)

			if !bytes.Equal(buf[:n], []byte("helloworld")) {
				t.Error("got wrong data!", string(buf[:n]))
			}
			s.Close()
		}(s)
	}
	wg.Wait()
}

func SubtestStress(t *testing.T, opt Options) {

	msgsize := 1 << 11
	errs := make(chan error, 0) // dont block anything.

	rateLimitN := 5000 // max of 5k funcs, because -race has 8k max.
	rateLimitChan := make(chan struct{}, rateLimitN)
	for i := 0; i < rateLimitN; i++ {
		rateLimitChan <- struct{}{}
	}

	rateLimit := func(f func()) {
		<-rateLimitChan
		f()
		rateLimitChan <- struct{}{}
	}

	writeStream := func(s smux.Stream, bufs chan<- []byte) {
		log("writeStream %p, %d msgNum", s, opt.msgNum)

		for i := 0; i < opt.msgNum; i++ {
			buf := randBuf(msgsize)
			bufs <- buf
			log("%p writing %d bytes (message %d/%d #%x)", s, len(buf), i, opt.msgNum, buf[:3])
			if _, err := s.Write(buf); err != nil {
				errs <- fmt.Errorf("s.Write(buf): %s", err)
				continue
			}
		}
	}

	readStream := func(s smux.Stream, bufs <-chan []byte) {
		log("readStream %p, %d msgNum", s, opt.msgNum)

		buf2 := make([]byte, msgsize)
		i := 0
		for buf1 := range bufs {
			i++
			log("%p reading %d bytes (message %d/%d #%x)", s, len(buf1), i-1, opt.msgNum, buf1[:3])

			if _, err := io.ReadFull(s, buf2); err != nil {
				errs <- fmt.Errorf("io.ReadFull(s, buf2): %s", err)
				log("%p failed to read %d bytes (message %d/%d #%x)", s, len(buf1), i-1, opt.msgNum, buf1[:3])
				continue
			}
			if !bytes.Equal(buf1, buf2) {
				errs <- fmt.Errorf("buffers not equal (%x != %x)", buf1[:3], buf2[:3])
			}
		}
	}

	openStreamAndRW := func(c smux.Conn) {
		log("openStreamAndRW %p, %d opt.msgNum", c, opt.msgNum)

		s, err := c.OpenStream()
		if err != nil {
			errs <- fmt.Errorf("Failed to create NewStream: %s", err)
			return
		}

		bufs := make(chan []byte, opt.msgNum)
		go func() {
			writeStream(s, bufs)
			close(bufs)
		}()

		readStream(s, bufs)
		s.Close()
	}

	openConnAndRW := func() {
		log("openConnAndRW")

		l, err := net.Listen("tcp", "localhost:0")
		checkErr(t, err)
		done := GoServe(t, opt.tr, l)
		defer done()

		nla := l.Addr()
		nc, err := net.Dial(nla.Network(), nla.String())
		checkErr(t, err)
		if err != nil {
			t.Fatal(fmt.Errorf("net.Dial(%s, %s): %s", nla.Network(), nla.String(), err))
			return
		}

		c, err := opt.tr.NewConn(nc, false)
		if err != nil {
			t.Fatal(fmt.Errorf("a.AddConn(%s <--> %s): %s", nc.LocalAddr(), nc.RemoteAddr(), err))
			return
		}

		// serve the outgoing conn, because some muxers assume
		// that we _always_ call serve. (this is an error?)
		go c.Serve(func(s smux.Stream) {
			log("serving connection")
			echoStream(s)
			s.Close()
		})

		var wg sync.WaitGroup
		for i := 0; i < opt.streamNum; i++ {
			wg.Add(1)
			go rateLimit(func() {
				defer wg.Done()
				openStreamAndRW(c)
			})
		}
		wg.Wait()
		c.Close()
	}

	openConnsAndRW := func() {
		log("openConnsAndRW, %d conns", opt.connNum)

		var wg sync.WaitGroup
		for i := 0; i < opt.connNum; i++ {
			wg.Add(1)
			go rateLimit(func() {
				defer wg.Done()
				openConnAndRW()
			})
		}
		wg.Wait()
	}

	go func() {
		openConnsAndRW()
		close(errs) // done
	}()

	for err := range errs {
		t.Error(err)
	}

}

func tcpPipe(t *testing.T) (net.Conn, net.Conn) {
	list, err := net.Listen("tcp", "0.0.0.0:0")
	if err != nil {
		t.Fatal(err)
	}

	con1, err := net.Dial("tcp", list.Addr().String())
	if err != nil {
		t.Fatal(err)
	}

	con2, err := list.Accept()
	if err != nil {
		t.Fatal(err)
	}

	return con1, con2
}

func SubtestStreamOpenStress(t *testing.T, tr smux.Transport) {
	a, b := tcpPipe(t)
	defer a.Close()
	defer b.Close()

	count := 10000
	go func() {
		muxa, err := tr.NewConn(a, true)
		if err != nil {
			t.Fatal(err)
		}
		stress := func() {
			for i := 0; i < count; i++ {
				s, err := muxa.OpenStream()
				if err != nil {
					panic(err)
				}
				s.Close()
			}
		}

		go stress()
		go stress()
		go stress()
		go stress()
		go stress()
	}()

	muxb, err := tr.NewConn(b, false)
	if err != nil {
		t.Fatal(err)
	}

	time.Sleep(time.Millisecond * 50)

	recv := make(chan struct{})
	go muxb.Serve(func(s smux.Stream) {
		recv <- struct{}{}
		s.Close()
	})

	limit := time.After(time.Second * 10)
	for i := 0; i < count*5; i++ {
		select {
		case <-recv:
		case <-limit:
			t.Fatal("timed out receiving streams")
		}
	}
}

func SubtestStress1Conn1Stream1Msg(t *testing.T, tr smux.Transport) {
	SubtestStress(t, Options{
		tr:        tr,
		connNum:   1,
		streamNum: 1,
		msgNum:    1,
		msgMax:    100,
		msgMin:    100,
	})
}

func SubtestStress1Conn1Stream100Msg(t *testing.T, tr smux.Transport) {
	SubtestStress(t, Options{
		tr:        tr,
		connNum:   1,
		streamNum: 1,
		msgNum:    100,
		msgMax:    100,
		msgMin:    100,
	})
}

func SubtestStress1Conn100Stream100Msg(t *testing.T, tr smux.Transport) {
	SubtestStress(t, Options{
		tr:        tr,
		connNum:   1,
		streamNum: 100,
		msgNum:    100,
		msgMax:    100,
		msgMin:    100,
	})
}

func SubtestStress50Conn10Stream50Msg(t *testing.T, tr smux.Transport) {
	SubtestStress(t, Options{
		tr:        tr,
		connNum:   50,
		streamNum: 10,
		msgNum:    50,
		msgMax:    100,
		msgMin:    100,
	})
}

func SubtestStress1Conn1000Stream10Msg(t *testing.T, tr smux.Transport) {
	SubtestStress(t, Options{
		tr:        tr,
		connNum:   1,
		streamNum: 1000,
		msgNum:    10,
		msgMax:    100,
		msgMin:    100,
	})
}

func SubtestStress1Conn100Stream100Msg10MB(t *testing.T, tr smux.Transport) {
	SubtestStress(t, Options{
		tr:        tr,
		connNum:   1,
		streamNum: 100,
		msgNum:    100,
		msgMax:    10000,
		msgMin:    1000,
	})
}

func SubtestAll(t *testing.T, tr smux.Transport) {

	tests := []TransportTest{
		SubtestSimpleWrite,
		SubtestStress1Conn1Stream1Msg,
		SubtestStress1Conn1Stream100Msg,
		SubtestStress1Conn100Stream100Msg,
		SubtestStress50Conn10Stream50Msg,
		SubtestStress1Conn1000Stream10Msg,
		SubtestStress1Conn100Stream100Msg10MB,
		SubtestStreamOpenStress,
		SubtestWriteCloses,
	}

	for _, f := range tests {
		if testing.Verbose() {
			fmt.Fprintf(os.Stderr, "==== RUN %s\n", GetFunctionName(f))
		}
		f(t, tr)
	}
}

type TransportTest func(t *testing.T, tr smux.Transport)

func TestNoOp(t *testing.T) {}

func GetFunctionName(i interface{}) string {
	return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
}
<|endoftext|>


<commit_before>package git_comment

import (
	"fmt"
	"regexp"
)

type Person struct {
	Name  string
	Email string
}

// Parse a property string and create a person. The expected format is:
// ```
// Name <email@example.com>
// ```
// If a valid person cannot be created, an error is returned instead
func CreatePerson(properties string) *Person {
	fullRe := regexp.MustCompile(`(.*)\s<(.*@.*)>$`)
	match := fullRe.FindStringSubmatch(properties)
	if len(match) == 3 {
		return &Person{match[1], match[2]}
	} else {
		emailRe := regexp.MustCompile(`\s?<(.*@.*)>$`)
		match = emailRe.FindStringSubmatch(properties)
		if len(match) == 2 {
			return &Person{"", match[1]}
		}
		return &Person{properties, ""}
	}
}

func (p *Person) Serialize() string {
	if len(p.Name) > 0 {
		if len(p.Email) > 0 {
			return fmt.Sprintf("%v <%v>", p.Name, p.Email)
		}
		return p.Name
	} else if len(p.Email) > 0 {
		return fmt.Sprintf("<%v>", p.Email)
	}
	return ""
}
<commit_msg>Allow extended author format<commit_after>package git_comment

import (
	"fmt"
	"regexp"
)

type Person struct {
	Name  string
	Email string
}

// Parse a property string and create a person. The expected format is:
// ```
// Name <email@example.com>
// ```
// If a valid person cannot be created, an error is returned instead
func CreatePerson(properties string) *Person {
	fullRe := regexp.MustCompile(`(.*)\s<(.*@.*)>`)
	match := fullRe.FindStringSubmatch(properties)
	if len(match) == 3 {
		return &Person{match[1], match[2]}
	} else {
		emailRe := regexp.MustCompile(`\s?<(.*@.*)>`)
		match = emailRe.FindStringSubmatch(properties)
		if len(match) == 2 {
			return &Person{"", match[1]}
		}
		return &Person{properties, ""}
	}
}

func (p *Person) Serialize() string {
	if len(p.Name) > 0 {
		if len(p.Email) > 0 {
			return fmt.Sprintf("%v <%v>", p.Name, p.Email)
		}
		return p.Name
	} else if len(p.Email) > 0 {
		return fmt.Sprintf("<%v>", p.Email)
	}
	return ""
}
<|endoftext|>


<commit_before>package websocket_test

import (
	"fmt"
	"net/http"
	"net/url"
	"strings"
	"testing"

	gorilla "github.com/gorilla/websocket"
	"github.com/spring1843/chat-server/src/chat"
	"github.com/spring1843/chat-server/src/config"
	"github.com/spring1843/chat-server/src/drivers/websocket"
)

func TestCantStartAndConnect(t *testing.T) {
	config := config.Config{
		WebAddress: "127.0.0.1:4008",
	}

	chatServer := chat.NewServer()
	chatServer.Listen()
	websocket.SetWebSocket(chatServer)

	http.HandleFunc("/ws", websocket.Handler)

	go func() {
		if err := http.ListenAndServe(config.WebAddress, nil); err != nil {
			t.Fatalf("Failed listening to Websocet on %s. Error: %s", config.WebAddress, err)
		}
	}()

	tryouts := 10
	conns := make([]*gorilla.Conn, tryouts, tryouts)
	i := 0
	for i < tryouts {
		nickName := fmt.Sprintf("user%d", i)
		conns[i] = connectUser(t, nickName, config)
		i++
	}

	if chatServer.ConnectedUsersCount() != tryouts {
		t.Fatalf("Expected user count to be %d after disconnecting users, got %d", tryouts, chatServer.ConnectedUsersCount())
	}

	i = 0
	for i < tryouts {
		disconnectUser(t, conns[i], chatServer)
		i++
	}

	if chatServer.ConnectedUsersCount() != 0 {
		t.Fatalf("Expected user count to be %d after disconnecting users, got %d", 0, chatServer.ConnectedUsersCount())
	}
}

func connectUser(t *testing.T, nickname string, config config.Config) *gorilla.Conn {
	url := url.URL{Scheme: "ws", Host: config.WebAddress, Path: "/ws"}

	conn, _, err := gorilla.DefaultDialer.Dial(url.String(), nil)
	if err != nil {
		t.Fatalf("Websocket Dial error: %s", err.Error())
	}

	_, message, err := conn.ReadMessage()
	if err != nil {
		t.Fatalf("Error while reading connection %s", err.Error())
	}

	if !strings.Contains(string(message), "Welcome") {
		t.Error("Could not receive welcome message")
	}

	if err := conn.WriteMessage(1, []byte(nickname)); err != nil {
		t.Fatalf("Error writing to connection. Error %s", err)
	}

	_, message, err = conn.ReadMessage()
	if err != nil {
		t.Fatalf("Error while reading connection. Error %s", err.Error())
	}

	expect := "Welcome " + nickname
	if !strings.Contains(string(message), expect) {
		t.Fatalf("Could not set user %s, expected 'Thanks User1' got %s", nickname, expect)
	}

	return conn
}

func disconnectUser(t *testing.T, conn *gorilla.Conn, chatServer *chat.Server) {
	if err := conn.WriteMessage(1, []byte(`/quit`)); err != nil {
		t.Fatalf("Error writing to connection. Error %s", err)
	}

	_, message, err := conn.ReadMessage()
	if err != nil {
		t.Fatalf("Failed reading from WebSocket connection. Error %s", err)
	}
	if !strings.Contains(string(message), "Good Bye") {
		t.Fatalf("Could not quit from server. Expected 'Good Bye' got %s", string(message))
	}

	if chatServer.IsUserConnected("User1") {
		t.Fatal("User is still connected to server after quiting")
	}
}
<commit_msg>Test with multiple user works<commit_after>package websocket_test

import (
	"fmt"
	"net/http"
	"net/url"
	"strings"
	"testing"

	gorilla "github.com/gorilla/websocket"
	"github.com/spring1843/chat-server/src/chat"
	"github.com/spring1843/chat-server/src/config"
	"github.com/spring1843/chat-server/src/drivers/websocket"
)

func TestCantStartAndConnect(t *testing.T) {
	config := config.Config{
		WebAddress: "127.0.0.1:4008",
	}

	chatServer := chat.NewServer()
	chatServer.Listen()
	websocket.SetWebSocket(chatServer)

	http.HandleFunc("/ws", websocket.Handler)

	go func() {
		if err := http.ListenAndServe(config.WebAddress, nil); err != nil {
			t.Fatalf("Failed listening to Websocet on %s. Error: %s", config.WebAddress, err)
		}
	}()

	tryouts := 10
	i := 0
	for i < tryouts {
		nickName := fmt.Sprintf("user%d", i)
		go connectAndDisconnect(t, nickName, config, chatServer)
		i++
	}
}

func connectUser(t *testing.T, nickname string, config config.Config) *gorilla.Conn {
	url := url.URL{Scheme: "ws", Host: config.WebAddress, Path: "/ws"}

	conn, _, err := gorilla.DefaultDialer.Dial(url.String(), nil)
	if err != nil {
		t.Fatalf("Websocket Dial error: %s", err.Error())
	}

	_, message, err := conn.ReadMessage()
	if err != nil {
		t.Fatalf("Error while reading connection %s", err.Error())
	}

	if !strings.Contains(string(message), "Welcome") {
		t.Error("Could not receive welcome message")
	}

	if err := conn.WriteMessage(1, []byte(nickname)); err != nil {
		t.Fatalf("Error writing to connection. Error %s", err)
	}

	_, message, err = conn.ReadMessage()
	if err != nil {
		t.Fatalf("Error while reading connection. Error %s", err.Error())
	}

	expect := "Welcome " + nickname
	if !strings.Contains(string(message), expect) {
		t.Fatalf("Could not set user %s, expected 'Thanks User1' got %s", nickname, expect)
	}

	return conn
}

func disconnectUser(t *testing.T, conn *gorilla.Conn, chatServer *chat.Server) {
	if err := conn.WriteMessage(1, []byte(`/quit`)); err != nil {
		t.Fatalf("Error writing to connection. Error %s", err)
	}

	_, message, err := conn.ReadMessage()
	if err != nil {
		t.Fatalf("Failed reading from WebSocket connection. Error %s", err)
	}
	if !strings.Contains(string(message), "Good Bye") {
		t.Fatalf("Could not quit from server. Expected 'Good Bye' got %s", string(message))
	}

	if chatServer.IsUserConnected("User1") {
		t.Fatal("User is still connected to server after quiting")
	}
}

func connectAndDisconnect(t *testing.T, nickname string, config config.Config, chatServer *chat.Server) {
	conn := connectUser(t, nickname, config)
	disconnectUser(t, conn, chatServer)
}
<|endoftext|>


<commit_before>package packet

// ArtAddressPacket contains an ArtAddress Packet.
type ArtAddressPacket struct {
	Header
}
<commit_msg>Add ArtAddress packet<commit_after>package packet

import (
	"bytes"
	"encoding/binary"

	"github.com/jsimonetti/go-artnet/packet/code"
	"github.com/jsimonetti/go-artnet/version"
)

var _ ArtNetPacket = &ArtAddressPacket{}

// ArtAddressPacket contains an ArtAddress Packet.
//
// A Controller or monitoring device on the network can reprogram numerous controls of a
// node remotely. This, for example, would allow the lighting console to re-route DMX512
// data at remote locations. This is achieved by sending an ArtAddress packet to the Node’s
// IP address. (The IP address is returned in the ArtPoll packet). The node replies with an
// ArtPollReply packet.
// Fields 5 to 13 contain the data that will be programmed into the node
//
// Packet Strategy:
//  Controller -  Receive:            No Action
//                Unicast Transmit:   Controller transmits to a specific node IP address
//                Broadcast Transmit: Not Allowed
//  Node -        Receive:            Reply by broadcasting ArtPollReply
//                Unicast Transmit:   Not Allowed
//                Broadcast Transmit: Not Allowed
//  MediaServer - Receive:            Reply by broadcasting ArtPollReply
//                Unicast Transmit:   Not Allowed
//                Broadcast Transmit: Not Allowed
type ArtAddressPacket struct {
	// Inherit the Header header
	Header

	// this packet type contains a version
	version [2]byte

	// NetSwitch contains Bits 14-8 of the 15 bit Port-Address are encoded into the bottom 7
	// bits of this field. This is used in combination with SubSwitch and SwIn[] or SwOut[]
	// to produce the full universe address.
	NetSwitch uint8

	// BindIndex defines the bound node which originated this packet and is used to uniquely identify
	// the bound node when identical IP addresses are in use. This number represents the order of bound
	// devices. A lower number means closer to root device. A value of 1 means root device.
	BindIndex uint8

	// ShortName for the Node. The Controller uses the ArtAddress packet to program this
	// string. Max length is 17 characters. This is a fixed length field, although the string
	// it contains can be shorter than the field.
	ShortName string

	// LongName for the Node. The Controller uses the ArtAddress packet to program this string.
	// Max length is 63. This is a fixed length field, although the string it contains can be
	// shorter than the field.
	LongName string

	// SwIn Bits 3-0 of the 15 bit Port-Address for each of the 4
	// possible input ports are encoded into the low nibble
	SwIn [4]uint8

	// SwOut Bits 3-0 of the 15 bit Port-Address for each of the 4
	// possible output ports are encoded into the low nibble.
	SwOut [4]uint8

	// SubSwitch contains Bits 7-4 of the 15 bit Port-Address are encoded into the bottom 4
	// bits of this field. This is used in combination with NetSwitch and SwIn[] or SwOut[]
	// to produce the full universe address.
	SubSwitch uint8

	// SwVideo is set to 00 when video display is showing local data. Set to 01 when video
	// is showing ethernet data. The field is now deprecated
	SwVideo uint8

	// Command contains Node configuration commands. Note that Ltp / Htp settings should be
	// retained by the node during power cycling
	Command uint8
}

// NewArtAddressPacket returns an ArtNetPacket with the correct OpCode
func NewArtAddressPacket() *ArtAddressPacket {
	return &ArtAddressPacket{
		Header: Header{
			OpCode: code.OpAddress,
			id:     ArtNet,
		},
		version: version.Bytes(),
	}
}

// MarshalBinary marshals an ArtAddressPacket into a byte slice.
func (p *ArtAddressPacket) MarshalBinary() ([]byte, error) {
	var buf bytes.Buffer
	if err := binary.Write(&buf, binary.BigEndian, p); err != nil {
		return nil, err
	}
	return buf.Bytes(), p.validate()
}

// UnmarshalBinary unmarshals the contents of a byte slice into an ArtAddressPacket.
//TODO
func (p *ArtAddressPacket) UnmarshalBinary(b []byte) error {
	return p.validate()
}

// artPacket is an empty method to sattisfy the ArtNetPacket interface.
func (p *ArtAddressPacket) validate() error {
	if p.OpCode != code.OpAddress {
		return errInvalidOpCode
	}
	return nil
}
<|endoftext|>


<commit_before>package rice

import (
	"os"
	"path/filepath"
	"sort"
	"strings"
)

// Walk is like filepath.Walk()
// Visit http://golang.org/pkg/path/filepath/#Walk for more information
func (b *Box) Walk(path string, walkFn filepath.WalkFunc) error {

	pathFile, err := b.Open(path)
	if err != nil {
		return err
	}

	pathInfo, err := pathFile.Stat()
	if err != nil {
		return err
	}

	if b.IsAppended() || b.IsEmbedded() {
		return b.walk(path, pathInfo, walkFn)
	}

	// We don't have any embedded or appended box so use live filesystem mode
	return filepath.Walk(b.name+string(os.PathSeparator)+path, func(path string, info os.FileInfo, err error) error {

		// Strip out the box name from the returned paths
		path = strings.Replace(path, b.name+string(os.PathSeparator), "", -1)
		return walkFn(path, info, err)

	})

}

// walk recursively descends path.
// See walk() in $GOROOT/src/pkg/path/filepath/path.go
func (b *Box) walk(path string, info os.FileInfo, walkFn filepath.WalkFunc) error {

	err := walkFn(path, info, nil)
	if err != nil {
		if info.IsDir() && err == filepath.SkipDir {
			return nil
		}
		return err
	}

	if !info.IsDir() {
		return nil
	}

	names, err := b.readDirNames(path)
	if err != nil {
		return walkFn(path, info, err)
	}

	for _, name := range names {

		filename := filepath.Join(path, name)
		fileObject, err := b.Open(path)
		if err != nil {
			return err
		}

		fileInfo, err := fileObject.Stat()
		if err != nil {
			if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir {
				return err
			}
		} else {
			err = b.walk(filename, fileInfo, walkFn)
			if err != nil {
				if !fileInfo.IsDir() || err != filepath.SkipDir {
					return err
				}
			}
		}
	}

	return nil

}

// readDirNames reads the directory named by path and returns a sorted list of directory entries.
// See readDirNames() in $GOROOT/pkg/path/filepath/path.go
func (b *Box) readDirNames(path string) ([]string, error) {

	f, err := b.Open(path)
	if err != nil {
		return nil, err
	}

	stat, err := f.Stat()
	if err != nil {
		return nil, err
	}

	if !stat.IsDir() {
		return nil, nil
	}

	infos, err := f.Readdir(0)
	f.Close()
	if err != nil {
		return nil, err
	}

	var names []string

	for _, info := range infos {
		names = append(names, info.Name())
	}

	sort.Strings(names)
	return names, nil

}
<commit_msg>Fixed a small error that caused the parent's os.FileInfo to be returned for each walked result instead of the info for the current file.<commit_after>package rice

import (
	"os"
	"path/filepath"
	"sort"
	"strings"
)

// Walk is like filepath.Walk()
// Visit http://golang.org/pkg/path/filepath/#Walk for more information
func (b *Box) Walk(path string, walkFn filepath.WalkFunc) error {

	pathFile, err := b.Open(path)
	if err != nil {
		return err
	}

	pathInfo, err := pathFile.Stat()
	if err != nil {
		return err
	}

	if b.IsAppended() || b.IsEmbedded() {
		return b.walk(path, pathInfo, walkFn)
	}

	// We don't have any embedded or appended box so use live filesystem mode
	return filepath.Walk(b.name+string(os.PathSeparator)+path, func(path string, info os.FileInfo, err error) error {

		// Strip out the box name from the returned paths
		path = strings.Replace(path, b.name+string(os.PathSeparator), "", -1)
		return walkFn(path, info, err)

	})

}

// walk recursively descends path.
// See walk() in $GOROOT/src/pkg/path/filepath/path.go
func (b *Box) walk(path string, info os.FileInfo, walkFn filepath.WalkFunc) error {

	err := walkFn(path, info, nil)
	if err != nil {
		if info.IsDir() && err == filepath.SkipDir {
			return nil
		}
		return err
	}

	if !info.IsDir() {
		return nil
	}

	names, err := b.readDirNames(path)
	if err != nil {
		return walkFn(path, info, err)
	}

	for _, name := range names {

		filename := filepath.Join(path, name)
		fileObject, err := b.Open(filename)
		if err != nil {
			return err
		}

		fileInfo, err := fileObject.Stat()
		if err != nil {
			if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir {
				return err
			}
		} else {
			err = b.walk(filename, fileInfo, walkFn)
			if err != nil {
				if !fileInfo.IsDir() || err != filepath.SkipDir {
					return err
				}
			}
		}
	}

	return nil

}

// readDirNames reads the directory named by path and returns a sorted list of directory entries.
// See readDirNames() in $GOROOT/pkg/path/filepath/path.go
func (b *Box) readDirNames(path string) ([]string, error) {

	f, err := b.Open(path)
	if err != nil {
		return nil, err
	}

	stat, err := f.Stat()
	if err != nil {
		return nil, err
	}

	if !stat.IsDir() {
		return nil, nil
	}

	infos, err := f.Readdir(0)
	f.Close()
	if err != nil {
		return nil, err
	}

	var names []string

	for _, info := range infos {
		names = append(names, info.Name())
	}

	sort.Strings(names)
	return names, nil

}
<|endoftext|>


<commit_before>package wave

import (
	"sync"
)

// Once prepares a wave that will only execute one time after Start is called
// on the returned handle.
func Once(concurrency int, vals []string, callback func(string)) *handle {
	h := newHandle()
	go func() {
		<-h.startChan
		doTheWave(concurrency, vals, callback, h)
		close(h.stopChan)
	}()
	return h
}

func doTheWave(concurrency int, vals []string, callback func(string), h *handle) {
	valChan := make(chan string, 10)
	go func() {
		for _, val := range vals {
			valChan <- val
		}
		close(valChan)
	}()
	wg := sync.WaitGroup{}
	for i := 0; i < concurrency; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for {
				select {
				case <-h.interruptChan:
					return
				default:
					select {
					case <-h.interruptChan:
						return
					case val, ok := <-valChan:
						if !ok {
							return
						}
						callback(val)
					}
				}
			}
		}()
	}
	wg.Wait()
	if _, ok := <-valChan; ok {
		h.trigger(h.interruptFuncs)
	} else {
		h.trigger(h.eachFuncs)
	}
}

// Continuous prepares a wave that will repeat indefinitely unless interrupted
// by one of the available event triggers. Start must be called on the returned
// handle to begin the wave.
func Continuous(concurrency int, vals []string, callback func(string)) *handle {
	h := newHandle()
	go func() {
		<-h.startChan
		first := true
	loop:
		for {
			select {
			case <-h.interruptChan:
				break loop
			case <-h.finishChan:
				if first {
					doTheWave(concurrency, vals, callback, h)
					first = false
				}
				break loop
			default:
				doTheWave(concurrency, vals, callback, h)
				first = false
			}
		}
		close(h.stopChan)
	}()
	return h
}

type handle struct {
	start, interrupt, finish sync.Once

	startChan      chan struct{} // Close to request start
	interruptChan  chan struct{} // Close to request interrupt
	finishChan     chan struct{} // Close to request finish
	stopChan       chan struct{} // Close when stopped
	stopFuncs      []func()
	interruptFuncs []func()
	eachFuncs      []func()
	funcsLock      sync.RWMutex // Guards all []func()
}

func newHandle() *handle {
	return &handle{
		startChan:      make(chan struct{}),
		interruptChan:  make(chan struct{}),
		finishChan:     make(chan struct{}),
		stopChan:       make(chan struct{}),
		stopFuncs:      []func(){},
		interruptFuncs: []func(){},
		eachFuncs:      []func(){},
	}
}

func (h *handle) trigger(fs []func()) {
	wg := sync.WaitGroup{}
	h.funcsLock.RLock()
	for _, f := range fs {
		wg.Add(1)
		go func() { f(); wg.Done() }()
	}
	h.funcsLock.RUnlock()
	wg.Wait()
}

// Start begins the wave. It must be called for the wave to proceed.
// For continuous waves, the first call to Start is all that is needed. The wave
// will loop continuously after that.
func (h *handle) Start() {
	h.start.Do(func() {
		close(h.startChan)
	})
}

// Interrupt allows running callbacks to finish while preventing the wave from
// continuing. It will block until all callbacks finish.
func (h *handle) Interrupt() {
	h.interrupt.Do(func() {
		close(h.interruptChan)
	})
	h.Wait()
}

// Finish will block until the current wave is completed, then no further waves
// will be started.
// For convenience, Finish starts the wave if it hasn't started yet.
// Note: if Interrupt is called, Finish will unblock whenever the wave stops,
// whether or not it truly finished an entire wave.  TODO return boolean
func (h *handle) Finish() {
	h.Start()
	h.finish.Do(func() {
		close(h.finishChan)
	})
	h.Wait()
}

// Wait blocks until the wave signals a Stop.
func (h *handle) Wait() {
	<-h.stopChan
}

// OnStop registers a function to be called when the wave has stopped for any
// reason.
func (h *handle) OnStop(f func()) {
	h.funcsLock.Lock()
	h.stopFuncs = append(h.stopFuncs, f)
	h.funcsLock.Unlock()
}

// OnInterrupt registers a function to be called if the wave is interrupted.
// The callback will be invoked after processing has finished.
func (h *handle) OnInterrupt(f func()) {
	h.funcsLock.Lock()
	h.interruptFuncs = append(h.interruptFuncs, f)
	h.funcsLock.Unlock()
}

// AfterEach returns a channel that will send after each full wave has completed.
// It will not send unless the whole set of values has been processed.
func (h *handle) AfterEach(f func()) {
	h.funcsLock.Lock()
	h.eachFuncs = append(h.eachFuncs, f)
	h.funcsLock.Unlock()
}
<commit_msg>Remove Interrupt callbacks<commit_after>package wave

import (
	"sync"
)

// Once prepares a wave that will only execute one time after Start is called
// on the returned handle.
func Once(concurrency int, vals []string, callback func(string)) *handle {
	h := newHandle()
	go func() {
		<-h.startChan
		doTheWave(concurrency, vals, callback, h)
		close(h.stopChan)
	}()
	return h
}

func doTheWave(concurrency int, vals []string, callback func(string), h *handle) {
	valChan := make(chan string, 10)
	go func() {
		for _, val := range vals {
			valChan <- val
		}
		close(valChan)
	}()
	wg := sync.WaitGroup{}
	for i := 0; i < concurrency; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for {
				select {
				case <-h.interruptChan:
					return
				default:
					select {
					case <-h.interruptChan:
						return
					case val, ok := <-valChan:
						if !ok {
							return
						}
						callback(val)
					}
				}
			}
		}()
	}
	wg.Wait()
	h.trigger(h.eachFuncs)
}

// Continuous prepares a wave that will repeat indefinitely unless interrupted
// by one of the available event triggers. Start must be called on the returned
// handle to begin the wave.
func Continuous(concurrency int, vals []string, callback func(string)) *handle {
	h := newHandle()
	go func() {
		<-h.startChan
		first := true
	loop:
		for {
			select {
			case <-h.interruptChan:
				break loop
			case <-h.finishChan:
				if first {
					doTheWave(concurrency, vals, callback, h)
					first = false
				}
				break loop
			default:
				doTheWave(concurrency, vals, callback, h)
				first = false
			}
		}
		close(h.stopChan)
	}()
	return h
}

type handle struct {
	start, interrupt, finish sync.Once

	startChan     chan struct{} // Close to request start
	interruptChan chan struct{} // Close to request interrupt
	finishChan    chan struct{} // Close to request finish
	stopChan      chan struct{} // Close when stopped
	stopFuncs     []func()
	eachFuncs     []func()
	funcsLock     sync.RWMutex // Guards all []func()
}

func newHandle() *handle {
	return &handle{
		startChan:     make(chan struct{}),
		interruptChan: make(chan struct{}),
		finishChan:    make(chan struct{}),
		stopChan:      make(chan struct{}),
		stopFuncs:     []func(){},
		eachFuncs:     []func(){},
	}
}

func (h *handle) trigger(fs []func()) {
	wg := sync.WaitGroup{}
	h.funcsLock.RLock()
	for _, f := range fs {
		wg.Add(1)
		go func() { f(); wg.Done() }()
	}
	h.funcsLock.RUnlock()
	wg.Wait()
}

// Start begins the wave. It must be called for the wave to proceed.
// For continuous waves, the first call to Start is all that is needed. The wave
// will loop continuously after that.
func (h *handle) Start() {
	h.start.Do(func() {
		close(h.startChan)
	})
}

// Interrupt allows running callbacks to finish while preventing the wave from
// continuing. It will block until all callbacks finish.
func (h *handle) Interrupt() {
	h.interrupt.Do(func() {
		close(h.interruptChan)
	})
	h.Wait()
}

// Finish will block until the current wave is completed, then no further waves
// will be started.
// For convenience, Finish starts the wave if it hasn't started yet.
// Note: if Interrupt is called, Finish will unblock whenever the wave stops,
// whether or not it truly finished an entire wave.  TODO return boolean
func (h *handle) Finish() {
	h.Start()
	h.finish.Do(func() {
		close(h.finishChan)
	})
	h.Wait()
}

// Wait blocks until the wave signals a Stop.
func (h *handle) Wait() {
	<-h.stopChan
}

// OnStop registers a function to be called when the wave has stopped for any
// reason.
func (h *handle) OnStop(f func()) {
	h.funcsLock.Lock()
	h.stopFuncs = append(h.stopFuncs, f)
	h.funcsLock.Unlock()
}

// AfterEach returns a channel that will send after each full wave has completed.
// It will not send unless the whole set of values has been processed.
func (h *handle) AfterEach(f func()) {
	h.funcsLock.Lock()
	h.eachFuncs = append(h.eachFuncs, f)
	h.funcsLock.Unlock()
}
<|endoftext|>


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

package cli

import (
	"database/sql"
	"fmt"
	"time"

	"github.com/olekukonko/tablewriter"

	"github.com/cockroachdb/cockroach/security"
	"github.com/cockroachdb/cockroach/sql/parser"
)

func makeSQLClient() *sql.DB {
	// Use the sql administrator by default (root user).
	// TODO(marc): allow passing on the commandline.
	db, err := sql.Open("cockroach",
		fmt.Sprintf("%s://%s@%s?certs=%s",
			context.HTTPRequestScheme(),
			security.RootUser,
			context.Addr,
			context.Certs))
	if err != nil {
		fmt.Fprintf(osStderr, "failed to initialize SQL client: %s\n", err)
		osExit(1)
	}
	return db
}

// fmtMap is a mapping from column name to a function that takes the raw input,
// and outputs the string to be displayed.
type fmtMap map[string]func(interface{}) string

// runQuery takes a 'query' with optional 'parameters'.
// It runs the sql query and returns a list of columns names and a list of rows.
func runQuery(db *sql.DB, query string, parameters ...interface{}) (
	[]string, [][]string, error) {
	return runQueryWithFormat(db, nil, query, parameters...)
}

// runQuery takes a 'query' with optional 'parameters'.
// It runs the sql query and returns a list of columns names and a list of rows.
// If 'format' is not nil, the values with column name
// found in the map are run through the corresponding callback.
func runQueryWithFormat(db *sql.DB, format fmtMap, query string, parameters ...interface{}) (
	[]string, [][]string, error) {
	rows, err := db.Query(query, parameters...)
	if err != nil {
		return nil, nil, fmt.Errorf("query error: %s", err)
	}

	defer rows.Close()
	return sqlRowsToStrings(rows, format)
}

// runPrettyQueryWithFormat takes a 'query' with optional 'parameters'.
// It runs the sql query and writes pretty output to osStdout.
func runPrettyQuery(db *sql.DB, query string, parameters ...interface{}) error {
	return runPrettyQueryWithFormat(db, nil, query, parameters...)
}

// runPrettyQueryWithFormat takes a 'query' with optional 'parameters'.
// It runs the sql query and writes pretty output to osStdout.
// If 'format' is not nil, the values with column name
// found in the map are run through the corresponding callback.
func runPrettyQueryWithFormat(db *sql.DB, format fmtMap, query string, parameters ...interface{}) error {
	cols, allRows, err := runQueryWithFormat(db, format, query, parameters...)
	if err != nil {
		return err
	}
	return printQueryOutput(cols, allRows)
}

// sqlRowsToStrings turns 'rows' into a list of rows, each of which
// is a  list of column values.
// 'rows' should be closed by the caller.
// If 'format' is not nil, the values with column name
// found in the map are run through the corresponding callback.
// It returns the header row followed by all data rows.
// If both the header row and list of rows are empty, it means no row
// information was returned (eg: statement was not a query).
func sqlRowsToStrings(rows *sql.Rows, format fmtMap) ([]string, [][]string, error) {
	cols, err := rows.Columns()
	if err != nil {
		return nil, nil, fmt.Errorf("rows.Columns() error: %s", err)
	}

	if len(cols) == 0 {
		return nil, nil, nil
	}

	vals := make([]interface{}, len(cols))
	for i := range vals {
		vals[i] = new(interface{})
	}

	allRows := [][]string{}
	for rows.Next() {
		rowStrings := make([]string, len(cols))
		if err := rows.Scan(vals...); err != nil {
			return nil, nil, fmt.Errorf("scan error: %s", err)
		}
		for i, v := range vals {
			if f, ok := format[cols[i]]; ok {
				rowStrings[i] = f(*v.(*interface{}))
			} else {
				rowStrings[i] = formatVal(*v.(*interface{}))
			}
		}
		allRows = append(allRows, rowStrings)
	}

	return cols, allRows, nil
}

// printQueryOutput takes a list of column names and a list of row contents
// writes a pretty table to osStdout, or "OK" if empty.
func printQueryOutput(cols []string, allRows [][]string) error {
	if len(cols) == 0 {
		// This operation did not return rows, just show success.
		fmt.Fprintln(osStdout, "OK")
		return nil
	}

	// Initialize tablewriter and set column names as the header row.
	table := tablewriter.NewWriter(osStdout)
	table.SetAutoFormatHeaders(false)
	table.SetAutoWrapText(false)
	table.SetHeader(cols)

	for _, row := range allRows {
		if err := table.Append(row); err != nil {
			return err
		}
	}

	table.Render()
	return nil
}

func formatVal(val interface{}) string {
	switch t := val.(type) {
	case nil:
		return "NULL"
	case time.Time:
		return t.Format(parser.TimestampWithOffsetZoneFormat)
	}
	// Note that this prints a Go-syntax representation of the value.
	// This is to ensure that binary protobufs print escaped.
	return fmt.Sprintf("%#v", val)
}
<commit_msg>cli: only escape strings<commit_after>// Copyright 2015 The Cockroach Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License. See the AUTHORS file
// for names of contributors.
//
// Author: Marc berhault (marc@cockroachlabs.com)

package cli

import (
	"database/sql"
	"fmt"

	"github.com/olekukonko/tablewriter"

	"github.com/cockroachdb/cockroach/security"
)

func makeSQLClient() *sql.DB {
	// Use the sql administrator by default (root user).
	// TODO(marc): allow passing on the commandline.
	db, err := sql.Open("cockroach",
		fmt.Sprintf("%s://%s@%s?certs=%s",
			context.HTTPRequestScheme(),
			security.RootUser,
			context.Addr,
			context.Certs))
	if err != nil {
		fmt.Fprintf(osStderr, "failed to initialize SQL client: %s\n", err)
		osExit(1)
	}
	return db
}

// fmtMap is a mapping from column name to a function that takes the raw input,
// and outputs the string to be displayed.
type fmtMap map[string]func(interface{}) string

// runQuery takes a 'query' with optional 'parameters'.
// It runs the sql query and returns a list of columns names and a list of rows.
func runQuery(db *sql.DB, query string, parameters ...interface{}) (
	[]string, [][]string, error) {
	return runQueryWithFormat(db, nil, query, parameters...)
}

// runQuery takes a 'query' with optional 'parameters'.
// It runs the sql query and returns a list of columns names and a list of rows.
// If 'format' is not nil, the values with column name
// found in the map are run through the corresponding callback.
func runQueryWithFormat(db *sql.DB, format fmtMap, query string, parameters ...interface{}) (
	[]string, [][]string, error) {
	rows, err := db.Query(query, parameters...)
	if err != nil {
		return nil, nil, fmt.Errorf("query error: %s", err)
	}

	defer rows.Close()
	return sqlRowsToStrings(rows, format)
}

// runPrettyQueryWithFormat takes a 'query' with optional 'parameters'.
// It runs the sql query and writes pretty output to osStdout.
func runPrettyQuery(db *sql.DB, query string, parameters ...interface{}) error {
	return runPrettyQueryWithFormat(db, nil, query, parameters...)
}

// runPrettyQueryWithFormat takes a 'query' with optional 'parameters'.
// It runs the sql query and writes pretty output to osStdout.
// If 'format' is not nil, the values with column name
// found in the map are run through the corresponding callback.
func runPrettyQueryWithFormat(db *sql.DB, format fmtMap, query string, parameters ...interface{}) error {
	cols, allRows, err := runQueryWithFormat(db, format, query, parameters...)
	if err != nil {
		return err
	}
	return printQueryOutput(cols, allRows)
}

// sqlRowsToStrings turns 'rows' into a list of rows, each of which
// is a  list of column values.
// 'rows' should be closed by the caller.
// If 'format' is not nil, the values with column name
// found in the map are run through the corresponding callback.
// It returns the header row followed by all data rows.
// If both the header row and list of rows are empty, it means no row
// information was returned (eg: statement was not a query).
func sqlRowsToStrings(rows *sql.Rows, format fmtMap) ([]string, [][]string, error) {
	cols, err := rows.Columns()
	if err != nil {
		return nil, nil, fmt.Errorf("rows.Columns() error: %s", err)
	}

	if len(cols) == 0 {
		return nil, nil, nil
	}

	vals := make([]interface{}, len(cols))
	for i := range vals {
		vals[i] = new(interface{})
	}

	allRows := [][]string{}
	for rows.Next() {
		rowStrings := make([]string, len(cols))
		if err := rows.Scan(vals...); err != nil {
			return nil, nil, fmt.Errorf("scan error: %s", err)
		}
		for i, v := range vals {
			if f, ok := format[cols[i]]; ok {
				rowStrings[i] = f(*v.(*interface{}))
			} else {
				rowStrings[i] = formatVal(*v.(*interface{}))
			}
		}
		allRows = append(allRows, rowStrings)
	}

	return cols, allRows, nil
}

// printQueryOutput takes a list of column names and a list of row contents
// writes a pretty table to osStdout, or "OK" if empty.
func printQueryOutput(cols []string, allRows [][]string) error {
	if len(cols) == 0 {
		// This operation did not return rows, just show success.
		fmt.Fprintln(osStdout, "OK")
		return nil
	}

	// Initialize tablewriter and set column names as the header row.
	table := tablewriter.NewWriter(osStdout)
	table.SetAutoFormatHeaders(false)
	table.SetAutoWrapText(false)
	table.SetHeader(cols)

	for _, row := range allRows {
		if err := table.Append(row); err != nil {
			return err
		}
	}

	table.Render()
	return nil
}

func formatVal(val interface{}) string {
	switch t := val.(type) {
	case nil:
		return "NULL"
	case string:
		// Ensure that binary protobufs print escaped.
		return fmt.Sprintf("%q", t)
	}
	return fmt.Sprint(val)
}
<|endoftext|>


<commit_before>package store_test

import (
	"database/sql"
	"errors"
	"fmt"
	"lib/db"
	"lib/testsupport"
	"math/rand"
	"policy-server/fakes"
	"policy-server/models"
	"policy-server/store"

	"github.com/jmoiron/sqlx"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Store", func() {
	var dataStore store.Store
	var testDatabase *testsupport.TestDatabase
	var realDb *sqlx.DB
	var mockDb *fakes.Db
	var group store.GroupCreator
	var destination store.DestinationCreator
	var policy store.PolicyCreator

	BeforeEach(func() {
		mockDb = &fakes.Db{}

		dbName := fmt.Sprintf("test_netman_database_%x", rand.Int())
		dbConnectionInfo := testsupport.GetDBConnectionInfo()
		testDatabase = dbConnectionInfo.CreateDatabase(dbName)

		var err error
		realDb, err = db.GetConnectionPool(testDatabase.URL())
		Expect(err).NotTo(HaveOccurred())

		group = &store.Group{}
		destination = &store.Destination{}
		policy = &store.Policy{}

		dataStore, err = store.New(realDb, group, destination, policy)
		Expect(err).NotTo(HaveOccurred())
		mockDb.DriverNameReturns(realDb.DriverName())
	})

	AfterEach(func() {
		if realDb != nil {
			Expect(realDb.Close()).To(Succeed())
		}
		if testDatabase != nil {
			testDatabase.Destroy()
		}
	})

	Describe("Connecting to the database and migrating", func() {
		Context("when the tables already exist", func() {
			It("succeeds", func() {
				_, err := store.New(realDb, group, destination, policy)
				Expect(err).NotTo(HaveOccurred())
			})
		})

		Context("when the db operation fails", func() {
			BeforeEach(func() {
				mockDb.ExecReturns(nil, errors.New("some error"))
			})

			It("should return a sensible error", func() {
				_, err := store.New(mockDb, group, destination, policy)
				Expect(err).To(MatchError("setting up tables: some error"))
			})
		})
	})

	Describe("Create", func() {
		It("saves the policies", func() {
			policies := []models.Policy{{
				Source: models.Source{"some-app-guid"},
				Destination: models.Destination{
					ID:       "some-other-app-guid",
					Protocol: "tcp",
					Port:     8080,
				},
			}, {
				Source: models.Source{"another-app-guid"},
				Destination: models.Destination{
					ID:       "some-other-app-guid",
					Protocol: "udp",
					Port:     1234,
				},
			}}

			err := dataStore.Create(policies)
			Expect(err).NotTo(HaveOccurred())

			p, err := dataStore.All()
			Expect(err).NotTo(HaveOccurred())
			Expect(len(p)).To(Equal(2))
		})

		Context("when a policy with the same content already exists", func() {
			It("does not duplicate table rows", func() {
				policies := []models.Policy{}

				err := dataStore.Create(policies)
				Expect(err).NotTo(HaveOccurred())

				policyDuplicate := []models.Policy{{
					Source: models.Source{"some-app-guid"},
					Destination: models.Destination{
						ID:       "some-other-app-guid",
						Protocol: "tcp",
						Port:     8080,
					},
				}, {
					Source: models.Source{"some-app-guid"},
					Destination: models.Destination{
						ID:       "some-other-app-guid",
						Protocol: "tcp",
						Port:     8080,
					},
				}}

				err = dataStore.Create(policyDuplicate)
				Expect(err).NotTo(HaveOccurred())

				p, err := dataStore.All()
				Expect(err).NotTo(HaveOccurred())
				Expect(len(p)).To(Equal(1))
			})
		})

		Context("when a transaction create fails", func() {
			var err error

			BeforeEach(func() {
				mockDb.BeginxReturns(nil, errors.New("some-db-error"))
				dataStore, err = store.New(mockDb, group, destination, policy)
				Expect(err).NotTo(HaveOccurred())
			})

			It("returns an error", func() {
				err = dataStore.Create(nil)
				Expect(err).To(MatchError("begin transaction: some-db-error"))
			})
		})

		Context("when a Group create record fails", func() {
			var fakeGroup *fakes.GroupCreator
			var err error

			BeforeEach(func() {
				fakeGroup = &fakes.GroupCreator{}
				fakeGroup.CreateReturns(-1, errors.New("some-insert-error"))

				dataStore, err = store.New(realDb, fakeGroup, destination, policy)
				Expect(err).NotTo(HaveOccurred())
			})

			It("returns a error", func() {
				err = dataStore.Create([]models.Policy{{
					Source: models.Source{"some-app-guid"},
					Destination: models.Destination{
						ID:       "some-other-app-guid",
						Protocol: "tcp",
						Port:     8080,
					},
				}})
				Expect(err).To(MatchError("creating group: some-insert-error"))
			})

		})

		Context("when the second create group fails", func() {
			var fakeGroup *fakes.GroupCreator
			var err error

			BeforeEach(func() {
				fakeGroup = &fakes.GroupCreator{}
				type response struct {
					Id  int
					Err error
				}

				responses := []response{
					{2, nil},
					{-1, errors.New("some-insert-error")},
				}
				fakeGroup.CreateStub = func(t store.Transaction, guid string) (int, error) {
					response := responses[0]
					responses = responses[1:]
					return response.Id, response.Err
				}

				dataStore, err = store.New(realDb, fakeGroup, destination, policy)
				Expect(err).NotTo(HaveOccurred())
			})

			It("returns the error", func() {
				err = dataStore.Create([]models.Policy{{
					Source: models.Source{"some-app-guid"},
					Destination: models.Destination{
						ID:       "some-other-app-guid",
						Protocol: "tcp",
						Port:     8080,
					},
				}})

				Expect(err).To(MatchError("creating group: some-insert-error"))
			})
		})

		Context("when a Destination create record fails", func() {
			var fakeDestination *fakes.DestinationCreator
			var err error

			BeforeEach(func() {
				fakeDestination = &fakes.DestinationCreator{}
				fakeDestination.CreateReturns(-1, errors.New("some-insert-error"))

				dataStore, err = store.New(realDb, group, fakeDestination, policy)
				Expect(err).NotTo(HaveOccurred())
			})

			It("returns a error", func() {
				err = dataStore.Create([]models.Policy{{
					Source: models.Source{"some-app-guid"},
					Destination: models.Destination{
						ID:       "some-other-app-guid",
						Protocol: "tcp",
						Port:     8080,
					},
				}})
				Expect(err).To(MatchError("creating destination: some-insert-error"))
				var groupsCount int
				err = realDb.QueryRow(`select count(*) from groups`).Scan(&groupsCount)
				Expect(groupsCount).To(BeZero())
			})
		})

		Context("when a Policy create record fails", func() {
			var fakePolicy *fakes.PolicyCreator
			var err error

			BeforeEach(func() {
				fakePolicy = &fakes.PolicyCreator{}
				fakePolicy.CreateReturns(errors.New("some-insert-error"))

				dataStore, err = store.New(realDb, group, destination, fakePolicy)
				Expect(err).NotTo(HaveOccurred())
			})

			It("returns a error", func() {
				err = dataStore.Create([]models.Policy{{
					Source: models.Source{"some-app-guid"},
					Destination: models.Destination{
						ID:       "some-other-app-guid",
						Protocol: "tcp",
						Port:     8080,
					},
				}})
				Expect(err).To(MatchError("creating policy: some-insert-error"))
			})
		})
	})

	Describe("All", func() {
		var expectedPolicies []models.Policy

		BeforeEach(func() {
			expectedPolicies = []models.Policy{models.Policy{
				Source: models.Source{"some-app-guid"},
				Destination: models.Destination{
					ID:       "some-other-app-guid",
					Protocol: "tcp",
					Port:     8080,
				},
			}}

			err := dataStore.Create(expectedPolicies)
			Expect(err).NotTo(HaveOccurred())
		})

		It("returns all containers that have been added", func() {
			policies, err := dataStore.All()
			Expect(err).NotTo(HaveOccurred())
			Expect(policies).To(ConsistOf(expectedPolicies))
		})

		Context("when the db operation fails", func() {
			BeforeEach(func() {
				mockDb.QueryReturns(nil, errors.New("some query error"))
			})

			It("should return a sensible error", func() {
				store, err := store.New(mockDb, group, destination, policy)
				Expect(err).NotTo(HaveOccurred())

				_, err = store.All()
				Expect(err).To(MatchError("listing all: some query error"))
			})
		})

		Context("when the query result parsing fails", func() {
			var rows *sql.Rows

			BeforeEach(func() {
				expectedPolicies = []models.Policy{models.Policy{
					Source: models.Source{"some-app-guid"},
					Destination: models.Destination{
						ID:       "some-other-app-guid",
						Protocol: "tcp",
						Port:     8080,
					},
				}}

				err := dataStore.Create(expectedPolicies)
				Expect(err).NotTo(HaveOccurred())

				_, err = store.New(realDb, group, destination, policy)
				Expect(err).NotTo(HaveOccurred())
				rows, err = realDb.Query(`select * from policies`)
				Expect(err).NotTo(HaveOccurred())

				mockDb.QueryReturns(rows, nil)
			})

			AfterEach(func() {
				rows.Close()
			})

			It("should return a sensible error", func() {
				store, err := store.New(mockDb, group, destination, policy)
				Expect(err).NotTo(HaveOccurred())

				_, err = store.All()
				Expect(err).To(MatchError("listing all: sql: expected 3 destination arguments in Scan, not 4"))
			})
		})
	})
})
<commit_msg>Be more general about the DB error message in a unit test<commit_after>package store_test

import (
	"database/sql"
	"errors"
	"fmt"
	"lib/db"
	"lib/testsupport"
	"math/rand"
	"policy-server/fakes"
	"policy-server/models"
	"policy-server/store"

	"github.com/jmoiron/sqlx"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Store", func() {
	var dataStore store.Store
	var testDatabase *testsupport.TestDatabase
	var realDb *sqlx.DB
	var mockDb *fakes.Db
	var group store.GroupCreator
	var destination store.DestinationCreator
	var policy store.PolicyCreator

	BeforeEach(func() {
		mockDb = &fakes.Db{}

		dbName := fmt.Sprintf("test_netman_database_%x", rand.Int())
		dbConnectionInfo := testsupport.GetDBConnectionInfo()
		testDatabase = dbConnectionInfo.CreateDatabase(dbName)

		var err error
		realDb, err = db.GetConnectionPool(testDatabase.URL())
		Expect(err).NotTo(HaveOccurred())

		group = &store.Group{}
		destination = &store.Destination{}
		policy = &store.Policy{}

		dataStore, err = store.New(realDb, group, destination, policy)
		Expect(err).NotTo(HaveOccurred())
		mockDb.DriverNameReturns(realDb.DriverName())
	})

	AfterEach(func() {
		if realDb != nil {
			Expect(realDb.Close()).To(Succeed())
		}
		if testDatabase != nil {
			testDatabase.Destroy()
		}
	})

	Describe("Connecting to the database and migrating", func() {
		Context("when the tables already exist", func() {
			It("succeeds", func() {
				_, err := store.New(realDb, group, destination, policy)
				Expect(err).NotTo(HaveOccurred())
			})
		})

		Context("when the db operation fails", func() {
			BeforeEach(func() {
				mockDb.ExecReturns(nil, errors.New("some error"))
			})

			It("should return a sensible error", func() {
				_, err := store.New(mockDb, group, destination, policy)
				Expect(err).To(MatchError("setting up tables: some error"))
			})
		})
	})

	Describe("Create", func() {
		It("saves the policies", func() {
			policies := []models.Policy{{
				Source: models.Source{"some-app-guid"},
				Destination: models.Destination{
					ID:       "some-other-app-guid",
					Protocol: "tcp",
					Port:     8080,
				},
			}, {
				Source: models.Source{"another-app-guid"},
				Destination: models.Destination{
					ID:       "some-other-app-guid",
					Protocol: "udp",
					Port:     1234,
				},
			}}

			err := dataStore.Create(policies)
			Expect(err).NotTo(HaveOccurred())

			p, err := dataStore.All()
			Expect(err).NotTo(HaveOccurred())
			Expect(len(p)).To(Equal(2))
		})

		Context("when a policy with the same content already exists", func() {
			It("does not duplicate table rows", func() {
				policies := []models.Policy{}

				err := dataStore.Create(policies)
				Expect(err).NotTo(HaveOccurred())

				policyDuplicate := []models.Policy{{
					Source: models.Source{"some-app-guid"},
					Destination: models.Destination{
						ID:       "some-other-app-guid",
						Protocol: "tcp",
						Port:     8080,
					},
				}, {
					Source: models.Source{"some-app-guid"},
					Destination: models.Destination{
						ID:       "some-other-app-guid",
						Protocol: "tcp",
						Port:     8080,
					},
				}}

				err = dataStore.Create(policyDuplicate)
				Expect(err).NotTo(HaveOccurred())

				p, err := dataStore.All()
				Expect(err).NotTo(HaveOccurred())
				Expect(len(p)).To(Equal(1))
			})
		})

		Context("when a transaction create fails", func() {
			var err error

			BeforeEach(func() {
				mockDb.BeginxReturns(nil, errors.New("some-db-error"))
				dataStore, err = store.New(mockDb, group, destination, policy)
				Expect(err).NotTo(HaveOccurred())
			})

			It("returns an error", func() {
				err = dataStore.Create(nil)
				Expect(err).To(MatchError("begin transaction: some-db-error"))
			})
		})

		Context("when a Group create record fails", func() {
			var fakeGroup *fakes.GroupCreator
			var err error

			BeforeEach(func() {
				fakeGroup = &fakes.GroupCreator{}
				fakeGroup.CreateReturns(-1, errors.New("some-insert-error"))

				dataStore, err = store.New(realDb, fakeGroup, destination, policy)
				Expect(err).NotTo(HaveOccurred())
			})

			It("returns a error", func() {
				err = dataStore.Create([]models.Policy{{
					Source: models.Source{"some-app-guid"},
					Destination: models.Destination{
						ID:       "some-other-app-guid",
						Protocol: "tcp",
						Port:     8080,
					},
				}})
				Expect(err).To(MatchError("creating group: some-insert-error"))
			})

		})

		Context("when the second create group fails", func() {
			var fakeGroup *fakes.GroupCreator
			var err error

			BeforeEach(func() {
				fakeGroup = &fakes.GroupCreator{}
				type response struct {
					Id  int
					Err error
				}

				responses := []response{
					{2, nil},
					{-1, errors.New("some-insert-error")},
				}
				fakeGroup.CreateStub = func(t store.Transaction, guid string) (int, error) {
					response := responses[0]
					responses = responses[1:]
					return response.Id, response.Err
				}

				dataStore, err = store.New(realDb, fakeGroup, destination, policy)
				Expect(err).NotTo(HaveOccurred())
			})

			It("returns the error", func() {
				err = dataStore.Create([]models.Policy{{
					Source: models.Source{"some-app-guid"},
					Destination: models.Destination{
						ID:       "some-other-app-guid",
						Protocol: "tcp",
						Port:     8080,
					},
				}})

				Expect(err).To(MatchError("creating group: some-insert-error"))
			})
		})

		Context("when a Destination create record fails", func() {
			var fakeDestination *fakes.DestinationCreator
			var err error

			BeforeEach(func() {
				fakeDestination = &fakes.DestinationCreator{}
				fakeDestination.CreateReturns(-1, errors.New("some-insert-error"))

				dataStore, err = store.New(realDb, group, fakeDestination, policy)
				Expect(err).NotTo(HaveOccurred())
			})

			It("returns a error", func() {
				err = dataStore.Create([]models.Policy{{
					Source: models.Source{"some-app-guid"},
					Destination: models.Destination{
						ID:       "some-other-app-guid",
						Protocol: "tcp",
						Port:     8080,
					},
				}})
				Expect(err).To(MatchError("creating destination: some-insert-error"))
				var groupsCount int
				err = realDb.QueryRow(`select count(*) from groups`).Scan(&groupsCount)
				Expect(groupsCount).To(BeZero())
			})
		})

		Context("when a Policy create record fails", func() {
			var fakePolicy *fakes.PolicyCreator
			var err error

			BeforeEach(func() {
				fakePolicy = &fakes.PolicyCreator{}
				fakePolicy.CreateReturns(errors.New("some-insert-error"))

				dataStore, err = store.New(realDb, group, destination, fakePolicy)
				Expect(err).NotTo(HaveOccurred())
			})

			It("returns a error", func() {
				err = dataStore.Create([]models.Policy{{
					Source: models.Source{"some-app-guid"},
					Destination: models.Destination{
						ID:       "some-other-app-guid",
						Protocol: "tcp",
						Port:     8080,
					},
				}})
				Expect(err).To(MatchError("creating policy: some-insert-error"))
			})
		})
	})

	Describe("All", func() {
		var expectedPolicies []models.Policy

		BeforeEach(func() {
			expectedPolicies = []models.Policy{models.Policy{
				Source: models.Source{"some-app-guid"},
				Destination: models.Destination{
					ID:       "some-other-app-guid",
					Protocol: "tcp",
					Port:     8080,
				},
			}}

			err := dataStore.Create(expectedPolicies)
			Expect(err).NotTo(HaveOccurred())
		})

		It("returns all containers that have been added", func() {
			policies, err := dataStore.All()
			Expect(err).NotTo(HaveOccurred())
			Expect(policies).To(ConsistOf(expectedPolicies))
		})

		Context("when the db operation fails", func() {
			BeforeEach(func() {
				mockDb.QueryReturns(nil, errors.New("some query error"))
			})

			It("should return a sensible error", func() {
				store, err := store.New(mockDb, group, destination, policy)
				Expect(err).NotTo(HaveOccurred())

				_, err = store.All()
				Expect(err).To(MatchError("listing all: some query error"))
			})
		})

		Context("when the query result parsing fails", func() {
			var rows *sql.Rows

			BeforeEach(func() {
				expectedPolicies = []models.Policy{models.Policy{
					Source: models.Source{"some-app-guid"},
					Destination: models.Destination{
						ID:       "some-other-app-guid",
						Protocol: "tcp",
						Port:     8080,
					},
				}}

				err := dataStore.Create(expectedPolicies)
				Expect(err).NotTo(HaveOccurred())

				_, err = store.New(realDb, group, destination, policy)
				Expect(err).NotTo(HaveOccurred())
				rows, err = realDb.Query(`select * from policies`)
				Expect(err).NotTo(HaveOccurred())

				mockDb.QueryReturns(rows, nil)
			})

			AfterEach(func() {
				rows.Close()
			})

			It("should return a sensible error", func() {
				store, err := store.New(mockDb, group, destination, policy)
				Expect(err).NotTo(HaveOccurred())

				_, err = store.All()
				Expect(err).To(MatchError(ContainSubstring("listing all: sql: expected")))
			})
		})
	})
})
<|endoftext|>


<commit_before>package par1

import (
	"path/filepath"
	"testing"

	"github.com/klauspost/reedsolomon"
	"github.com/stretchr/testify/require"
)

type testEncoderDelegate struct {
	t *testing.T
}

func (d testEncoderDelegate) OnDataFileLoad(i, n int, path string, byteCount int, err error) {
	d.t.Helper()
	d.t.Logf("OnDataFileLoad(%d, %d, byteCount=%d, %s, %v)", i, n, byteCount, path, err)
}

func (d testEncoderDelegate) OnVolumeFileWrite(i, n int, path string, dataByteCount, byteCount int, err error) {
	d.t.Helper()
	d.t.Logf("OnVolumeFileWrite(%d, %d, %s, dataByteCount=%d, byteCount=%d, %v)", i, n, path, dataByteCount, byteCount, err)
}

func makeEncoderTestFileIO(t *testing.T) testFileIO {
	return makeTestFileIO(t, rootDir(), map[string][]byte{
		"file.rar":                                {0x1, 0x2, 0x3},
		filepath.Join("dir1", "file.r01"):         {0x5, 0x6, 0x7, 0x8},
		filepath.Join("dir2", "file.r02"):         {0x9, 0xa, 0xb, 0xc},
		filepath.Join("dir2", "dir3", "file.r03"): {0xd, 0xe},
		filepath.Join("dir4", "dir5", "file.r04"): nil,
	})
}

func TestEncodeParity(t *testing.T) {
	io := makeEncoderTestFileIO(t)

	paths := io.paths()

	encoder, err := newEncoder(io, testEncoderDelegate{t}, paths, 3)
	require.NoError(t, err)

	err = encoder.LoadFileData()
	require.NoError(t, err)

	err = encoder.ComputeParityData()
	require.NoError(t, err)

	rs, err := reedsolomon.New(len(encoder.fileData), encoder.volumeCount, reedsolomon.WithPAR1Matrix())
	require.NoError(t, err)

	var shards [][]byte
	for _, path := range paths {
		data := io.getData(path)
		shards = append(shards, append(data, make([]byte, 4-len(data))...))
	}

	shards = append(shards, encoder.parityData...)

	ok, err := rs.Verify(shards)
	require.NoError(t, err)
	require.True(t, ok)
}

func TestWriteParity(t *testing.T) {
	io := makeEncoderTestFileIO(t)

	paths := io.paths()

	encoder, err := newEncoder(io, testEncoderDelegate{t}, paths, 3)
	require.NoError(t, err)

	err = encoder.LoadFileData()
	require.NoError(t, err)

	err = encoder.ComputeParityData()
	require.NoError(t, err)

	err = encoder.Write("parity.par")
	require.NoError(t, err)

	for _, path := range paths {
		io.moveData(path, filepath.Base(path))
	}

	decoder, err := newDecoder(io, testDecoderDelegate{t}, "parity.par")
	require.NoError(t, err)

	err = decoder.LoadFileData()
	require.NoError(t, err)
	err = decoder.LoadParityData()
	require.NoError(t, err)

	needsRepair, err := decoder.Verify()
	require.NoError(t, err)
	require.False(t, needsRepair)
}
<commit_msg>Exercise more subdirs in PAR1 encoder tests<commit_after>package par1

import (
	"path/filepath"
	"testing"

	"github.com/klauspost/reedsolomon"
	"github.com/stretchr/testify/require"
)

type testEncoderDelegate struct {
	t *testing.T
}

func (d testEncoderDelegate) OnDataFileLoad(i, n int, path string, byteCount int, err error) {
	d.t.Helper()
	d.t.Logf("OnDataFileLoad(%d, %d, byteCount=%d, %s, %v)", i, n, byteCount, path, err)
}

func (d testEncoderDelegate) OnVolumeFileWrite(i, n int, path string, dataByteCount, byteCount int, err error) {
	d.t.Helper()
	d.t.Logf("OnVolumeFileWrite(%d, %d, %s, dataByteCount=%d, byteCount=%d, %v)", i, n, path, dataByteCount, byteCount, err)
}

func makeEncoderTestFileIO(t *testing.T, workingDir string) testFileIO {
	return makeTestFileIO(t, workingDir, map[string][]byte{
		"file.rar":                                {0x1, 0x2, 0x3},
		filepath.Join("dir1", "file.r01"):         {0x5, 0x6, 0x7, 0x8},
		filepath.Join("dir2", "file.r02"):         {0x9, 0xa, 0xb, 0xc},
		filepath.Join("dir2", "dir3", "file.r03"): {0xd, 0xe},
		filepath.Join("dir4", "dir5", "file.r04"): nil,
	})
}

func TestEncodeParity(t *testing.T) {
	io := makeEncoderTestFileIO(t, rootDir())

	paths := io.paths()

	encoder, err := newEncoder(io, testEncoderDelegate{t}, paths, 3)
	require.NoError(t, err)

	err = encoder.LoadFileData()
	require.NoError(t, err)

	err = encoder.ComputeParityData()
	require.NoError(t, err)

	rs, err := reedsolomon.New(len(encoder.fileData), encoder.volumeCount, reedsolomon.WithPAR1Matrix())
	require.NoError(t, err)

	var shards [][]byte
	for _, path := range paths {
		data := io.getData(path)
		shards = append(shards, append(data, make([]byte, 4-len(data))...))
	}

	shards = append(shards, encoder.parityData...)

	ok, err := rs.Verify(shards)
	require.NoError(t, err)
	require.True(t, ok)
}

func testWriteParity(t *testing.T, workingDir string, useAbsPath bool) {
	io := makeEncoderTestFileIO(t, workingDir)

	paths := io.paths()

	encoder, err := newEncoder(io, testEncoderDelegate{t}, paths, 3)
	require.NoError(t, err)

	err = encoder.LoadFileData()
	require.NoError(t, err)

	err = encoder.ComputeParityData()
	require.NoError(t, err)

	parPath := "file.par"
	if useAbsPath {
		parPath = filepath.Join(workingDir, parPath)
	}
	err = encoder.Write(parPath)
	require.NoError(t, err)

	for _, path := range paths {
		io.moveData(path, filepath.Base(path))
	}

	decoder, err := newDecoder(io, testDecoderDelegate{t}, parPath)
	require.NoError(t, err)

	err = decoder.LoadFileData()
	require.NoError(t, err)
	err = decoder.LoadParityData()
	require.NoError(t, err)

	needsRepair, err := decoder.Verify()
	require.NoError(t, err)
	require.False(t, needsRepair)
}

func TestWriteParity(t *testing.T) {
	runOnExampleWorkingDirs(t, testWriteParity)
}
<|endoftext|>


<commit_before>package clocky

import (
	"io/ioutil"
	"os"
	"strconv"
	"time"

	"appengine"
	"appengine/memcache"
	"appengine/urlfetch"
)

type Source struct {
	Key                 string
	URL                 string
	Refresh, Expiration int
}

var Sources = []*Source{
	&Source{
		Key: "nextbus",
		// http://www.sfmta.com/cms/asite/nextmunidata.htm
		URL: ("http://webservices.nextbus.com/service/publicXMLFeed?" +
			"command=predictionsForMultiStops&a=sf-muni" +
			"&stops=47|null|6825" +
			"&stops=49|null|6825" +
			"&stops=10|null|5859" +
			"&stops=12|null|5859" +
			"&stops=1|null|4016" +
			"&stops=1|null|6297" +
			"&stops=27|null|35165"),
		Refresh:    10,
		Expiration: 300,
	},
	&Source{
		Key: "forecast",
		URL: ("http://forecast.weather.gov/MapClick.php?" +
			"lat=37.79570&lon=-122.42100&FcstType=dwml&unit=1"),
		// http://graphical.weather.gov/xml/mdl/XML/Design/WebServicesUseGuildlines.php
		Refresh:    3600,
		Expiration: 8 * 3600,
	},
	// A buoy off Pier 1.
	&Source{
		Key: "conditions",
		URL: "http://www.weather.gov/xml/current_obs/display.php?stid=PXOC1",
		// http://graphical.weather.gov/xml/mdl/XML/Design/WebServicesUseGuildlines.php
		Refresh:    3600,
		Expiration: 4 * 3600,
	},
}

func (s Source) Fetch(c appengine.Context) os.Error {
	c.Debugf("fetching %s data", s.Key)

	client := urlfetch.Client(c)
	resp, err := client.Get(s.URL)
	if err != nil {
		c.Errorf("%q", err)
		return err
	}
	contents, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		c.Errorf("%q", err)
		return err
	}
	resp.Body.Close()

	item := &memcache.Item{
		Key:        s.Key,
		Value:      contents,
		Expiration: int32(s.Expiration),
	}
	if err := memcache.Set(c, item); err != nil {
		c.Errorf("%q", err)
		return err
	}

	// We keep the last updated time in memcache.  It's not
	// updated atomically with the page, so it's only used to
	// limit the rate of fetches from the data servers.  Don't use
	// it for display; use the data creation times in the data
	// instead.  It doesn't matter to the user that we fetched a
	// weather forecast 3 minutes ago if the forecast is 48
	// minutes old.
	item = &memcache.Item{
		Key:   s.Key + "_fresh",
		Value: []byte(strconv.Itoa64(time.Seconds())),
	}
	if err := memcache.Set(c, item); err != nil {
		c.Errorf("%q", err)
		return err
	}

	c.Infof("fetched %d bytes of %s data", len(contents), s.Key)
	return nil
}

// Freshen calls Fetch iff the item is not known to be fresh.
func (s *Source) Freshen(c appengine.Context) os.Error {
	item, err := memcache.Get(c, s.Key+"_fresh")
	if err == memcache.ErrCacheMiss {
		return s.Fetch(c)
	} else if err != nil {
		c.Errorf("%q", err)
		// Something is wrong with memcache, so don't try to fetch.
		return err
	}

	fresh, err := strconv.Atoi64(string(item.Value))
	if err != nil {
		c.Errorf("%q", err)
		return s.Fetch(c)
	}

	stale := fresh + int64(s.Refresh)
	c.Debugf("%s stale = %s", s.Key, time.SecondsToUTC(stale).Format(time.RFC3339))
	if stale > time.Seconds() {
		return nil
	}
	return s.Fetch(c)
}
<commit_msg>Fix 27 bus stop.  Use a buoy off Crissy Field instead of Pier 1.<commit_after>package clocky

import (
	"io/ioutil"
	"os"
	"strconv"
	"time"

	"appengine"
	"appengine/memcache"
	"appengine/urlfetch"
)

type Source struct {
	Key                 string
	URL                 string
	Refresh, Expiration int
}

var Sources = []*Source{
	&Source{
		Key: "nextbus",
		// http://www.sfmta.com/cms/asite/nextmunidata.htm
		URL: ("http://webservices.nextbus.com/service/publicXMLFeed?" +
			"command=predictionsForMultiStops&a=sf-muni" +
			"&stops=47|null|6825" +
			"&stops=49|null|6825" +
			"&stops=10|null|5859" +
			"&stops=12|null|5859" +
			"&stops=1|null|4016" +
			"&stops=1|null|6297" +
			"&stops=27|null|5165"),
		Refresh:    10,
		Expiration: 300,
	},
	&Source{
		Key: "forecast",
		URL: ("http://forecast.weather.gov/MapClick.php?" +
			"lat=37.79570&lon=-122.42100&FcstType=dwml&unit=1"),
		// http://graphical.weather.gov/xml/mdl/XML/Design/WebServicesUseGuildlines.php
		Refresh:    3600,
		Expiration: 8 * 3600,
	},
	// A buoy near Crissy Field.
	&Source{
		Key: "conditions",
		URL: "http://www.weather.gov/xml/current_obs/display.php?stid=FTPC1",
		// http://graphical.weather.gov/xml/mdl/XML/Design/WebServicesUseGuildlines.php
		Refresh:    3600,
		Expiration: 4 * 3600,
	},
}

func (s Source) Fetch(c appengine.Context) os.Error {
	c.Debugf("fetching %s data", s.Key)

	client := urlfetch.Client(c)
	resp, err := client.Get(s.URL)
	if err != nil {
		c.Errorf("%q", err)
		return err
	}
	contents, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		c.Errorf("%q", err)
		return err
	}
	resp.Body.Close()

	item := &memcache.Item{
		Key:        s.Key,
		Value:      contents,
		Expiration: int32(s.Expiration),
	}
	if err := memcache.Set(c, item); err != nil {
		c.Errorf("%q", err)
		return err
	}

	// We keep the last updated time in memcache.  It's not
	// updated atomically with the page, so it's only used to
	// limit the rate of fetches from the data servers.  Don't use
	// it for display; use the data creation times in the data
	// instead.  It doesn't matter to the user that we fetched a
	// weather forecast 3 minutes ago if the forecast is 48
	// minutes old.
	item = &memcache.Item{
		Key:   s.Key + "_fresh",
		Value: []byte(strconv.Itoa64(time.Seconds())),
	}
	if err := memcache.Set(c, item); err != nil {
		c.Errorf("%q", err)
		return err
	}

	c.Infof("fetched %d bytes of %s data", len(contents), s.Key)
	return nil
}

// Freshen calls Fetch iff the item is not known to be fresh.
func (s *Source) Freshen(c appengine.Context) os.Error {
	item, err := memcache.Get(c, s.Key+"_fresh")
	if err == memcache.ErrCacheMiss {
		return s.Fetch(c)
	} else if err != nil {
		c.Errorf("%q", err)
		// Something is wrong with memcache, so don't try to fetch.
		return err
	}

	fresh, err := strconv.Atoi64(string(item.Value))
	if err != nil {
		c.Errorf("%q", err)
		return s.Fetch(c)
	}

	stale := fresh + int64(s.Refresh)
	c.Debugf("%s stale = %s", s.Key, time.SecondsToUTC(stale).Format(time.RFC3339))
	if stale > time.Seconds() {
		return nil
	}
	return s.Fetch(c)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"context"
	"log"
	"os/exec"

	"cloud.google.com/go/pubsub"
	"google.golang.org/api/iterator"
)

const updateTopicString string = "onesie-updates"
const updateSub string = "onesie-server"

func main() {
	log.Println("Starting")
	pubsubClient, err := pubsub.NewClient(context.Background(), "940380154622")
	if err != nil {
		log.Fatalf("Failed to create client: %v", err)
	}

	updateTopic := pubsubClient.Topic(updateTopicString)
	sub := pubsubClient.Subscription(updateSub)
	b, err := sub.Exists(context.Background())
	if err != nil {
		log.Fatal(err)
	}
	if !b {
		sub, err = pubsubClient.CreateSubscription(context.Background(), updateSub, updateTopic, 0, nil)
		if err != nil {
			log.Fatal(err)
		}
	}

	// Construct the iterator
	it, err := sub.Pull(context.Background())
	if err != nil {
		log.Fatal(err)
	}
	defer it.Stop()

	// Consume 1 messages
	for i := 0; i < 1; i++ {
		msg, err := it.Next()
		if err == iterator.Done {
			log.Println("No more messages")
			break
		}
		if err != nil {
			log.Fatal(err)
			break
		}

		msgStr := string(msg.Data)
		log.Printf("Recieved Message: %+v", msgStr)

		if msgStr == "update" {
			// Create an *exec.Cmd
			cmd := exec.Command("/opt/dehydrated/dehydrated", "-c --config /opt/onesie-configs/dehydrated.conf")

			// Stdout buffer
			cmdOutput := &bytes.Buffer{}
			// Attach buffer to command
			cmd.Stdout = cmdOutput

			// Execute command
			err := cmd.Run() // will wait for command to return
			if err != nil {
				log.Fatal(err)
			}
			// Only output the commands stdout
			log.Println(cmdOutput.Bytes()) // => go version go1.3 darwin/amd64
		}
		msg.Done(true)
	}
}
<commit_msg>better messages<commit_after>package main

import (
	"bytes"
	"context"
	"log"
	"os/exec"

	"cloud.google.com/go/pubsub"
	"google.golang.org/api/iterator"
)

const updateTopicString string = "onesie-updates"
const updateSub string = "onesie-server"

func main() {
	log.Println("Starting")
	pubsubClient, err := pubsub.NewClient(context.Background(), "940380154622")
	if err != nil {
		log.Fatalf("Failed to create client: %v", err)
	}

	updateTopic := pubsubClient.Topic(updateTopicString)
	sub := pubsubClient.Subscription(updateSub)
	b, err := sub.Exists(context.Background())
	if err != nil {
		log.Fatal(err)
	}
	if !b {
		sub, err = pubsubClient.CreateSubscription(context.Background(), updateSub, updateTopic, 0, nil)
		if err != nil {
			log.Fatal(err)
		}
	}

	// Construct the iterator
	it, err := sub.Pull(context.Background())
	if err != nil {
		log.Fatalf("Error getting messages: %+v", err)
	}
	defer it.Stop()

	// Consume 1 messages
	for i := 0; i < 1; i++ {
		msg, err := it.Next()
		if err == iterator.Done {
			log.Println("No more messages.")
			break
		}
		if err != nil {
			log.Printf("Error while getting message: %+v", err)
			break
		}

		msgStr := string(msg.Data)
		log.Printf("Recieved Message: %+v", msgStr)

		if msgStr == "update" {
			// Create an *exec.Cmd
			cmd := exec.Command("/opt/dehydrated/dehydrated", "-c --config /opt/onesie-configs/dehydrated.conf")

			// Stdout buffer
			cmdOutput := &bytes.Buffer{}
			// Attach buffer to command
			cmd.Stdout = cmdOutput

			// Execute command
			err := cmd.Run() // will wait for command to return
			if err != nil {
				log.Fatal("Error running command: %+v", err)
			}
			// Only output the commands stdout
			log.Println(cmdOutput.Bytes()) // => go version go1.3 darwin/amd64
		}
		msg.Done(true)
	}

	log.Println("Finished.")
}
<|endoftext|>