<commit_before>// Copyright 2016 The Netstack 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 fdbased provides the implemention of data-link layer endpoints
// backed by boundary-preserving file descriptors (e.g., TUN devices,
// seqpacket/datagram sockets).
//
// FD based endpoints can be used in the networking stack by calling New() to
// create a new endpoint, and then passing it as an argument to
// Stack.CreateNIC().
package fdbased

import (
	"runtime"
	"sync/atomic"
	"syscall"

	"github.com/google/netstack/tcpip"
	"github.com/google/netstack/tcpip/buffer"
	"github.com/google/netstack/tcpip/header"
	"github.com/google/netstack/tcpip/link/rawfile"
	"github.com/google/netstack/tcpip/stack"
)

// BufConfig defines the shape of the vectorised view used to read packets from the NIC.
var BufConfig = []int{128, 256, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768}

type endpoint struct {
	// fd is the file descriptor used to send and receive packets.
	fd int

	// mtu (maximum transmission unit) is the maximum size of a packet.
	mtu uint32

	// caps holds the endpoint capabilities.
	caps stack.LinkEndpointCapabilities

	// closed is a function to be called when the FD's peer (if any) closes
	// its end of the communication pipe.
	closed func(*tcpip.Error)

	// pendingReaders is the number of readers that haven't stopped yet.
	pendingReaders int32

	// readerCh is a channel used as a semaphore to allow only one reader
	// goroutine to run at a time.
	readerCh chan struct{}
}

// New creates a new fd-based endpoint.
func New(fd int, mtu uint32, checksumOffload bool, closed func(*tcpip.Error)) tcpip.LinkEndpointID {
	syscall.SetNonblock(fd, true)

	caps := stack.LinkEndpointCapabilities(0)
	if checksumOffload {
		caps |= stack.CapabilityChecksumOffload
	}

	e := &endpoint{
		fd:       fd,
		mtu:      mtu,
		caps:     caps,
		closed:   closed,
		readerCh: make(chan struct{}, 1),
	}
	return stack.RegisterLinkEndpoint(e)
}

// Attach launches the goroutine that reads packets from the file descriptor and
// dispatches them via the provided dispatcher.
func (e *endpoint) Attach(dispatcher stack.NetworkDispatcher) {
	// Allow one reader to go through.
	e.readerCh <- struct{}{}

	// Start all readers.
	n := int32(runtime.GOMAXPROCS(0))
	atomic.StoreInt32(&e.pendingReaders, n)
	for i := n; i > 0; i-- {
		go e.dispatchLoop(dispatcher)
	}
}

// MTU implements stack.LinkEndpoint.MTU. It returns the value initialized
// during construction.
func (e *endpoint) MTU() uint32 {
	return e.mtu
}

// Capabilities implements stack.LinkEndpoint.Capabilities.
func (e *endpoint) Capabilities() stack.LinkEndpointCapabilities {
	return e.caps
}

// MaxHeaderLength returns the maximum size of the header. Given that it
// doesn't have a header, it just returns 0.
func (*endpoint) MaxHeaderLength() uint16 {
	return 0
}

// LinkAddress returns the link address of this endpoint.
func (*endpoint) LinkAddress() tcpip.LinkAddress {
	return ""
}

// WritePacket writes outbound packets to the file descriptor. If it is not
// currently writable, the packet is dropped.
func (e *endpoint) WritePacket(_ *stack.Route, hdr *buffer.Prependable, payload buffer.View, protocol tcpip.NetworkProtocolNumber) *tcpip.Error {
	if payload == nil {
		return rawfile.NonBlockingWrite(e.fd, hdr.UsedBytes())

	}

	return rawfile.NonBlockingWrite2(e.fd, hdr.UsedBytes(), payload)
}

func capViews(n int, buffers []int, views []buffer.View) int {
	c := 0
	for i, s := range buffers {
		c += s
		if c >= n {
			views[i].CapLength(s - (c - n))
			return i + 1
		}
	}
	return len(buffers)
}

func allocateViews(bufConfig []int, views []buffer.View, iovecs []syscall.Iovec) {
	for i, v := range views {
		if v != nil {
			break
		}
		b := buffer.NewView(bufConfig[i])
		views[i] = b
		iovecs[i] = syscall.Iovec{
			Base: &b[0],
			Len:  uint64(len(b)),
		}
	}
}

// dispatch reads one packet from the file descriptor and dispatches it.
func (e *endpoint) dispatch(d stack.NetworkDispatcher, vv *buffer.VectorisedView, views []buffer.View, iovecs []syscall.Iovec) (bool, *tcpip.Error) {
	allocateViews(BufConfig, views, iovecs)

	// Read the next packet. After we've read it, allow another reader to
	// concurrently read from the fd.
	n, err := rawfile.BlockingReadv(e.fd, iovecs)
	e.readerCh <- struct{}{}
	if err != nil {
		return false, err
	}

	if n <= 0 {
		return false, nil
	}

	// We don't get any indication of what the packet is, so try to guess
	// if it's an IPv4 or IPv6 packet.
	var p tcpip.NetworkProtocolNumber
	switch header.IPVersion(views[0]) {
	case header.IPv4Version:
		p = header.IPv4ProtocolNumber
	case header.IPv6Version:
		p = header.IPv6ProtocolNumber
	default:
		return true, nil
	}

	used := capViews(n, BufConfig, views)
	vv.SetViews(views[:used])
	vv.SetSize(n)

	d.DeliverNetworkPacket(e, "", p, vv)

	// Prepare e.views for another packet: release used views.
	for i := 0; i < used; i++ {
		views[i] = nil
	}

	return true, nil
}

// dispatchLoop reads packets from the file descriptor in a loop and dispatches
// them to the network stack.
func (e *endpoint) dispatchLoop(d stack.NetworkDispatcher) *tcpip.Error {
	views := make([]buffer.View, len(BufConfig))
	iovecs := make([]syscall.Iovec, len(BufConfig))
	vv := buffer.NewVectorisedView(0, views)
	for {
		// Wait for this reader's turn to read from the fd.
		<-e.readerCh

		// Attempt to read and dispatch the next packet.
		cont, err := e.dispatch(d, &vv, views, iovecs)
		if err != nil || !cont {
			if e.closed != nil && atomic.AddInt32(&e.pendingReaders, -1) == 0 {
				// We call this once, when the last reader
				// completes.
				e.closed(err)
			}
			return err
		}
	}
}

// InjectableEndpoint is an injectable fd-based endpoint. The endpoint writes
// to the FD, but does not read from it. All reads come from injected packets.
type InjectableEndpoint struct {
	endpoint

	dispatcher stack.NetworkDispatcher
}

// Attach saves the stack network-layer dispatcher for use later when packets
// are injected.
func (e *InjectableEndpoint) Attach(dispatcher stack.NetworkDispatcher) {
	e.dispatcher = dispatcher
}

// Inject injects an inbound packet.
func (e *InjectableEndpoint) Inject(protocol tcpip.NetworkProtocolNumber, vv *buffer.VectorisedView) {
	uu := vv.Clone(nil)
	e.dispatcher.DeliverNetworkPacket(e, "", protocol, &uu)
}

// NewInjectable creates a new fd-based InjectableEndpoint.
func NewInjectable(fd int, mtu uint32) (tcpip.LinkEndpointID, *InjectableEndpoint) {
	syscall.SetNonblock(fd, true)

	e := &InjectableEndpoint{endpoint: endpoint{
		fd:   fd,
		mtu:  mtu,
		caps: stack.CapabilityChecksumOffload,
	}}

	return stack.RegisterLinkEndpoint(e), e
}
<commit_msg>Add Wait() method to InjectableEndpoint.<commit_after>// Copyright 2016 The Netstack 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 fdbased provides the implemention of data-link layer endpoints
// backed by boundary-preserving file descriptors (e.g., TUN devices,
// seqpacket/datagram sockets).
//
// FD based endpoints can be used in the networking stack by calling New() to
// create a new endpoint, and then passing it as an argument to
// Stack.CreateNIC().
package fdbased

import (
	"runtime"
	"sync/atomic"
	"syscall"

	"github.com/google/netstack/gate"
	"github.com/google/netstack/tcpip"
	"github.com/google/netstack/tcpip/buffer"
	"github.com/google/netstack/tcpip/header"
	"github.com/google/netstack/tcpip/link/rawfile"
	"github.com/google/netstack/tcpip/stack"
)

// BufConfig defines the shape of the vectorised view used to read packets from the NIC.
var BufConfig = []int{128, 256, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768}

type endpoint struct {
	// fd is the file descriptor used to send and receive packets.
	fd int

	// mtu (maximum transmission unit) is the maximum size of a packet.
	mtu uint32

	// caps holds the endpoint capabilities.
	caps stack.LinkEndpointCapabilities

	// closed is a function to be called when the FD's peer (if any) closes
	// its end of the communication pipe.
	closed func(*tcpip.Error)

	// pendingReaders is the number of readers that haven't stopped yet.
	pendingReaders int32

	// readerCh is a channel used as a semaphore to allow only one reader
	// goroutine to run at a time.
	readerCh chan struct{}
}

// New creates a new fd-based endpoint.
func New(fd int, mtu uint32, checksumOffload bool, closed func(*tcpip.Error)) tcpip.LinkEndpointID {
	syscall.SetNonblock(fd, true)

	caps := stack.LinkEndpointCapabilities(0)
	if checksumOffload {
		caps |= stack.CapabilityChecksumOffload
	}

	e := &endpoint{
		fd:       fd,
		mtu:      mtu,
		caps:     caps,
		closed:   closed,
		readerCh: make(chan struct{}, 1),
	}
	return stack.RegisterLinkEndpoint(e)
}

// Attach launches the goroutine that reads packets from the file descriptor and
// dispatches them via the provided dispatcher.
func (e *endpoint) Attach(dispatcher stack.NetworkDispatcher) {
	// Allow one reader to go through.
	e.readerCh <- struct{}{}

	// Start all readers.
	n := int32(runtime.GOMAXPROCS(0))
	atomic.StoreInt32(&e.pendingReaders, n)
	for i := n; i > 0; i-- {
		go e.dispatchLoop(dispatcher)
	}
}

// MTU implements stack.LinkEndpoint.MTU. It returns the value initialized
// during construction.
func (e *endpoint) MTU() uint32 {
	return e.mtu
}

// Capabilities implements stack.LinkEndpoint.Capabilities.
func (e *endpoint) Capabilities() stack.LinkEndpointCapabilities {
	return e.caps
}

// MaxHeaderLength returns the maximum size of the header. Given that it
// doesn't have a header, it just returns 0.
func (*endpoint) MaxHeaderLength() uint16 {
	return 0
}

// LinkAddress returns the link address of this endpoint.
func (*endpoint) LinkAddress() tcpip.LinkAddress {
	return ""
}

// WritePacket writes outbound packets to the file descriptor. If it is not
// currently writable, the packet is dropped.
func (e *endpoint) WritePacket(_ *stack.Route, hdr *buffer.Prependable, payload buffer.View, protocol tcpip.NetworkProtocolNumber) *tcpip.Error {
	if payload == nil {
		return rawfile.NonBlockingWrite(e.fd, hdr.UsedBytes())

	}

	return rawfile.NonBlockingWrite2(e.fd, hdr.UsedBytes(), payload)
}

func capViews(n int, buffers []int, views []buffer.View) int {
	c := 0
	for i, s := range buffers {
		c += s
		if c >= n {
			views[i].CapLength(s - (c - n))
			return i + 1
		}
	}
	return len(buffers)
}

func allocateViews(bufConfig []int, views []buffer.View, iovecs []syscall.Iovec) {
	for i, v := range views {
		if v != nil {
			break
		}
		b := buffer.NewView(bufConfig[i])
		views[i] = b
		iovecs[i] = syscall.Iovec{
			Base: &b[0],
			Len:  uint64(len(b)),
		}
	}
}

// dispatch reads one packet from the file descriptor and dispatches it.
func (e *endpoint) dispatch(d stack.NetworkDispatcher, vv *buffer.VectorisedView, views []buffer.View, iovecs []syscall.Iovec) (bool, *tcpip.Error) {
	allocateViews(BufConfig, views, iovecs)

	// Read the next packet. After we've read it, allow another reader to
	// concurrently read from the fd.
	n, err := rawfile.BlockingReadv(e.fd, iovecs)
	e.readerCh <- struct{}{}
	if err != nil {
		return false, err
	}

	if n <= 0 {
		return false, nil
	}

	// We don't get any indication of what the packet is, so try to guess
	// if it's an IPv4 or IPv6 packet.
	var p tcpip.NetworkProtocolNumber
	switch header.IPVersion(views[0]) {
	case header.IPv4Version:
		p = header.IPv4ProtocolNumber
	case header.IPv6Version:
		p = header.IPv6ProtocolNumber
	default:
		return true, nil
	}

	used := capViews(n, BufConfig, views)
	vv.SetViews(views[:used])
	vv.SetSize(n)

	d.DeliverNetworkPacket(e, "", p, vv)

	// Prepare e.views for another packet: release used views.
	for i := 0; i < used; i++ {
		views[i] = nil
	}

	return true, nil
}

// dispatchLoop reads packets from the file descriptor in a loop and dispatches
// them to the network stack.
func (e *endpoint) dispatchLoop(d stack.NetworkDispatcher) *tcpip.Error {
	views := make([]buffer.View, len(BufConfig))
	iovecs := make([]syscall.Iovec, len(BufConfig))
	vv := buffer.NewVectorisedView(0, views)
	for {
		// Wait for this reader's turn to read from the fd.
		<-e.readerCh

		// Attempt to read and dispatch the next packet.
		cont, err := e.dispatch(d, &vv, views, iovecs)
		if err != nil || !cont {
			if e.closed != nil && atomic.AddInt32(&e.pendingReaders, -1) == 0 {
				// We call this once, when the last reader
				// completes.
				e.closed(err)
			}
			return err
		}
	}
}

// InjectableEndpoint is an injectable fd-based endpoint. The endpoint writes
// to the FD, but does not read from it. All reads come from injected packets.
type InjectableEndpoint struct {
	endpoint

	gate       gate.Gate
	dispatcher stack.NetworkDispatcher
}

// Attach saves the stack network-layer dispatcher for use later when packets
// are injected.
func (e *InjectableEndpoint) Attach(dispatcher stack.NetworkDispatcher) {
	e.dispatcher = dispatcher
}

// Inject injects an inbound packet.
func (e *InjectableEndpoint) Inject(protocol tcpip.NetworkProtocolNumber, vv *buffer.VectorisedView) {
	e.dispatcher.DeliverNetworkPacket(e, "", protocol, vv)
}

// WritePacket writes packets to the underlying file descriptor as long as
// Wait() hasn't been called.
func (e *InjectableEndpoint) WritePacket(r *stack.Route, hdr *buffer.Prependable, payload buffer.View, protocol tcpip.NetworkProtocolNumber) *tcpip.Error {
	if !e.gate.Enter() {
		return nil
	}

	err := e.endpoint.WritePacket(r, hdr, payload, protocol)
	e.gate.Leave()
	return err
}

// Wait waits for all inflight WritePacket calls to finish and prevent new ones
// from starting. It guarantees that the endpoint won't use the underlying
// file descriptor anymore.
func (e *InjectableEndpoint) Wait() {
	e.gate.Close()
}

// NewInjectable creates a new fd-based InjectableEndpoint.
func NewInjectable(fd int, mtu uint32) (tcpip.LinkEndpointID, *InjectableEndpoint) {
	syscall.SetNonblock(fd, true)

	e := &InjectableEndpoint{endpoint: endpoint{
		fd:   fd,
		mtu:  mtu,
		caps: stack.CapabilityChecksumOffload,
	}}

	return stack.RegisterLinkEndpoint(e), e
}
<|endoftext|>


<commit_before>// Copyright 2017 Manu Martinez-Almeida.  All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.

package gin

import (
	"bufio"
	"crypto/tls"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"net/http/httptest"
	"os"
	"sync"
	"testing"
	"time"

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

func testRequest(t *testing.T, url string) {
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{
			InsecureSkipVerify: true,
		},
	}
	client := &http.Client{Transport: tr}

	resp, err := client.Get(url)
	assert.NoError(t, err)
	defer resp.Body.Close()

	body, ioerr := ioutil.ReadAll(resp.Body)
	assert.NoError(t, ioerr)
	assert.Equal(t, "it worked", string(body), "resp body should match")
	assert.Equal(t, "200 OK", resp.Status, "should get a 200")
}

func TestRunEmpty(t *testing.T) {
	os.Setenv("PORT", "")
	router := New()
	go func() {
		router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })
		assert.NoError(t, router.Run())
	}()
	// have to wait for the goroutine to start and run the server
	// otherwise the main thread will complete
	time.Sleep(5 * time.Millisecond)

	assert.Error(t, router.Run(":8080"))
	testRequest(t, "http://localhost:8080/example")
}

func TestRunTLS(t *testing.T) {
	router := New()
	go func() {
		router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })

		assert.NoError(t, router.RunTLS(":8443", "./testdata/certificate/cert.pem", "./testdata/certificate/key.pem"))
	}()

	// have to wait for the goroutine to start and run the server
	// otherwise the main thread will complete
	time.Sleep(5 * time.Millisecond)

	assert.Error(t, router.RunTLS(":8443", "./testdata/certificate/cert.pem", "./testdata/certificate/key.pem"))
	testRequest(t, "https://localhost:8443/example")
}

func TestRunEmptyWithEnv(t *testing.T) {
	os.Setenv("PORT", "3123")
	router := New()
	go func() {
		router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })
		assert.NoError(t, router.Run())
	}()
	// have to wait for the goroutine to start and run the server
	// otherwise the main thread will complete
	time.Sleep(5 * time.Millisecond)

	assert.Error(t, router.Run(":3123"))
	testRequest(t, "http://localhost:3123/example")
}

func TestRunTooMuchParams(t *testing.T) {
	router := New()
	assert.Panics(t, func() {
		router.Run("2", "2")
	})
}

func TestRunWithPort(t *testing.T) {
	router := New()
	go func() {
		router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })
		assert.NoError(t, router.Run(":5150"))
	}()
	// have to wait for the goroutine to start and run the server
	// otherwise the main thread will complete
	time.Sleep(5 * time.Millisecond)

	assert.Error(t, router.Run(":5150"))
	testRequest(t, "http://localhost:5150/example")
}

func TestUnixSocket(t *testing.T) {
	router := New()

	go func() {
		router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })
		assert.NoError(t, router.RunUnix("/tmp/unix_unit_test"))
	}()
	// have to wait for the goroutine to start and run the server
	// otherwise the main thread will complete
	time.Sleep(5 * time.Millisecond)

	c, err := net.Dial("unix", "/tmp/unix_unit_test")
	assert.NoError(t, err)

	fmt.Fprint(c, "GET /example HTTP/1.0\r\n\r\n")
	scanner := bufio.NewScanner(c)
	var response string
	for scanner.Scan() {
		response += scanner.Text()
	}
	assert.Contains(t, response, "HTTP/1.0 200", "should get a 200")
	assert.Contains(t, response, "it worked", "resp body should match")
}

func TestBadUnixSocket(t *testing.T) {
	router := New()
	assert.Error(t, router.RunUnix("#/tmp/unix_unit_test"))
}

func TestFileDescriptor(t *testing.T) {
	router := New()

	addr, err := net.ResolveTCPAddr("tcp", ":8000")
	assert.NoError(t, err)
	listener, err := net.ListenTCP("tcp", addr)
	assert.NoError(t, err)
	socketFile, err := listener.File()
	assert.NoError(t, err)

	go func() {
		router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })
		assert.NoError(t, router.RunFd(int(socketFile.Fd())))
	}()
	// have to wait for the goroutine to start and run the server
	// otherwise the main thread will complete
	time.Sleep(5 * time.Millisecond)

	c, err := net.Dial("tcp", "localhost:8000")
	assert.NoError(t, err)

	fmt.Fprintf(c, "GET /example HTTP/1.0\r\n\r\n")
	scanner := bufio.NewScanner(c)
	var response string
	for scanner.Scan() {
		response += scanner.Text()
	}
	assert.Contains(t, response, "HTTP/1.0 200", "should get a 200")
	assert.Contains(t, response, "it worked", "resp body should match")
}

func TestBadFileDescriptor(t *testing.T) {
	router := New()
	assert.Error(t, router.RunFd(0))
}

func TestWithHttptestWithAutoSelectedPort(t *testing.T) {
	router := New()
	router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })

	ts := httptest.NewServer(router)
	defer ts.Close()

	testRequest(t, ts.URL+"/example")
}

func TestConcurrentHandleContext(t *testing.T) {
	router := New()
	router.GET("/", func(c *Context) {
		c.Request.URL.Path = "/example"
		router.HandleContext(c)
	})
	router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })

	ts := httptest.NewServer(router)
	defer ts.Close()

	var wg sync.WaitGroup
	iterations := 200
	wg.Add(iterations)
	for i := 0; i < iterations; i++ {
		go func() {
			testRequest(t, ts.URL+"/")
			wg.Done()
		}()
	}
	wg.Wait()
}

// func TestWithHttptestWithSpecifiedPort(t *testing.T) {
// 	router := New()
// 	router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })

// 	l, _ := net.Listen("tcp", ":8033")
// 	ts := httptest.Server{
// 		Listener: l,
// 		Config:   &http.Server{Handler: router},
// 	}
// 	ts.Start()
// 	defer ts.Close()

// 	testRequest(t, "http://localhost:8033/example")
// }
<commit_msg>fix test - auto choose port number (#1719)<commit_after>// Copyright 2017 Manu Martinez-Almeida.  All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.

package gin

import (
	"bufio"
	"crypto/tls"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"net/http/httptest"
	"os"
	"sync"
	"testing"
	"time"

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

func testRequest(t *testing.T, url string) {
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{
			InsecureSkipVerify: true,
		},
	}
	client := &http.Client{Transport: tr}

	resp, err := client.Get(url)
	assert.NoError(t, err)
	defer resp.Body.Close()

	body, ioerr := ioutil.ReadAll(resp.Body)
	assert.NoError(t, ioerr)
	assert.Equal(t, "it worked", string(body), "resp body should match")
	assert.Equal(t, "200 OK", resp.Status, "should get a 200")
}

func TestRunEmpty(t *testing.T) {
	os.Setenv("PORT", "")
	router := New()
	go func() {
		router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })
		assert.NoError(t, router.Run())
	}()
	// have to wait for the goroutine to start and run the server
	// otherwise the main thread will complete
	time.Sleep(5 * time.Millisecond)

	assert.Error(t, router.Run(":8080"))
	testRequest(t, "http://localhost:8080/example")
}

func TestRunTLS(t *testing.T) {
	router := New()
	go func() {
		router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })

		assert.NoError(t, router.RunTLS(":8443", "./testdata/certificate/cert.pem", "./testdata/certificate/key.pem"))
	}()

	// have to wait for the goroutine to start and run the server
	// otherwise the main thread will complete
	time.Sleep(5 * time.Millisecond)

	assert.Error(t, router.RunTLS(":8443", "./testdata/certificate/cert.pem", "./testdata/certificate/key.pem"))
	testRequest(t, "https://localhost:8443/example")
}

func TestRunEmptyWithEnv(t *testing.T) {
	os.Setenv("PORT", "3123")
	router := New()
	go func() {
		router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })
		assert.NoError(t, router.Run())
	}()
	// have to wait for the goroutine to start and run the server
	// otherwise the main thread will complete
	time.Sleep(5 * time.Millisecond)

	assert.Error(t, router.Run(":3123"))
	testRequest(t, "http://localhost:3123/example")
}

func TestRunTooMuchParams(t *testing.T) {
	router := New()
	assert.Panics(t, func() {
		router.Run("2", "2")
	})
}

func TestRunWithPort(t *testing.T) {
	router := New()
	go func() {
		router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })
		assert.NoError(t, router.Run(":5150"))
	}()
	// have to wait for the goroutine to start and run the server
	// otherwise the main thread will complete
	time.Sleep(5 * time.Millisecond)

	assert.Error(t, router.Run(":5150"))
	testRequest(t, "http://localhost:5150/example")
}

func TestUnixSocket(t *testing.T) {
	router := New()

	go func() {
		router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })
		assert.NoError(t, router.RunUnix("/tmp/unix_unit_test"))
	}()
	// have to wait for the goroutine to start and run the server
	// otherwise the main thread will complete
	time.Sleep(5 * time.Millisecond)

	c, err := net.Dial("unix", "/tmp/unix_unit_test")
	assert.NoError(t, err)

	fmt.Fprint(c, "GET /example HTTP/1.0\r\n\r\n")
	scanner := bufio.NewScanner(c)
	var response string
	for scanner.Scan() {
		response += scanner.Text()
	}
	assert.Contains(t, response, "HTTP/1.0 200", "should get a 200")
	assert.Contains(t, response, "it worked", "resp body should match")
}

func TestBadUnixSocket(t *testing.T) {
	router := New()
	assert.Error(t, router.RunUnix("#/tmp/unix_unit_test"))
}

func TestFileDescriptor(t *testing.T) {
	router := New()

	addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
	assert.NoError(t, err)
	listener, err := net.ListenTCP("tcp", addr)
	assert.NoError(t, err)
	socketFile, err := listener.File()
	assert.NoError(t, err)

	go func() {
		router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })
		assert.NoError(t, router.RunFd(int(socketFile.Fd())))
	}()
	// have to wait for the goroutine to start and run the server
	// otherwise the main thread will complete
	time.Sleep(5 * time.Millisecond)

	c, err := net.Dial("tcp", listener.Addr().String())
	assert.NoError(t, err)

	fmt.Fprintf(c, "GET /example HTTP/1.0\r\n\r\n")
	scanner := bufio.NewScanner(c)
	var response string
	for scanner.Scan() {
		response += scanner.Text()
	}
	assert.Contains(t, response, "HTTP/1.0 200", "should get a 200")
	assert.Contains(t, response, "it worked", "resp body should match")
}

func TestBadFileDescriptor(t *testing.T) {
	router := New()
	assert.Error(t, router.RunFd(0))
}

func TestWithHttptestWithAutoSelectedPort(t *testing.T) {
	router := New()
	router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })

	ts := httptest.NewServer(router)
	defer ts.Close()

	testRequest(t, ts.URL+"/example")
}

func TestConcurrentHandleContext(t *testing.T) {
	router := New()
	router.GET("/", func(c *Context) {
		c.Request.URL.Path = "/example"
		router.HandleContext(c)
	})
	router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })

	ts := httptest.NewServer(router)
	defer ts.Close()

	var wg sync.WaitGroup
	iterations := 200
	wg.Add(iterations)
	for i := 0; i < iterations; i++ {
		go func() {
			testRequest(t, ts.URL+"/")
			wg.Done()
		}()
	}
	wg.Wait()
}

// func TestWithHttptestWithSpecifiedPort(t *testing.T) {
// 	router := New()
// 	router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })

// 	l, _ := net.Listen("tcp", ":8033")
// 	ts := httptest.Server{
// 		Listener: l,
// 		Config:   &http.Server{Handler: router},
// 	}
// 	ts.Start()
// 	defer ts.Close()

// 	testRequest(t, "http://localhost:8033/example")
// }
<|endoftext|>


<commit_before>package backendutil

import (
	"testing"

	"github.com/emersion/go-imap"
)

func TestMatchSeqNumAndUid(t *testing.T) {
	seqNum := uint32(42)
	uid := uint32(69)

	c := &imap.SearchCriteria{
		Or: [2]*imap.SearchCriteria{
			{
				Uid: new(imap.SeqSet),
				Not: &imap.SearchCriteria{SeqSet: new(imap.SeqSet)},
			},
			{
				SeqSet: new(imap.SeqSet),
			},
		},
	}

	if MatchSeqNumAndUid(seqNum, uid, c) {
		t.Error("Expected not to match criteria")
	}

	c.Or[0].Uid.AddNum(uid)
	if !MatchSeqNumAndUid(seqNum, uid, c) {
		t.Error("Expected to match criteria")
	}

	c.Or[0].Not.SeqSet.AddNum(seqNum)
	if MatchSeqNumAndUid(seqNum, uid, c) {
		t.Error("Expected not to match criteria")
	}

	c.Or[1].SeqSet.AddNum(seqNum)
	if !MatchSeqNumAndUid(seqNum, uid, c) {
		t.Error("Expected to match criteria")
	}
}
<commit_msg>backendutil: adds tests for MatchFlags<commit_after>package backendutil

import (
	"testing"

	"github.com/emersion/go-imap"
)

var flagsTests = []struct{
	flags []string
	criteria *imap.SearchCriteria
	res bool
}{
	{
		flags: []string{imap.SeenFlag},
		criteria: &imap.SearchCriteria{
			Seen: true,
			Unflagged: true,
		},
		res: true,
	},
	{
		flags: []string{imap.SeenFlag, imap.RecentFlag},
		criteria: &imap.SearchCriteria{New: true},
		res: false,
	},
	{
		flags: []string{imap.RecentFlag},
		criteria: &imap.SearchCriteria{New: true},
		res: true,
	},
	{
		flags: []string{imap.SeenFlag},
		criteria: &imap.SearchCriteria{
			Not: &imap.SearchCriteria{Unseen: true},
		},
		res: true,
	},
	{
		flags: []string{imap.RecentFlag},
		criteria: &imap.SearchCriteria{
			Not: &imap.SearchCriteria{Unseen: true},
		},
		res: false,
	},
}

func TestMatchFlags(t *testing.T) {
	for i, test := range flagsTests {
		ok := MatchFlags(test.flags, test.criteria)
		if test.res && !ok {
			t.Errorf("Expected #%v to match search criteria", i)
		}
		if !test.res && ok {
			t.Errorf("Expected #%v not to match search criteria", i)
		}
	}
}

func TestMatchSeqNumAndUid(t *testing.T) {
	seqNum := uint32(42)
	uid := uint32(69)

	c := &imap.SearchCriteria{
		Or: [2]*imap.SearchCriteria{
			{
				Uid: new(imap.SeqSet),
				Not: &imap.SearchCriteria{SeqSet: new(imap.SeqSet)},
			},
			{
				SeqSet: new(imap.SeqSet),
			},
		},
	}

	if MatchSeqNumAndUid(seqNum, uid, c) {
		t.Error("Expected not to match criteria")
	}

	c.Or[0].Uid.AddNum(uid)
	if !MatchSeqNumAndUid(seqNum, uid, c) {
		t.Error("Expected to match criteria")
	}

	c.Or[0].Not.SeqSet.AddNum(seqNum)
	if MatchSeqNumAndUid(seqNum, uid, c) {
		t.Error("Expected not to match criteria")
	}

	c.Or[1].SeqSet.AddNum(seqNum)
	if !MatchSeqNumAndUid(seqNum, uid, c) {
		t.Error("Expected to match criteria")
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 Marc-Antoine Ruel. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

package main

import (
	"encoding/json"
	"fmt"
	"os"
	"os/user"
	"path/filepath"
	"sync"

	"github.com/maruel/dlibox/go/anim1d"
	"github.com/maruel/dlibox/go/pio/host"
	"github.com/pkg/errors"
)

// Pattern is a JSON encoded pattern.
type Pattern string

// validatePattern verifies that the pattern can be decoded, reencoded and that
// the format is the canonical one.
func (p Pattern) Validate() error {
	var obj anim1d.SPattern
	if err := json.Unmarshal([]byte(p), &obj); err != nil {
		return err
	}
	b, err := obj.MarshalJSON()
	if err == nil && Pattern(b) != p {
		err = fmt.Errorf("pattern not in canonical format: expected %v; got %v", string(b), p)
	}
	return err
}

const morning Pattern = "{\"After\":\"#000000\",\"Before\":{\"After\":\"#ffffff\",\"Before\":{\"After\":\"#ff7f00\",\"Before\":\"#000000\",\"Curve\":\"direct\",\"DurationMS\":6000000,\"OffsetMS\":0,\"_type\":\"Transition\"},\"Curve\":\"direct\",\"DurationMS\":6000000,\"OffsetMS\":6000000,\"_type\":\"Transition\"},\"Curve\":\"direct\",\"DurationMS\":600000,\"OffsetMS\":18000000,\"_type\":\"Transition\"}"

// LRU is the list of recent patterns. The first is the oldest.
type LRU struct {
	Max      int
	Patterns []Pattern
}

func (l *LRU) ResetDefault() {
	*l = LRU{
		Max: 25,
		Patterns: []Pattern{
			"{\"_type\":\"Aurore\"}",
			"{\"Child\":{\"Frame\":\"Lff0000ff0000ff0000ff0000ff0000ffffffffffffffffffffffffffffff\",\"_type\":\"Repeated\"},\"MovesPerSec\":6,\"_type\":\"Rotate\"}",
			"{\"Patterns\":[{\"_type\":\"Aurore\"},{\"Seed\":0,\"Stars\":null,\"_type\":\"NightStars\"},{\"AverageDelay\":0,\"Duration\":0,\"_type\":\"WishingStar\"}],\"Weights\":[1,1,1],\"_type\":\"Mixer\"}",
			"{\"Curve\":\"easeinout\",\"DurationShowMS\":1000000,\"DurationTransitionMS\":1000000,\"Patterns\":[\"#ff0000\",\"#00ff00\",\"#0000ff\"],\"_type\":\"Loop\"}",
			"{\"Curve\":\"direct\",\"Left\":\"#000000\",\"Right\":\"#0000ff\",\"_type\":\"Gradient\"}",
			"{\"Curve\":\"direct\",\"Left\":\"#000000\",\"Right\":\"#ff0000\",\"_type\":\"Gradient\"}",
			"{\"Curve\":\"direct\",\"Left\":\"#000000\",\"Right\":\"#00ff00\",\"_type\":\"Gradient\"}",
			"{\"Curve\":\"direct\",\"Left\":\"#000000\",\"Right\":\"#ffffff\",\"_type\":\"Gradient\"}",
			"{\"Child\":\"Lff0000ff0000ee0000dd0000cc0000bb0000aa0000990000880000770000660000550000440000330000220000110000\",\"MovesPerSec\":30,\"_type\":\"PingPong\"}",
			"{\"After\":\"#000000\",\"Before\":{\"After\":\"#ffffff\",\"Before\":{\"After\":\"#ff7f00\",\"Before\":\"#000000\",\"Curve\":\"direct\",\"DurationMS\":0,\"OffsetMS\":0,\"_type\":\"Transition\"},\"Curve\":\"direct\",\"DurationMS\":0,\"OffsetMS\":0,\"_type\":\"Transition\"},\"Curve\":\"direct\",\"DurationMS\":0,\"OffsetMS\":0,\"_type\":\"Transition\"}",
			"\"#000000\"",
			"{\"Child\":\"Lffffff\",\"MovesPerSec\":30,\"_type\":\"PingPong\"}",
			"{\"Curve\":\"easeinout\",\"DurationShowMS\":1000000,\"DurationTransitionMS\":10000000,\"Patterns\":[\"#ff0000\",\"#ff7f00\",\"#ffff00\",\"#00ff00\",\"#0000ff\",\"#4b0082\",\"#8b00ff\"],\"_type\":\"Loop\"}",
			"\"Rainbow\"",
			"{\"Seed\":0,\"Stars\":null,\"_type\":\"NightStars\"}",
			"{\"Child\":\"L010001ff000000ff000000ff\",\"_type\":\"Chronometer\"}",
			morning,
		},
	}
}

func (l *LRU) Validate() error {
	for i, s := range l.Patterns {
		if err := s.Validate(); err != nil {
			return errors.Wrap(err, fmt.Sprintf("can't load recent pattern %d", i))
		}
	}
	return nil
}

// Inject moves the pattern at the top of LRU cache.
func (l *LRU) Inject(pattern string) {
	for i, old := range l.Patterns {
		if old == Pattern(pattern) {
			copy(l.Patterns[i:], l.Patterns[i+1:])
			l.Patterns = l.Patterns[:len(l.Patterns)-1]
			break
		}
	}
	if len(l.Patterns) < l.Max {
		l.Patterns = append(l.Patterns, "")
	}
	copy(l.Patterns[1:], l.Patterns)
	l.Patterns[0] = Pattern(pattern)
}

//

// APA102 contains light specific settings.
type APA102 struct {
	// Speed of the transfer.
	SPIspeed int64
	// Number of lights controlled by this device. If lower than the actual
	// number of lights, the remaining lights will flash oddly.
	NumberLights int
}

// IR contains InfraRed remote information.
type IR struct {
	Mapping map[host.Key]Pattern // TODO(maruel): We may actually do something more complex than just set a pattern.
}

// PIR contains a motion detection behavior.
type PIR struct {
	Pin     int
	Pattern Pattern // TODO(maruel): We may actually do something more complex than just set a pattern.
}

// PatternSettings contains settings about patterns.
type PatternSettings struct {
	Named   map[string]Pattern // Patterns that are 'named'.
	Startup Pattern            // Startup pattern to use. If not set, use Last.
	Last    Pattern            // Last pattern used.
}

func (p *PatternSettings) ResetDefault() {
	*p = PatternSettings{
		Named:   map[string]Pattern{},
		Startup: "\"#010001\"",
		Last:    "\"#010001\"",
	}
}

func (p *PatternSettings) Validate() error {
	for k, v := range p.Named {
		if err := v.Validate(); err != nil {
			return errors.Wrap(err, fmt.Sprintf("can't load pattern %s", k))
		}
	}
	if len(p.Startup) != 0 {
		if err := p.Startup.Validate(); err != nil {
			return errors.Wrap(err, "can't load pattern for Last")
		}
	}
	if len(p.Last) != 0 {
		return p.Last.Validate()
	}
	return nil
}

// Settings is all the host settings.
type Settings struct {
	Alarms          Alarms
	APA102          APA102
	IR              IR
	PIR             PIR
	PatternSettings PatternSettings
}

func (s *Settings) ResetDefault() {
	s.Alarms.ResetDefault()
	s.APA102 = APA102{
		SPIspeed:     10000000,
		NumberLights: 150,
	}
	s.PIR = PIR{
		Pin:     -1,
		Pattern: "\"#ffffff\"",
	}
	s.IR = IR{
		Mapping: map[host.Key]Pattern{
			host.KeyNumeric0: "\"#000000\"",
			host.Key100Plus:  "\"#ffffff\"",
		},
	}
	s.PatternSettings.ResetDefault()
}

func (s *Settings) Validate() error {
	if err := s.Alarms.Validate(); err != nil {
		return err
	}
	for k, v := range s.IR.Mapping {
		if err := v.Validate(); err != nil {
			return errors.Wrap(err, fmt.Sprintf("can't load pattern for key %s", k))
		}
	}
	if err := s.PIR.Pattern.Validate(); err != nil {
		return errors.Wrap(err, "can't load pattern for PIR")
	}
	return s.PatternSettings.Validate()
}

// Config contains all the configuration for this specific host.
type Config struct {
	lock     sync.Mutex
	Settings Settings
	LRU      LRU
}

func (c *Config) ResetDefault() {
	c.Settings.ResetDefault()
	c.LRU.ResetDefault()
}

func (c *Config) Validate() error {
	if err := c.Settings.Validate(); err != nil {
		return err
	}
	return c.LRU.Validate()
}

func (c *Config) Load(n string) error {
	f, err := os.Open(n)
	if err != nil {
		if os.IsNotExist(err) {
			// Ignore if the file is not present.
			return nil
		}
		return err
	}
	defer f.Close()
	d := json.NewDecoder(f)
	d.UseNumber()
	if err := d.Decode(c); err != nil {
		return err
	}
	return c.Validate()
}

func (c *Config) Save(n string) error {
	if err := c.Validate(); err != nil {
		return err
	}
	b, err := json.MarshalIndent(c, "", "  ")
	if err != nil {
		return err
	}
	f, err := os.Create(n)
	if err != nil {
		return err
	}
	defer f.Close()
	_, err = f.Write(append(b, '\n'))
	return err
}

type ConfigMgr struct {
	Config
	path string
}

func (c *ConfigMgr) Load() error {
	home, err := getHome()
	if err != nil {
		return err
	}
	c.path = filepath.Join(home, "dlibox.json")
	return c.Config.Load(c.path)
}

func (c *ConfigMgr) Init(p *anim1d.Painter) error {
	if err := c.Settings.Alarms.Reset(p); err != nil {
		return nil
	}
	if len(c.Settings.PatternSettings.Startup) != 0 {
		return p.SetPattern(string(c.Settings.PatternSettings.Startup))
	}
	if len(c.Settings.PatternSettings.Last) != 0 {
		return p.SetPattern(string(c.Settings.PatternSettings.Last))
	}
	return nil
}

func (c *ConfigMgr) Close() error {
	if len(c.path) != 0 {
		return c.Config.Save(c.path)
	}
	return nil
}

//

// getHome returns the home directory even when cross compiled.
//
// When cross compiling, user.Current() fails.
func getHome() (string, error) {
	if u, err := user.Current(); err == nil {
		return u.HomeDir, nil
	}
	if s := os.Getenv("HOME"); len(s) != 0 {
		return s, nil
	}
	return "", errors.New("can't find HOME")
}
<commit_msg>Use Last by default.<commit_after>// Copyright 2016 Marc-Antoine Ruel. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

package main

import (
	"encoding/json"
	"fmt"
	"os"
	"os/user"
	"path/filepath"
	"sync"

	"github.com/maruel/dlibox/go/anim1d"
	"github.com/maruel/dlibox/go/pio/host"
	"github.com/pkg/errors"
)

// Pattern is a JSON encoded pattern.
type Pattern string

// validatePattern verifies that the pattern can be decoded, reencoded and that
// the format is the canonical one.
func (p Pattern) Validate() error {
	var obj anim1d.SPattern
	if err := json.Unmarshal([]byte(p), &obj); err != nil {
		return err
	}
	b, err := obj.MarshalJSON()
	if err == nil && Pattern(b) != p {
		err = fmt.Errorf("pattern not in canonical format: expected %v; got %v", string(b), p)
	}
	return err
}

const morning Pattern = "{\"After\":\"#000000\",\"Before\":{\"After\":\"#ffffff\",\"Before\":{\"After\":\"#ff7f00\",\"Before\":\"#000000\",\"Curve\":\"direct\",\"DurationMS\":6000000,\"OffsetMS\":0,\"_type\":\"Transition\"},\"Curve\":\"direct\",\"DurationMS\":6000000,\"OffsetMS\":6000000,\"_type\":\"Transition\"},\"Curve\":\"direct\",\"DurationMS\":600000,\"OffsetMS\":18000000,\"_type\":\"Transition\"}"

// LRU is the list of recent patterns. The first is the oldest.
type LRU struct {
	Max      int
	Patterns []Pattern
}

func (l *LRU) ResetDefault() {
	*l = LRU{
		Max: 25,
		Patterns: []Pattern{
			"{\"_type\":\"Aurore\"}",
			"{\"Child\":{\"Frame\":\"Lff0000ff0000ff0000ff0000ff0000ffffffffffffffffffffffffffffff\",\"_type\":\"Repeated\"},\"MovesPerSec\":6,\"_type\":\"Rotate\"}",
			"{\"Patterns\":[{\"_type\":\"Aurore\"},{\"Seed\":0,\"Stars\":null,\"_type\":\"NightStars\"},{\"AverageDelay\":0,\"Duration\":0,\"_type\":\"WishingStar\"}],\"Weights\":[1,1,1],\"_type\":\"Mixer\"}",
			"{\"Curve\":\"easeinout\",\"DurationShowMS\":1000000,\"DurationTransitionMS\":1000000,\"Patterns\":[\"#ff0000\",\"#00ff00\",\"#0000ff\"],\"_type\":\"Loop\"}",
			"{\"Curve\":\"direct\",\"Left\":\"#000000\",\"Right\":\"#0000ff\",\"_type\":\"Gradient\"}",
			"{\"Curve\":\"direct\",\"Left\":\"#000000\",\"Right\":\"#ff0000\",\"_type\":\"Gradient\"}",
			"{\"Curve\":\"direct\",\"Left\":\"#000000\",\"Right\":\"#00ff00\",\"_type\":\"Gradient\"}",
			"{\"Curve\":\"direct\",\"Left\":\"#000000\",\"Right\":\"#ffffff\",\"_type\":\"Gradient\"}",
			"{\"Child\":\"Lff0000ff0000ee0000dd0000cc0000bb0000aa0000990000880000770000660000550000440000330000220000110000\",\"MovesPerSec\":30,\"_type\":\"PingPong\"}",
			"{\"After\":\"#000000\",\"Before\":{\"After\":\"#ffffff\",\"Before\":{\"After\":\"#ff7f00\",\"Before\":\"#000000\",\"Curve\":\"direct\",\"DurationMS\":0,\"OffsetMS\":0,\"_type\":\"Transition\"},\"Curve\":\"direct\",\"DurationMS\":0,\"OffsetMS\":0,\"_type\":\"Transition\"},\"Curve\":\"direct\",\"DurationMS\":0,\"OffsetMS\":0,\"_type\":\"Transition\"}",
			"\"#000000\"",
			"{\"Child\":\"Lffffff\",\"MovesPerSec\":30,\"_type\":\"PingPong\"}",
			"{\"Curve\":\"easeinout\",\"DurationShowMS\":1000000,\"DurationTransitionMS\":10000000,\"Patterns\":[\"#ff0000\",\"#ff7f00\",\"#ffff00\",\"#00ff00\",\"#0000ff\",\"#4b0082\",\"#8b00ff\"],\"_type\":\"Loop\"}",
			"\"Rainbow\"",
			"{\"Seed\":0,\"Stars\":null,\"_type\":\"NightStars\"}",
			"{\"Child\":\"L010001ff000000ff000000ff\",\"_type\":\"Chronometer\"}",
			morning,
		},
	}
}

func (l *LRU) Validate() error {
	for i, s := range l.Patterns {
		if err := s.Validate(); err != nil {
			return errors.Wrap(err, fmt.Sprintf("can't load recent pattern %d", i))
		}
	}
	return nil
}

// Inject moves the pattern at the top of LRU cache.
func (l *LRU) Inject(pattern string) {
	for i, old := range l.Patterns {
		if old == Pattern(pattern) {
			copy(l.Patterns[i:], l.Patterns[i+1:])
			l.Patterns = l.Patterns[:len(l.Patterns)-1]
			break
		}
	}
	if len(l.Patterns) < l.Max {
		l.Patterns = append(l.Patterns, "")
	}
	copy(l.Patterns[1:], l.Patterns)
	l.Patterns[0] = Pattern(pattern)
}

//

// APA102 contains light specific settings.
type APA102 struct {
	// Speed of the transfer.
	SPIspeed int64
	// Number of lights controlled by this device. If lower than the actual
	// number of lights, the remaining lights will flash oddly.
	NumberLights int
}

// IR contains InfraRed remote information.
type IR struct {
	Mapping map[host.Key]Pattern // TODO(maruel): We may actually do something more complex than just set a pattern.
}

// PIR contains a motion detection behavior.
type PIR struct {
	Pin     int
	Pattern Pattern // TODO(maruel): We may actually do something more complex than just set a pattern.
}

// PatternSettings contains settings about patterns.
type PatternSettings struct {
	Named   map[string]Pattern // Patterns that are 'named'.
	Startup Pattern            // Startup pattern to use. If not set, use Last.
	Last    Pattern            // Last pattern used.
}

func (p *PatternSettings) ResetDefault() {
	*p = PatternSettings{
		Named:   map[string]Pattern{},
		Startup: "\"#010001\"",
		Last:    "\"#010001\"",
	}
}

func (p *PatternSettings) Validate() error {
	for k, v := range p.Named {
		if err := v.Validate(); err != nil {
			return errors.Wrap(err, fmt.Sprintf("can't load pattern %s", k))
		}
	}
	if len(p.Startup) != 0 {
		if err := p.Startup.Validate(); err != nil {
			return errors.Wrap(err, "can't load pattern for Last")
		}
	}
	if len(p.Last) != 0 {
		return p.Last.Validate()
	}
	return nil
}

// Settings is all the host settings.
type Settings struct {
	Alarms          Alarms
	APA102          APA102
	IR              IR
	PIR             PIR
	PatternSettings PatternSettings
}

func (s *Settings) ResetDefault() {
	s.Alarms.ResetDefault()
	s.APA102 = APA102{
		SPIspeed:     10000000,
		NumberLights: 150,
	}
	s.PIR = PIR{
		Pin:     -1,
		Pattern: "\"#ffffff\"",
	}
	s.IR = IR{
		Mapping: map[host.Key]Pattern{
			host.KeyNumeric0: "\"#000000\"",
			host.Key100Plus:  "\"#ffffff\"",
		},
	}
	s.PatternSettings.ResetDefault()
}

func (s *Settings) Validate() error {
	if err := s.Alarms.Validate(); err != nil {
		return err
	}
	for k, v := range s.IR.Mapping {
		if err := v.Validate(); err != nil {
			return errors.Wrap(err, fmt.Sprintf("can't load pattern for key %s", k))
		}
	}
	if err := s.PIR.Pattern.Validate(); err != nil {
		return errors.Wrap(err, "can't load pattern for PIR")
	}
	return s.PatternSettings.Validate()
}

// Config contains all the configuration for this specific host.
type Config struct {
	lock     sync.Mutex
	Settings Settings
	LRU      LRU
}

func (c *Config) ResetDefault() {
	c.Settings.ResetDefault()
	c.LRU.ResetDefault()
}

func (c *Config) Validate() error {
	if err := c.Settings.Validate(); err != nil {
		return err
	}
	return c.LRU.Validate()
}

func (c *Config) Load(n string) error {
	f, err := os.Open(n)
	if err != nil {
		if os.IsNotExist(err) {
			// Ignore if the file is not present.
			return nil
		}
		return err
	}
	defer f.Close()
	d := json.NewDecoder(f)
	d.UseNumber()
	if err := d.Decode(c); err != nil {
		return err
	}
	return c.Validate()
}

func (c *Config) Save(n string) error {
	if err := c.Validate(); err != nil {
		return err
	}
	b, err := json.MarshalIndent(c, "", "  ")
	if err != nil {
		return err
	}
	f, err := os.Create(n)
	if err != nil {
		return err
	}
	defer f.Close()
	_, err = f.Write(append(b, '\n'))
	return err
}

type ConfigMgr struct {
	Config
	path string
}

func (c *ConfigMgr) Load() error {
	home, err := getHome()
	if err != nil {
		return err
	}
	c.path = filepath.Join(home, "dlibox.json")
	return c.Config.Load(c.path)
}

func (c *ConfigMgr) Init(p *anim1d.Painter) error {
	if err := c.Settings.Alarms.Reset(p); err != nil {
		return nil
	}
	if len(c.Settings.PatternSettings.Last) != 0 {
		return p.SetPattern(string(c.Settings.PatternSettings.Last))
	}
	if len(c.Settings.PatternSettings.Startup) != 0 {
		return p.SetPattern(string(c.Settings.PatternSettings.Startup))
	}
	return nil
}

func (c *ConfigMgr) Close() error {
	if len(c.path) != 0 {
		return c.Config.Save(c.path)
	}
	return nil
}

//

// getHome returns the home directory even when cross compiled.
//
// When cross compiling, user.Current() fails.
func getHome() (string, error) {
	if u, err := user.Current(); err == nil {
		return u.HomeDir, nil
	}
	if s := os.Getenv("HOME"); len(s) != 0 {
		return s, nil
	}
	return "", errors.New("can't find HOME")
}
<|endoftext|>


<commit_before>package posix

import (
	"os"
	"syscall"

	co "github.com/lunixbochs/usercorn/go/kernel/common"
)

func (k *PosixKernel) Mmap(addrHint, size uint64, prot, flags int, fd co.Fd, off co.Off) uint64 {
	// TODO: MAP_FIXED means abort if we can't get the address
	mmap, err := k.U.Mmap(addrHint, size)
	if err != nil {
		return UINT64_MAX // FIXME
	}
	if fd > 0 {
		path, err := PathFromFd(int(fd))
		fd2, _ := syscall.Dup(int(fd))
		f := os.NewFile(uintptr(fd2), path)
		// register mapped files for symbolication of mapped shared libraries
		if err == nil {
			k.U.RegisterAddr(f, mmap.Addr, size, int64(off))
		}
		tmp := make([]byte, size)
		n, _ := f.ReadAt(tmp, int64(off))
		k.U.MemWrite(mmap.Addr, tmp[:n])
		syscall.Close(fd2)
	}
	// currently just trusting protection enums between Unicorn/kernel to match
	k.U.MemProtect(mmap.Addr, size, prot)
	return mmap.Addr
}

func (k *PosixKernel) Mmap2(addrHint, size uint64, prot, flags int, fd co.Fd, off co.Off) uint64 {
	return k.Mmap(addrHint, size, prot, flags, fd, off)
}

func (k *PosixKernel) Munmap(addr, size uint64) uint64 {
	return 0
}

func (k *PosixKernel) Mprotect(addr, size uint64, prot int) uint64 {
	if err := k.U.MemProtect(addr, size, prot); err != nil {
		return UINT64_MAX // FIXME
	}
	return 0
}

func (k *PosixKernel) Brk(addr uint64) uint64 {
	// TODO: return is Linux specific
	ret, _ := k.U.Brk(addr)
	return ret
}
<commit_msg>fix MAP_FIXED<commit_after>package posix

import (
	"os"
	"syscall"

	co "github.com/lunixbochs/usercorn/go/kernel/common"
	"github.com/lunixbochs/usercorn/go/models"
)

func (k *PosixKernel) Mmap(addrHint, size uint64, prot, flags int, fd co.Fd, off co.Off) uint64 {
	MAP_FIXED := 0x10 // on OS X and Linux anyway
	// TODO: MAP_FIXED means abort if we can't get the address
	var err error
	var mmap *models.Mmap
	if flags&MAP_FIXED != 0 {
		err = k.U.MemMapProt(addrHint, size, prot)
		mmap = &models.Mmap{Addr: addrHint}
	} else {
		mmap, err = k.U.Mmap(addrHint, size)
	}
	if err != nil {
		return UINT64_MAX // FIXME
	}
	if fd > 0 {
		path, err := PathFromFd(int(fd))
		fd2, _ := syscall.Dup(int(fd))
		f := os.NewFile(uintptr(fd2), path)
		// register mapped files for symbolication of mapped shared libraries
		if err == nil {
			k.U.RegisterAddr(f, mmap.Addr, size, int64(off))
		}
		tmp := make([]byte, size)
		n, _ := f.ReadAt(tmp, int64(off))
		k.U.MemWrite(mmap.Addr, tmp[:n])
		syscall.Close(fd2)
	}
	// currently just trusting protection enums between Unicorn/kernel to match
	k.U.MemProtect(mmap.Addr, size, prot)
	return mmap.Addr
}

func (k *PosixKernel) Mmap2(addrHint, size uint64, prot, flags int, fd co.Fd, off co.Off) uint64 {
	return k.Mmap(addrHint, size, prot, flags, fd, off)
}

func (k *PosixKernel) Munmap(addr, size uint64) uint64 {
	return 0
}

func (k *PosixKernel) Mprotect(addr, size uint64, prot int) uint64 {
	if err := k.U.MemProtect(addr, size, prot); err != nil {
		return UINT64_MAX // FIXME
	}
	return 0
}

func (k *PosixKernel) Brk(addr uint64) uint64 {
	// TODO: return is Linux specific
	ret, _ := k.U.Brk(addr)
	return ret
}
<|endoftext|>


<commit_before>package mysql

import (
	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
	"vitess.io/vitess/go/vt/vterrors"
)

var (
	// BinglogMagicNumber is 4-byte number at the beginning of every binary log
	BinglogMagicNumber = []byte{0xfe, 0x62, 0x69, 0x6e}
	readPacketErr      = vterrors.Errorf(vtrpcpb.Code_INTERNAL, "error reading BinlogDumpGTID packet")
)

func (c *Conn) parseComBinlogDumpGTID(data []byte) (logFile string, logPos uint64, position Position, err error) {
	pos := 1
	pos += 2 // flags
	pos += 4 // server-id

	fileNameLen, pos, ok := readUint32(data, pos)
	if !ok {
		return logFile, logPos, position, readPacketErr
	}
	logFile = string(data[pos : pos+int(fileNameLen)])
	pos += int(fileNameLen)

	logPos, pos, ok = readUint64(data, pos)
	if !ok {
		return logFile, logPos, position, readPacketErr
	}

	dataSize, pos, ok := readUint32(data, pos)
	if !ok {
		return logFile, logPos, position, readPacketErr
	}
	if gtid := string(data[pos : pos+int(dataSize)]); gtid != "" {
		position, err = DecodePosition(gtid)
		if err != nil {
			return logFile, logPos, position, err
		}
	}

	return logFile, logPos, position, nil
}
<commit_msg>add copyright header<commit_after>/*
Copyright 2022 The Vitess Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package mysql

import (
	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
	"vitess.io/vitess/go/vt/vterrors"
)

var (
	// BinglogMagicNumber is 4-byte number at the beginning of every binary log
	BinglogMagicNumber = []byte{0xfe, 0x62, 0x69, 0x6e}
	readPacketErr      = vterrors.Errorf(vtrpcpb.Code_INTERNAL, "error reading BinlogDumpGTID packet")
)

func (c *Conn) parseComBinlogDumpGTID(data []byte) (logFile string, logPos uint64, position Position, err error) {
	pos := 1
	pos += 2 // flags
	pos += 4 // server-id

	fileNameLen, pos, ok := readUint32(data, pos)
	if !ok {
		return logFile, logPos, position, readPacketErr
	}
	logFile = string(data[pos : pos+int(fileNameLen)])
	pos += int(fileNameLen)

	logPos, pos, ok = readUint64(data, pos)
	if !ok {
		return logFile, logPos, position, readPacketErr
	}

	dataSize, pos, ok := readUint32(data, pos)
	if !ok {
		return logFile, logPos, position, readPacketErr
	}
	if gtid := string(data[pos : pos+int(dataSize)]); gtid != "" {
		position, err = DecodePosition(gtid)
		if err != nil {
			return logFile, logPos, position, err
		}
	}

	return logFile, logPos, position, nil
}
<|endoftext|>


<commit_before>package teams

import (
	"context"
	"testing"

	"github.com/keybase/client/go/protocol/keybase1"
)

func TestRotate(t *testing.T) {
	tc, owner, other, name := memberSetupMultiple(t)
	defer tc.Cleanup()

	if err := SetRoleWriter(context.TODO(), tc.G, name, other.Username); err != nil {
		t.Fatal(err)
	}

	team, err := Get(context.TODO(), tc.G, name)
	if err != nil {
		t.Fatal(err)
	}
	if team.Box.Generation != 1 {
		t.Fatalf("initial team generation: %d, expected 1", team.Box.Generation)
	}
	ctextInitial := team.Box.Ctext

	if err := team.Rotate(context.TODO()); err != nil {
		t.Fatal(err)
	}

	after, err := Get(context.TODO(), tc.G, name)
	if err != nil {
		t.Fatal(err)
	}
	if after.Box.Generation != 2 {
		t.Fatalf("rotated team generation: %d, expected 2", after.Box.Generation)
	}
	if after.Box.Ctext == ctextInitial {
		t.Fatal("TeamBox.Ctext did not change when rotated")
	}

	assertRole(tc, name, owner.Username, keybase1.TeamRole_OWNER)
	assertRole(tc, name, other.Username, keybase1.TeamRole_WRITER)
}

func TestHandleRotateRequest(t *testing.T) {
	tc, owner, other, name := memberSetupMultiple(t)
	defer tc.Cleanup()

	if err := SetRoleWriter(context.TODO(), tc.G, name, other.Username); err != nil {
		t.Fatal(err)
	}

	team, err := Get(context.TODO(), tc.G, name)
	if err != nil {
		t.Fatal(err)
	}
	if team.Box.Generation != 1 {
		t.Fatalf("initial team generation: %d, expected 1", team.Box.Generation)
	}
	ctextInitial := team.Box.Ctext

	if err := HandleRotateRequest(context.TODO(), tc.G, team.ID, team.Box.Generation); err != nil {
		t.Fatal(err)
	}

	after, err := Get(context.TODO(), tc.G, name)
	if err != nil {
		t.Fatal(err)
	}
	if after.Box.Generation != 2 {
		t.Fatalf("rotated team generation: %d, expected 2", after.Box.Generation)
	}
	if after.Box.Ctext == ctextInitial {
		t.Fatal("TeamBox.Ctext did not change when rotated")
	}

	assertRole(tc, name, owner.Username, keybase1.TeamRole_OWNER)
	assertRole(tc, name, other.Username, keybase1.TeamRole_WRITER)
}
<commit_msg>Add test for team.clkr with old generation<commit_after>package teams

import (
	"context"
	"testing"

	"github.com/keybase/client/go/protocol/keybase1"
)

func TestRotate(t *testing.T) {
	tc, owner, other, name := memberSetupMultiple(t)
	defer tc.Cleanup()

	if err := SetRoleWriter(context.TODO(), tc.G, name, other.Username); err != nil {
		t.Fatal(err)
	}

	team, err := Get(context.TODO(), tc.G, name)
	if err != nil {
		t.Fatal(err)
	}
	if team.Box.Generation != 1 {
		t.Fatalf("initial team generation: %d, expected 1", team.Box.Generation)
	}
	ctextInitial := team.Box.Ctext

	if err := team.Rotate(context.TODO()); err != nil {
		t.Fatal(err)
	}

	after, err := Get(context.TODO(), tc.G, name)
	if err != nil {
		t.Fatal(err)
	}
	if after.Box.Generation != 2 {
		t.Fatalf("rotated team generation: %d, expected 2", after.Box.Generation)
	}
	if after.Box.Ctext == ctextInitial {
		t.Fatal("TeamBox.Ctext did not change when rotated")
	}

	assertRole(tc, name, owner.Username, keybase1.TeamRole_OWNER)
	assertRole(tc, name, other.Username, keybase1.TeamRole_WRITER)
}

func TestHandleRotateRequestOldGeneration(t *testing.T) {
	tc, owner, other, name := memberSetupMultiple(t)
	defer tc.Cleanup()

	if err := SetRoleWriter(context.TODO(), tc.G, name, other.Username); err != nil {
		t.Fatal(err)
	}

	team, err := Get(context.TODO(), tc.G, name)
	if err != nil {
		t.Fatal(err)
	}

	// rotate to bump the generation
	if err := team.Rotate(context.TODO()); err != nil {
		t.Fatal(err)
	}

	team, err = Get(context.TODO(), tc.G, name)
	if err != nil {
		t.Fatal(err)
	}
	if team.Box.Generation != 2 {
		t.Fatalf("team generation: %d, expected 2", team.Box.Generation)
	}
	ctextInitial := team.Box.Ctext

	// this shouldn't do anything
	if err := HandleRotateRequest(context.TODO(), tc.G, team.ID, 1); err != nil {
		t.Fatal(err)
	}

	after, err := Get(context.TODO(), tc.G, name)
	if err != nil {
		t.Fatal(err)
	}
	if after.Box.Generation != 2 {
		t.Fatalf("HandleRotateRequest with old generation changed team generation: %d, expected 2", after.Box.Generation)
	}
	if after.Box.Ctext != ctextInitial {
		t.Fatal("TeamBox.Ctext changed after HandleRotateRequest with old generation")
	}

	assertRole(tc, name, owner.Username, keybase1.TeamRole_OWNER)
	assertRole(tc, name, other.Username, keybase1.TeamRole_WRITER)
}

func TestHandleRotateRequest(t *testing.T) {
	tc, owner, other, name := memberSetupMultiple(t)
	defer tc.Cleanup()

	if err := SetRoleWriter(context.TODO(), tc.G, name, other.Username); err != nil {
		t.Fatal(err)
	}

	team, err := Get(context.TODO(), tc.G, name)
	if err != nil {
		t.Fatal(err)
	}
	if team.Box.Generation != 1 {
		t.Fatalf("initial team generation: %d, expected 1", team.Box.Generation)
	}
	ctextInitial := team.Box.Ctext

	if err := HandleRotateRequest(context.TODO(), tc.G, team.ID, team.Box.Generation); err != nil {
		t.Fatal(err)
	}

	after, err := Get(context.TODO(), tc.G, name)
	if err != nil {
		t.Fatal(err)
	}
	if after.Box.Generation != 2 {
		t.Fatalf("rotated team generation: %d, expected 2", after.Box.Generation)
	}
	if after.Box.Ctext == ctextInitial {
		t.Fatal("TeamBox.Ctext did not change when rotated")
	}

	assertRole(tc, name, owner.Username, keybase1.TeamRole_OWNER)
	assertRole(tc, name, other.Username, keybase1.TeamRole_WRITER)
}
<|endoftext|>


<commit_before>package net

import (
	"encoding/json"
	"strconv"
	"time"

	"github.com/cloudfoundry/cli/cf/configuration/core_config"
	"github.com/cloudfoundry/cli/cf/errors"
	"github.com/cloudfoundry/cli/cf/terminal"
)

type ccErrorResponse struct {
	Code        int
	Description string
}

func cloudControllerErrorHandler(statusCode int, body []byte) error {
	response := ccErrorResponse{}
	json.Unmarshal(body, &response)

	if response.Code == 1000 { // MAGICKAL NUMBERS AHOY
		return errors.NewInvalidTokenError(response.Description)
	} else {
		return errors.NewHttpError(statusCode, strconv.Itoa(response.Code), response.Description)
	}
}

func NewCloudControllerGateway(config core_config.Reader, clock func() time.Time, ui terminal.UI) Gateway {
	gateway := newGateway(cloudControllerErrorHandler, config, ui)
	gateway.Clock = clock
	gateway.PollingEnabled = true
	return gateway
}
<commit_msg>Remove magic number<commit_after>package net

import (
	"encoding/json"
	"strconv"
	"time"

	"github.com/cloudfoundry/cli/cf/configuration/core_config"
	"github.com/cloudfoundry/cli/cf/errors"
	"github.com/cloudfoundry/cli/cf/terminal"
)

type ccErrorResponse struct {
	Code        int
	Description string
}

const invalidTokenCode = 1000

func cloudControllerErrorHandler(statusCode int, body []byte) error {
	response := ccErrorResponse{}
	json.Unmarshal(body, &response)

	if response.Code == invalidTokenCode {
		return errors.NewInvalidTokenError(response.Description)
	}

	return errors.NewHttpError(statusCode, strconv.Itoa(response.Code), response.Description)
}

func NewCloudControllerGateway(config core_config.Reader, clock func() time.Time, ui terminal.UI) Gateway {
	gateway := newGateway(cloudControllerErrorHandler, config, ui)
	gateway.Clock = clock
	gateway.PollingEnabled = true
	return gateway
}
<|endoftext|>


<commit_before>package wrappa_test

import (
	"net/http"

	"github.com/concourse/concourse/atc"
	"github.com/concourse/concourse/atc/api/auth"
	"github.com/concourse/concourse/atc/db/dbfakes"
	"github.com/concourse/concourse/atc/wrappa"
	"github.com/tedsuo/rata"

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

var _ = Describe("APIAuthWrappa", func() {
	var (
		rejector                                auth.Rejector
		fakeCheckPipelineAccessHandlerFactory   auth.CheckPipelineAccessHandlerFactory
		fakeCheckBuildReadAccessHandlerFactory  auth.CheckBuildReadAccessHandlerFactory
		fakeCheckBuildWriteAccessHandlerFactory auth.CheckBuildWriteAccessHandlerFactory
		fakeCheckWorkerTeamAccessHandlerFactory auth.CheckWorkerTeamAccessHandlerFactory
		fakeBuildFactory                        *dbfakes.FakeBuildFactory
	)

	BeforeEach(func() {
		fakeTeamFactory := new(dbfakes.FakeTeamFactory)
		workerFactory := new(dbfakes.FakeWorkerFactory)
		fakeBuildFactory = new(dbfakes.FakeBuildFactory)
		fakeCheckPipelineAccessHandlerFactory = auth.NewCheckPipelineAccessHandlerFactory(
			fakeTeamFactory,
		)
		rejector = auth.UnauthorizedRejector{}

		fakeCheckBuildReadAccessHandlerFactory = auth.NewCheckBuildReadAccessHandlerFactory(fakeBuildFactory)
		fakeCheckBuildWriteAccessHandlerFactory = auth.NewCheckBuildWriteAccessHandlerFactory(fakeBuildFactory)
		fakeCheckWorkerTeamAccessHandlerFactory = auth.NewCheckWorkerTeamAccessHandlerFactory(workerFactory)
	})

	unauthenticated := func(handler http.Handler) http.Handler {
		return auth.CSRFValidationHandler(
			handler,
			rejector,
		)
	}

	authenticated := func(handler http.Handler) http.Handler {
		return auth.CSRFValidationHandler(
			auth.CheckAuthenticationHandler(
				handler,
				rejector,
			),
			rejector,
		)
	}

	authenticatedAndAdmin := func(handler http.Handler) http.Handler {
		return auth.CSRFValidationHandler(
			auth.CheckAdminHandler(
				handler,
				rejector,
			),
			rejector,
		)
	}

	authorized := func(handler http.Handler) http.Handler {
		return auth.CSRFValidationHandler(
			auth.CheckAuthorizationHandler(
				handler,
				rejector,
			),
			rejector,
		)
	}

	openForPublicPipelineOrAuthorized := func(handler http.Handler) http.Handler {
		return auth.CSRFValidationHandler(
			fakeCheckPipelineAccessHandlerFactory.HandlerFor(
				handler,
				rejector,
			),
			rejector,
		)
	}

	doesNotCheckIfPrivateJob := func(handler http.Handler) http.Handler {
		return auth.CSRFValidationHandler(
			fakeCheckBuildReadAccessHandlerFactory.AnyJobHandler(
				handler,
				rejector,
			),
			rejector,
		)
	}

	checksIfPrivateJob := func(handler http.Handler) http.Handler {
		return auth.CSRFValidationHandler(
			fakeCheckBuildReadAccessHandlerFactory.CheckIfPrivateJobHandler(
				handler,
				rejector,
			),
			rejector,
		)
	}

	checkWritePermissionForBuild := func(handler http.Handler) http.Handler {
		return auth.CSRFValidationHandler(
			fakeCheckBuildWriteAccessHandlerFactory.HandlerFor(
				handler,
				rejector,
			),
			rejector,
		)
	}

	checkTeamAccessForWorker := func(handler http.Handler) http.Handler {
		return auth.CSRFValidationHandler(
			fakeCheckWorkerTeamAccessHandlerFactory.HandlerFor(
				handler,
				rejector,
			),
			rejector,
		)
	}

	Describe("Wrap", func() {
		var (
			inputHandlers    rata.Handlers
			expectedHandlers rata.Handlers

			wrappedHandlers rata.Handlers
		)

		BeforeEach(func() {
			inputHandlers = rata.Handlers{}

			for _, route := range atc.Routes {
				inputHandlers[route.Name] = &stupidHandler{}
			}

			expectedHandlers = rata.Handlers{
				//unauthenticated / delegating to handler
				atc.GetInfo:              unauthenticated(inputHandlers[atc.GetInfo]),
				atc.DownloadCLI:          unauthenticated(inputHandlers[atc.DownloadCLI]),
				atc.CheckResourceWebHook: unauthenticated(inputHandlers[atc.CheckResourceWebHook]),
				atc.ListAllPipelines:     unauthenticated(inputHandlers[atc.ListAllPipelines]),
				atc.ListBuilds:           unauthenticated(inputHandlers[atc.ListBuilds]),
				atc.ListPipelines:        unauthenticated(inputHandlers[atc.ListPipelines]),
				atc.ListAllJobs:          unauthenticated(inputHandlers[atc.ListAllJobs]),
				atc.ListAllResources:     unauthenticated(inputHandlers[atc.ListAllResources]),
				atc.ListTeams:            unauthenticated(inputHandlers[atc.ListTeams]),
				atc.MainJobBadge:         unauthenticated(inputHandlers[atc.MainJobBadge]),

				// authorized or public pipeline
				atc.GetBuild:       doesNotCheckIfPrivateJob(inputHandlers[atc.GetBuild]),
				atc.BuildResources: doesNotCheckIfPrivateJob(inputHandlers[atc.BuildResources]),
				atc.GetBuildPlan:   doesNotCheckIfPrivateJob(inputHandlers[atc.GetBuildPlan]),

				// authorized or public pipeline and public job
				atc.BuildEvents:         checksIfPrivateJob(inputHandlers[atc.BuildEvents]),
				atc.GetBuildPreparation: checksIfPrivateJob(inputHandlers[atc.GetBuildPreparation]),

				// resource belongs to authorized team
				atc.AbortBuild:              checkWritePermissionForBuild(inputHandlers[atc.AbortBuild]),
				atc.SendInputToBuildPlan:    checkWritePermissionForBuild(inputHandlers[atc.SendInputToBuildPlan]),
				atc.ReadOutputFromBuildPlan: checkWritePermissionForBuild(inputHandlers[atc.ReadOutputFromBuildPlan]),

				// resource belongs to authorized team
				atc.PruneWorker:              checkTeamAccessForWorker(inputHandlers[atc.PruneWorker]),
				atc.LandWorker:               checkTeamAccessForWorker(inputHandlers[atc.LandWorker]),
				atc.ReportWorkerContainers:   checkTeamAccessForWorker(inputHandlers[atc.ReportWorkerContainers]),
				atc.ReportWorkerVolumes:      checkTeamAccessForWorker(inputHandlers[atc.ReportWorkerVolumes]),
				atc.RetireWorker:             checkTeamAccessForWorker(inputHandlers[atc.RetireWorker]),
				atc.ListDestroyingContainers: checkTeamAccessForWorker(inputHandlers[atc.ListDestroyingContainers]),
				atc.ListDestroyingVolumes:    checkTeamAccessForWorker(inputHandlers[atc.ListDestroyingVolumes]),

				// belongs to public pipeline or authorized
				atc.GetPipeline:                   openForPublicPipelineOrAuthorized(inputHandlers[atc.GetPipeline]),
				atc.GetJobBuild:                   openForPublicPipelineOrAuthorized(inputHandlers[atc.GetJobBuild]),
				atc.PipelineBadge:                 openForPublicPipelineOrAuthorized(inputHandlers[atc.PipelineBadge]),
				atc.JobBadge:                      openForPublicPipelineOrAuthorized(inputHandlers[atc.JobBadge]),
				atc.ListJobs:                      openForPublicPipelineOrAuthorized(inputHandlers[atc.ListJobs]),
				atc.GetJob:                        openForPublicPipelineOrAuthorized(inputHandlers[atc.GetJob]),
				atc.ListJobBuilds:                 openForPublicPipelineOrAuthorized(inputHandlers[atc.ListJobBuilds]),
				atc.ListPipelineBuilds:            openForPublicPipelineOrAuthorized(inputHandlers[atc.ListPipelineBuilds]),
				atc.GetResource:                   openForPublicPipelineOrAuthorized(inputHandlers[atc.GetResource]),
				atc.ListBuildsWithVersionAsInput:  openForPublicPipelineOrAuthorized(inputHandlers[atc.ListBuildsWithVersionAsInput]),
				atc.ListBuildsWithVersionAsOutput: openForPublicPipelineOrAuthorized(inputHandlers[atc.ListBuildsWithVersionAsOutput]),
				atc.ListResources:                 openForPublicPipelineOrAuthorized(inputHandlers[atc.ListResources]),
				atc.ListResourceTypes:             openForPublicPipelineOrAuthorized(inputHandlers[atc.ListResourceTypes]),
				atc.ListResourceVersions:          openForPublicPipelineOrAuthorized(inputHandlers[atc.ListResourceVersions]),
				atc.GetResourceCausality:          openForPublicPipelineOrAuthorized(inputHandlers[atc.GetResourceCausality]),
				atc.GetResourceVersion:            openForPublicPipelineOrAuthorized(inputHandlers[atc.GetResourceVersion]),

				// authenticated
				atc.CreateBuild:     authenticated(inputHandlers[atc.CreateBuild]),
				atc.GetContainer:    authenticated(inputHandlers[atc.GetContainer]),
				atc.HijackContainer: authenticated(inputHandlers[atc.HijackContainer]),
				atc.ListContainers:  authenticated(inputHandlers[atc.ListContainers]),
				atc.ListVolumes:     authenticated(inputHandlers[atc.ListVolumes]),
				atc.ListTeamBuilds:  authenticated(inputHandlers[atc.ListTeamBuilds]),
				atc.ListWorkers:     authenticated(inputHandlers[atc.ListWorkers]),
				atc.RegisterWorker:  authenticated(inputHandlers[atc.RegisterWorker]),
				atc.HeartbeatWorker: authenticated(inputHandlers[atc.HeartbeatWorker]),
				atc.DeleteWorker:    authenticated(inputHandlers[atc.DeleteWorker]),
				atc.SetTeam:         authenticated(inputHandlers[atc.SetTeam]),
				atc.RenameTeam:      authenticated(inputHandlers[atc.RenameTeam]),
				atc.DestroyTeam:     authenticated(inputHandlers[atc.DestroyTeam]),

				// authenticated and is admin
				atc.GetLogLevel:  authenticatedAndAdmin(inputHandlers[atc.GetLogLevel]),
				atc.SetLogLevel:  authenticatedAndAdmin(inputHandlers[atc.SetLogLevel]),
				atc.GetInfoCreds: authenticatedAndAdmin(inputHandlers[atc.GetInfoCreds]),

				// authorized (requested team matches resource team)
				atc.CheckResource:          authorized(inputHandlers[atc.CheckResource]),
				atc.CheckResourceType:      authorized(inputHandlers[atc.CheckResourceType]),
				atc.CreateJobBuild:         authorized(inputHandlers[atc.CreateJobBuild]),
				atc.DeletePipeline:         authorized(inputHandlers[atc.DeletePipeline]),
				atc.DisableResourceVersion: authorized(inputHandlers[atc.DisableResourceVersion]),
				atc.EnableResourceVersion:  authorized(inputHandlers[atc.EnableResourceVersion]),
				atc.PinResourceVersion:     authorized(inputHandlers[atc.PinResourceVersion]),
				atc.UnpinResource:          authorized(inputHandlers[atc.UnpinResource]),
				atc.GetConfig:              authorized(inputHandlers[atc.GetConfig]),
				atc.GetVersionsDB:          authorized(inputHandlers[atc.GetVersionsDB]),
				atc.ListJobInputs:          authorized(inputHandlers[atc.ListJobInputs]),
				atc.OrderPipelines:         authorized(inputHandlers[atc.OrderPipelines]),
				atc.PauseJob:               authorized(inputHandlers[atc.PauseJob]),
				atc.PausePipeline:          authorized(inputHandlers[atc.PausePipeline]),
				atc.RenamePipeline:         authorized(inputHandlers[atc.RenamePipeline]),
				atc.SaveConfig:             authorized(inputHandlers[atc.SaveConfig]),
				atc.UnpauseJob:             authorized(inputHandlers[atc.UnpauseJob]),
				atc.UnpausePipeline:        authorized(inputHandlers[atc.UnpausePipeline]),
				atc.ExposePipeline:         authorized(inputHandlers[atc.ExposePipeline]),
				atc.HidePipeline:           authorized(inputHandlers[atc.HidePipeline]),
				atc.CreatePipelineBuild:    authorized(inputHandlers[atc.CreatePipelineBuild]),
				atc.ClearTaskCache:         authorized(inputHandlers[atc.ClearTaskCache]),
			}
		})

		JustBeforeEach(func() {
			wrappedHandlers = wrappa.NewAPIAuthWrappa(
				fakeCheckPipelineAccessHandlerFactory,
				fakeCheckBuildReadAccessHandlerFactory,
				fakeCheckBuildWriteAccessHandlerFactory,
				fakeCheckWorkerTeamAccessHandlerFactory,
			).Wrap(inputHandlers)

		})

		It("validates sensitive routes, and noop validates public routes", func() {
			for name, _ := range inputHandlers {
				Expect(wrappedHandlers[name]).To(BeIdenticalTo(expectedHandlers[name]))
			}
		})
	})
})
<commit_msg>atc: fix wrappa test<commit_after>package wrappa_test

import (
	"net/http"

	"github.com/concourse/concourse/atc"
	"github.com/concourse/concourse/atc/api/auth"
	"github.com/concourse/concourse/atc/db/dbfakes"
	"github.com/concourse/concourse/atc/wrappa"
	"github.com/tedsuo/rata"

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

var _ = Describe("APIAuthWrappa", func() {
	var (
		rejector                                auth.Rejector
		fakeCheckPipelineAccessHandlerFactory   auth.CheckPipelineAccessHandlerFactory
		fakeCheckBuildReadAccessHandlerFactory  auth.CheckBuildReadAccessHandlerFactory
		fakeCheckBuildWriteAccessHandlerFactory auth.CheckBuildWriteAccessHandlerFactory
		fakeCheckWorkerTeamAccessHandlerFactory auth.CheckWorkerTeamAccessHandlerFactory
		fakeBuildFactory                        *dbfakes.FakeBuildFactory
	)

	BeforeEach(func() {
		fakeTeamFactory := new(dbfakes.FakeTeamFactory)
		workerFactory := new(dbfakes.FakeWorkerFactory)
		fakeBuildFactory = new(dbfakes.FakeBuildFactory)
		fakeCheckPipelineAccessHandlerFactory = auth.NewCheckPipelineAccessHandlerFactory(
			fakeTeamFactory,
		)
		rejector = auth.UnauthorizedRejector{}

		fakeCheckBuildReadAccessHandlerFactory = auth.NewCheckBuildReadAccessHandlerFactory(fakeBuildFactory)
		fakeCheckBuildWriteAccessHandlerFactory = auth.NewCheckBuildWriteAccessHandlerFactory(fakeBuildFactory)
		fakeCheckWorkerTeamAccessHandlerFactory = auth.NewCheckWorkerTeamAccessHandlerFactory(workerFactory)
	})

	unauthenticated := func(handler http.Handler) http.Handler {
		return auth.CSRFValidationHandler(
			handler,
			rejector,
		)
	}

	authenticated := func(handler http.Handler) http.Handler {
		return auth.CSRFValidationHandler(
			auth.CheckAuthenticationHandler(
				handler,
				rejector,
			),
			rejector,
		)
	}

	authenticatedAndAdmin := func(handler http.Handler) http.Handler {
		return auth.CSRFValidationHandler(
			auth.CheckAdminHandler(
				handler,
				rejector,
			),
			rejector,
		)
	}

	authorized := func(handler http.Handler) http.Handler {
		return auth.CSRFValidationHandler(
			auth.CheckAuthorizationHandler(
				handler,
				rejector,
			),
			rejector,
		)
	}

	openForPublicPipelineOrAuthorized := func(handler http.Handler) http.Handler {
		return auth.CSRFValidationHandler(
			fakeCheckPipelineAccessHandlerFactory.HandlerFor(
				handler,
				rejector,
			),
			rejector,
		)
	}

	doesNotCheckIfPrivateJob := func(handler http.Handler) http.Handler {
		return auth.CSRFValidationHandler(
			fakeCheckBuildReadAccessHandlerFactory.AnyJobHandler(
				handler,
				rejector,
			),
			rejector,
		)
	}

	checksIfPrivateJob := func(handler http.Handler) http.Handler {
		return auth.CSRFValidationHandler(
			fakeCheckBuildReadAccessHandlerFactory.CheckIfPrivateJobHandler(
				handler,
				rejector,
			),
			rejector,
		)
	}

	checkWritePermissionForBuild := func(handler http.Handler) http.Handler {
		return auth.CSRFValidationHandler(
			fakeCheckBuildWriteAccessHandlerFactory.HandlerFor(
				handler,
				rejector,
			),
			rejector,
		)
	}

	checkTeamAccessForWorker := func(handler http.Handler) http.Handler {
		return auth.CSRFValidationHandler(
			fakeCheckWorkerTeamAccessHandlerFactory.HandlerFor(
				handler,
				rejector,
			),
			rejector,
		)
	}

	Describe("Wrap", func() {
		var (
			inputHandlers    rata.Handlers
			expectedHandlers rata.Handlers

			wrappedHandlers rata.Handlers
		)

		BeforeEach(func() {
			inputHandlers = rata.Handlers{}

			for _, route := range atc.Routes {
				inputHandlers[route.Name] = &stupidHandler{}
			}

			expectedHandlers = rata.Handlers{
				//unauthenticated / delegating to handler
				atc.GetInfo:              unauthenticated(inputHandlers[atc.GetInfo]),
				atc.DownloadCLI:          unauthenticated(inputHandlers[atc.DownloadCLI]),
				atc.CheckResourceWebHook: unauthenticated(inputHandlers[atc.CheckResourceWebHook]),
				atc.ListAllPipelines:     unauthenticated(inputHandlers[atc.ListAllPipelines]),
				atc.ListBuilds:           unauthenticated(inputHandlers[atc.ListBuilds]),
				atc.ListPipelines:        unauthenticated(inputHandlers[atc.ListPipelines]),
				atc.ListAllJobs:          unauthenticated(inputHandlers[atc.ListAllJobs]),
				atc.ListAllResources:     unauthenticated(inputHandlers[atc.ListAllResources]),
				atc.ListTeams:            unauthenticated(inputHandlers[atc.ListTeams]),
				atc.MainJobBadge:         unauthenticated(inputHandlers[atc.MainJobBadge]),

				// authorized or public pipeline
				atc.GetBuild:       doesNotCheckIfPrivateJob(inputHandlers[atc.GetBuild]),
				atc.BuildResources: doesNotCheckIfPrivateJob(inputHandlers[atc.BuildResources]),
				atc.GetBuildPlan:   doesNotCheckIfPrivateJob(inputHandlers[atc.GetBuildPlan]),

				// authorized or public pipeline and public job
				atc.BuildEvents:         checksIfPrivateJob(inputHandlers[atc.BuildEvents]),
				atc.GetBuildPreparation: checksIfPrivateJob(inputHandlers[atc.GetBuildPreparation]),

				// resource belongs to authorized team
				atc.AbortBuild:              checkWritePermissionForBuild(inputHandlers[atc.AbortBuild]),
				atc.SendInputToBuildPlan:    checkWritePermissionForBuild(inputHandlers[atc.SendInputToBuildPlan]),
				atc.ReadOutputFromBuildPlan: checkWritePermissionForBuild(inputHandlers[atc.ReadOutputFromBuildPlan]),

				// resource belongs to authorized team
				atc.PruneWorker:              checkTeamAccessForWorker(inputHandlers[atc.PruneWorker]),
				atc.LandWorker:               checkTeamAccessForWorker(inputHandlers[atc.LandWorker]),
				atc.ReportWorkerContainers:   checkTeamAccessForWorker(inputHandlers[atc.ReportWorkerContainers]),
				atc.ReportWorkerVolumes:      checkTeamAccessForWorker(inputHandlers[atc.ReportWorkerVolumes]),
				atc.RetireWorker:             checkTeamAccessForWorker(inputHandlers[atc.RetireWorker]),
				atc.ListDestroyingContainers: checkTeamAccessForWorker(inputHandlers[atc.ListDestroyingContainers]),
				atc.ListDestroyingVolumes:    checkTeamAccessForWorker(inputHandlers[atc.ListDestroyingVolumes]),

				// belongs to public pipeline or authorized
				atc.GetPipeline:                   openForPublicPipelineOrAuthorized(inputHandlers[atc.GetPipeline]),
				atc.GetJobBuild:                   openForPublicPipelineOrAuthorized(inputHandlers[atc.GetJobBuild]),
				atc.PipelineBadge:                 openForPublicPipelineOrAuthorized(inputHandlers[atc.PipelineBadge]),
				atc.JobBadge:                      openForPublicPipelineOrAuthorized(inputHandlers[atc.JobBadge]),
				atc.ListJobs:                      openForPublicPipelineOrAuthorized(inputHandlers[atc.ListJobs]),
				atc.GetJob:                        openForPublicPipelineOrAuthorized(inputHandlers[atc.GetJob]),
				atc.ListJobBuilds:                 openForPublicPipelineOrAuthorized(inputHandlers[atc.ListJobBuilds]),
				atc.ListPipelineBuilds:            openForPublicPipelineOrAuthorized(inputHandlers[atc.ListPipelineBuilds]),
				atc.GetResource:                   openForPublicPipelineOrAuthorized(inputHandlers[atc.GetResource]),
				atc.ListBuildsWithVersionAsInput:  openForPublicPipelineOrAuthorized(inputHandlers[atc.ListBuildsWithVersionAsInput]),
				atc.ListBuildsWithVersionAsOutput: openForPublicPipelineOrAuthorized(inputHandlers[atc.ListBuildsWithVersionAsOutput]),
				atc.ListResources:                 openForPublicPipelineOrAuthorized(inputHandlers[atc.ListResources]),
				atc.ListResourceTypes:             openForPublicPipelineOrAuthorized(inputHandlers[atc.ListResourceTypes]),
				atc.ListResourceVersions:          openForPublicPipelineOrAuthorized(inputHandlers[atc.ListResourceVersions]),
				atc.GetResourceCausality:          openForPublicPipelineOrAuthorized(inputHandlers[atc.GetResourceCausality]),
				atc.GetResourceVersion:            openForPublicPipelineOrAuthorized(inputHandlers[atc.GetResourceVersion]),

				// authenticated
				atc.CreateBuild:     authenticated(inputHandlers[atc.CreateBuild]),
				atc.GetContainer:    authenticated(inputHandlers[atc.GetContainer]),
				atc.HijackContainer: authenticated(inputHandlers[atc.HijackContainer]),
				atc.ListContainers:  authenticated(inputHandlers[atc.ListContainers]),
				atc.ListVolumes:     authenticated(inputHandlers[atc.ListVolumes]),
				atc.ListTeamBuilds:  authenticated(inputHandlers[atc.ListTeamBuilds]),
				atc.ListWorkers:     authenticated(inputHandlers[atc.ListWorkers]),
				atc.RegisterWorker:  authenticated(inputHandlers[atc.RegisterWorker]),
				atc.HeartbeatWorker: authenticated(inputHandlers[atc.HeartbeatWorker]),
				atc.DeleteWorker:    authenticated(inputHandlers[atc.DeleteWorker]),
				atc.SetTeam:         authenticated(inputHandlers[atc.SetTeam]),
				atc.RenameTeam:      authenticated(inputHandlers[atc.RenameTeam]),
				atc.DestroyTeam:     authenticated(inputHandlers[atc.DestroyTeam]),

				// authenticated and is admin
				atc.GetLogLevel:  authenticatedAndAdmin(inputHandlers[atc.GetLogLevel]),
				atc.SetLogLevel:  authenticatedAndAdmin(inputHandlers[atc.SetLogLevel]),
				atc.GetInfoCreds: authenticatedAndAdmin(inputHandlers[atc.GetInfoCreds]),

				// authorized (requested team matches resource team)
				atc.CheckResource:           authorized(inputHandlers[atc.CheckResource]),
				atc.CheckResourceType:       authorized(inputHandlers[atc.CheckResourceType]),
				atc.CreateJobBuild:          authorized(inputHandlers[atc.CreateJobBuild]),
				atc.DeletePipeline:          authorized(inputHandlers[atc.DeletePipeline]),
				atc.DisableResourceVersion:  authorized(inputHandlers[atc.DisableResourceVersion]),
				atc.EnableResourceVersion:   authorized(inputHandlers[atc.EnableResourceVersion]),
				atc.PinResourceVersion:      authorized(inputHandlers[atc.PinResourceVersion]),
				atc.UnpinResource:           authorized(inputHandlers[atc.UnpinResource]),
				atc.SetPinCommentOnResource: authorized(inputHandlers[atc.SetPinCommentOnResource]),
				atc.GetConfig:               authorized(inputHandlers[atc.GetConfig]),
				atc.GetVersionsDB:           authorized(inputHandlers[atc.GetVersionsDB]),
				atc.ListJobInputs:           authorized(inputHandlers[atc.ListJobInputs]),
				atc.OrderPipelines:          authorized(inputHandlers[atc.OrderPipelines]),
				atc.PauseJob:                authorized(inputHandlers[atc.PauseJob]),
				atc.PausePipeline:           authorized(inputHandlers[atc.PausePipeline]),
				atc.RenamePipeline:          authorized(inputHandlers[atc.RenamePipeline]),
				atc.SaveConfig:              authorized(inputHandlers[atc.SaveConfig]),
				atc.UnpauseJob:              authorized(inputHandlers[atc.UnpauseJob]),
				atc.UnpausePipeline:         authorized(inputHandlers[atc.UnpausePipeline]),
				atc.ExposePipeline:          authorized(inputHandlers[atc.ExposePipeline]),
				atc.HidePipeline:            authorized(inputHandlers[atc.HidePipeline]),
				atc.CreatePipelineBuild:     authorized(inputHandlers[atc.CreatePipelineBuild]),
				atc.ClearTaskCache:          authorized(inputHandlers[atc.ClearTaskCache]),
			}
		})

		JustBeforeEach(func() {
			wrappedHandlers = wrappa.NewAPIAuthWrappa(
				fakeCheckPipelineAccessHandlerFactory,
				fakeCheckBuildReadAccessHandlerFactory,
				fakeCheckBuildWriteAccessHandlerFactory,
				fakeCheckWorkerTeamAccessHandlerFactory,
			).Wrap(inputHandlers)

		})

		It("validates sensitive routes, and noop validates public routes", func() {
			for name, _ := range inputHandlers {
				Expect(wrappedHandlers[name]).To(BeIdenticalTo(expectedHandlers[name]))
			}
		})
	})
})
<|endoftext|>


<commit_before>/*
Statsd client

Supports counting, sampling, timing, gauges, sets and multi-metrics packet.

Using the client to increment a counter:

	client, err := statsd.Dial("127.0.0.1:8125")
	if err != nil {
		// handle error
	}
	defer client.Close()
	err = client.Increment("buckets", 1, 1)

*/
package statsd

import (
	"bufio"
	"fmt"
	"math/rand"
	"net"
	"sync"
	"time"
)

const (
	defaultBufSize = 512
)

// Client is statsd client representing a connection to a statsd server.
type Client struct {
	conn net.Conn
	buf  *bufio.Writer
	m    sync.Mutex
}

func millisecond(d time.Duration) int {
	return int(d.Seconds() * 1000)
}

// Dial connects to the given address on the given network using net.Dial and then returns a new Client for the connection.
func Dial(addr string) (*Client, error) {
	conn, err := net.Dial("udp", addr)
	if err != nil {
		return nil, err
	}
	return newClient(conn, 0), nil
}

// DialTimeout acts like Dial but takes a timeout. The timeout includes name resolution, if required.
func DialTimeout(addr string, timeout time.Duration) (*Client, error) {
	conn, err := net.DialTimeout("udp", addr, timeout)
	if err != nil {
		return nil, err
	}
	return newClient(conn, 0), nil
}

// DialSize acts like Dial but takes a packet size.
// By default, the packet size is 512, see https://github.com/etsy/statsd/blob/master/docs/metric_types.md#multi-metric-packets for guidelines.
func DialSize(addr string, size int) (*Client, error) {
	conn, err := net.Dial("udp", addr)
	if err != nil {
		return nil, err
	}
	return newClient(conn, size), nil
}

func newClient(conn net.Conn, size int) *Client {
	if size <= 0 {
		size = defaultBufSize
	}
	return &Client{
		conn: conn,
		buf:  bufio.NewWriterSize(conn, size),
	}
}

// Increment increments the counter for the given bucket.
func (c *Client) Increment(stat string, count int, rate float64) error {
	return c.send(stat, rate, "%d|c", count)
}

// Increment increments the counter for the given bucket by 1 at a rate of 1.
func (c *Client) Incr(stat string) error {
	return c.Increment(stat, 1, 1)
}

// Decrement decrements the counter for the given bucket.
func (c *Client) Decrement(stat string, count int, rate float64) error {
	return c.Increment(stat, -count, rate)
}

// Decrement decrements the counter for the given bucket by 1 at a rate of 1.
func (c *Client) Decr(stat string) error {
	return c.Increment(stat, -1, 1)
}

// Duration records time spent for the given bucket with time.Duration.
func (c *Client) Duration(stat string, duration time.Duration, rate float64) error {
	return c.send(stat, rate, "%d|ms", millisecond(duration))
}

// Timing records time spent for the given bucket in milliseconds.
func (c *Client) Timing(stat string, delta int, rate float64) error {
	return c.send(stat, rate, "%d|ms", delta)
}

// Time calculates time spent in given function and send it.
func (c *Client) Time(stat string, rate float64, f func()) error {
	ts := time.Now()
	f()
	return c.Duration(stat, time.Since(ts), rate)
}

// Gauge records arbitrary values for the given bucket.
func (c *Client) Gauge(stat string, value int, rate float64) error {
	return c.send(stat, rate, "%d|g", value)
}

// IncrementGauge increments the value of the gauge.
func (c *Client) IncrementGauge(stat string, value int, rate float64) error {
	return c.send(stat, rate, "+%d|g", value)
}

// DecrementGauge decrements the value of the gauge.
func (c *Client) DecrementGauge(stat string, value int, rate float64) error {
	return c.send(stat, rate, "-%d|g", value)
}

// Unique records unique occurences of events.
func (c *Client) Unique(stat string, value int, rate float64) error {
	return c.send(stat, rate, "%d|s", value)
}

// Flush flushes writes any buffered data to the network.
func (c *Client) Flush() error {
	return c.buf.Flush()
}

// Close closes the connection.
func (c *Client) Close() error {
	if err := c.Flush(); err != nil {
		return err
	}
	c.buf = nil
	return c.conn.Close()
}

func (c *Client) send(stat string, rate float64, format string, args ...interface{}) error {
	if rate < 1 {
		if rand.Float64() < rate {
			format = fmt.Sprintf("%s|@%g", format, rate)
		} else {
			return nil
		}
	}

	format = fmt.Sprintf("%s:%s", stat, format)

	c.m.Lock()
	defer c.m.Unlock()

	// Flush data if we have reach the buffer limit
	if c.buf.Available() < len(format) {
		if err := c.Flush(); err != nil {
			return nil
		}
	}

	// Buffer is not empty, start filling it
	if c.buf.Buffered() > 0 {
		format = fmt.Sprintf("\n%s", format)
	}

	_, err := fmt.Fprintf(c.buf, format, args...)
	return err
}
<commit_msg>add debug(). Closes #3<commit_after>package statsd

import (
	"bufio"
	"fmt"
	. "github.com/visionmedia/go-debug"
	"math/rand"
	"net"
	"sync"
	"time"
)

var debug = Debug("statsd")

const defaultBufSize = 512

// Client is statsd client representing a connection to a statsd server.
type Client struct {
	conn net.Conn
	buf  *bufio.Writer
	m    sync.Mutex
}

func millisecond(d time.Duration) int {
	return int(d.Seconds() * 1000)
}

// Dial connects to the given address on the given network using net.Dial and then returns a new Client for the connection.
func Dial(addr string) (*Client, error) {
	conn, err := net.Dial("udp", addr)
	if err != nil {
		return nil, err
	}
	return newClient(conn, 0), nil
}

// DialTimeout acts like Dial but takes a timeout. The timeout includes name resolution, if required.
func DialTimeout(addr string, timeout time.Duration) (*Client, error) {
	conn, err := net.DialTimeout("udp", addr, timeout)
	if err != nil {
		return nil, err
	}
	return newClient(conn, 0), nil
}

// DialSize acts like Dial but takes a packet size.
// By default, the packet size is 512, see https://github.com/etsy/statsd/blob/master/docs/metric_types.md#multi-metric-packets for guidelines.
func DialSize(addr string, size int) (*Client, error) {
	conn, err := net.Dial("udp", addr)
	if err != nil {
		return nil, err
	}
	return newClient(conn, size), nil
}

func newClient(conn net.Conn, size int) *Client {
	if size <= 0 {
		size = defaultBufSize
	}
	return &Client{
		conn: conn,
		buf:  bufio.NewWriterSize(conn, size),
	}
}

// Increment increments the counter for the given bucket.
func (c *Client) Increment(stat string, count int, rate float64) error {
	return c.send(stat, rate, "%d|c", count)
}

// Increment increments the counter for the given bucket by 1 at a rate of 1.
func (c *Client) Incr(stat string) error {
	return c.Increment(stat, 1, 1)
}

// Decrement decrements the counter for the given bucket.
func (c *Client) Decrement(stat string, count int, rate float64) error {
	return c.Increment(stat, -count, rate)
}

// Decrement decrements the counter for the given bucket by 1 at a rate of 1.
func (c *Client) Decr(stat string) error {
	return c.Increment(stat, -1, 1)
}

// Duration records time spent for the given bucket with time.Duration.
func (c *Client) Duration(stat string, duration time.Duration, rate float64) error {
	return c.send(stat, rate, "%d|ms", millisecond(duration))
}

// Timing records time spent for the given bucket in milliseconds.
func (c *Client) Timing(stat string, delta int, rate float64) error {
	return c.send(stat, rate, "%d|ms", delta)
}

// Time calculates time spent in given function and send it.
func (c *Client) Time(stat string, rate float64, f func()) error {
	ts := time.Now()
	f()
	return c.Duration(stat, time.Since(ts), rate)
}

// Gauge records arbitrary values for the given bucket.
func (c *Client) Gauge(stat string, value int, rate float64) error {
	return c.send(stat, rate, "%d|g", value)
}

// IncrementGauge increments the value of the gauge.
func (c *Client) IncrementGauge(stat string, value int, rate float64) error {
	return c.send(stat, rate, "+%d|g", value)
}

// DecrementGauge decrements the value of the gauge.
func (c *Client) DecrementGauge(stat string, value int, rate float64) error {
	return c.send(stat, rate, "-%d|g", value)
}

// Unique records unique occurences of events.
func (c *Client) Unique(stat string, value int, rate float64) error {
	return c.send(stat, rate, "%d|s", value)
}

// Flush flushes writes any buffered data to the network.
func (c *Client) Flush() error {
	return c.buf.Flush()
}

// Close closes the connection.
func (c *Client) Close() error {
	if err := c.Flush(); err != nil {
		return err
	}
	c.buf = nil
	return c.conn.Close()
}

func (c *Client) send(stat string, rate float64, format string, args ...interface{}) error {
	if rate < 1 {
		if rand.Float64() < rate {
			format = fmt.Sprintf("%s|@%g", format, rate)
		} else {
			return nil
		}
	}

	format = fmt.Sprintf("%s:%s", stat, format)
	debug(format, args...)

	c.m.Lock()
	defer c.m.Unlock()

	// Flush data if we have reach the buffer limit
	if c.buf.Available() < len(format) {
		if err := c.Flush(); err != nil {
			return nil
		}
	}

	// Buffer is not empty, start filling it
	if c.buf.Buffered() > 0 {
		format = fmt.Sprintf("\n%s", format)
	}

	_, err := fmt.Fprintf(c.buf, format, args...)
	return err
}
<|endoftext|>


<commit_before>package d2s

// status struct will represent the characters in game status.
type status byte

type readableStatus struct {
	Expansion bool `json:"expansion"`
	Died      bool `json:"died"`
	Hardcore  bool `json:"hardcore"`
}

// Readable will return a readable format for the status byte.
func (s status) Readable() readableStatus {
	return readableStatus{
		Expansion: ((s >> 5) & 1) > 0,
		Died:      ((s >> 3) & 1) > 0,
		Hardcore:  ((s >> 2) & 1) > 0,
	}
}
<commit_msg>Added ladder bit, the parser will now recognize if a character is ladder or not.<commit_after>package d2s

// status struct will represent the characters in game status.
type status byte

type readableStatus struct {
	Expansion bool `json:"expansion"`
	Died      bool `json:"died"`
	Hardcore  bool `json:"hardcore"`
	Ladder    bool `json:"ladder"`
}

// Readable will return a readable format for the status byte.
func (s status) Readable() readableStatus {
	return readableStatus{
		Expansion: ((s >> 5) & 1) > 0,
		Died:      ((s >> 3) & 1) > 0,
		Hardcore:  ((s >> 2) & 1) > 0,
		Ladder:    ((s >> 6) & 1) > 0,
	}
}
<|endoftext|>


<commit_before>package spdy

import (
// "crypto/tls"
//   "net"
//   "sync"
)

type stream struct {
  conn           *connection
  streamID       uint32
  state          StreamState
  priority       uint8
  certificates   [][]byte
  headers        *Headers
  settings       []*Setting
  credentials    []Certificate
  unidirectional bool
}

type StreamState uint8

const (
  CLOSED StreamState = iota
  HALF_CLOSED_HERE
  HALF_CLOSED_THERE
  OPEN
)

const MAX_PRIORITY = 7
<commit_msg>Added stream request<commit_after>package spdy

import (
// "crypto/tls"
//   "net"
//   "sync"
)

type stream struct {
  conn           *connection
  streamID       uint32
  state          StreamState
  priority       uint8
	request        *Request
  certificates   [][]byte
  headers        *Headers
  settings       []*Setting
  credentials    []Certificate
  unidirectional bool
}

type StreamState uint8

const (
  CLOSED StreamState = iota
  HALF_CLOSED_HERE
  HALF_CLOSED_THERE
  OPEN
)

const MAX_PRIORITY = 7
<|endoftext|>