<commit_before>package peerreader

import (
	"bufio"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"time"

	"github.com/cenkalti/rain/internal/bufferpool"
	"github.com/cenkalti/rain/internal/logger"
	"github.com/cenkalti/rain/internal/peerprotocol"
	"github.com/cenkalti/rain/internal/piece"
)

const (
	// maxBlockSize is the max size of block data that we accept from peers.
	maxBlockSize = 32 * 1024
	// time to wait for a message. peer must send keep-alive messages to keep connection alive.
	readTimeout = 2 * time.Minute
)

var blockPool = bufferpool.New(piece.BlockSize)

type PeerReader struct {
	conn         net.Conn
	buf          *bufio.Reader
	log          logger.Logger
	pieceTimeout time.Duration
	messages     chan interface{}
	stopC        chan struct{}
	doneC        chan struct{}
}

func New(conn net.Conn, l logger.Logger, pieceTimeout time.Duration, bufferSize int) *PeerReader {
	return &PeerReader{
		conn:         conn,
		buf:          bufio.NewReaderSize(conn, bufferSize),
		log:          l,
		pieceTimeout: pieceTimeout,
		messages:     make(chan interface{}),
		stopC:        make(chan struct{}),
		doneC:        make(chan struct{}),
	}
}

func (p *PeerReader) Messages() <-chan interface{} {
	return p.messages
}

func (p *PeerReader) Stop() {
	close(p.stopC)
}

func (p *PeerReader) Done() chan struct{} {
	return p.doneC
}

func (p *PeerReader) Run() {
	defer close(p.doneC)

	var err error
	defer func() {
		if err == nil {
			return
		} else if err == io.EOF { // peer closed the connection
			return
		} else if err == io.ErrUnexpectedEOF {
			return
		} else if _, ok := err.(*net.OpError); ok {
			return
		}
		select {
		case <-p.stopC: // don't log error if peer is stopped
		default:
			p.log.Error(err)
		}
	}()

	first := true
	for {
		err = p.conn.SetReadDeadline(time.Now().Add(readTimeout))
		if err != nil {
			return
		}

		var length uint32
		// p.log.Debug("Reading message...")
		err = binary.Read(p.buf, binary.BigEndian, &length)
		if err != nil {
			return
		}
		// p.log.Debugf("Received message of length: %d", length)

		if length == 0 { // keep-alive message
			p.log.Debug("Received message of type \"keep alive\"")
			continue
		}

		var id peerprotocol.MessageID
		err = binary.Read(p.buf, binary.BigEndian, &id)
		if err != nil {
			return
		}
		length--

		// p.log.Debugf("Received message of type: %q", id)

		var msg interface{}

		switch id {
		case peerprotocol.Choke:
			msg = peerprotocol.ChokeMessage{}
		case peerprotocol.Unchoke:
			msg = peerprotocol.UnchokeMessage{}
		case peerprotocol.Interested:
			msg = peerprotocol.InterestedMessage{}
		case peerprotocol.NotInterested:
			msg = peerprotocol.NotInterestedMessage{}
		case peerprotocol.Have:
			var hm peerprotocol.HaveMessage
			err = binary.Read(p.buf, binary.BigEndian, &hm)
			if err != nil {
				return
			}
			msg = hm
		case peerprotocol.Bitfield:
			if !first {
				err = errors.New("bitfield can only be sent after handshake")
				return
			}
			var bm peerprotocol.BitfieldMessage
			bm.Data = make([]byte, length)
			_, err = io.ReadFull(p.buf, bm.Data)
			if err != nil {
				return
			}
			msg = bm
		case peerprotocol.Request:
			var rm peerprotocol.RequestMessage
			err = binary.Read(p.buf, binary.BigEndian, &rm)
			if err != nil {
				return
			}
			// p.log.Debugf("Received Request: %+v", rm)

			if rm.Length > maxBlockSize {
				err = fmt.Errorf("received a request with block size larger than allowed (%d > %d)", rm.Length, maxBlockSize)
				return
			}
			msg = rm
		case peerprotocol.Reject:
			var rm peerprotocol.RejectMessage
			err = binary.Read(p.buf, binary.BigEndian, &rm)
			if err != nil {
				return
			}
			p.log.Debugf("Received Reject: %+v", rm)
			msg = rm
		case peerprotocol.Cancel:
			var cm peerprotocol.CancelMessage
			err = binary.Read(p.buf, binary.BigEndian, &cm)
			if err != nil {
				return
			}
			if cm.Length > maxBlockSize {
				err = errors.New("received a cancel with block size larger than allowed")
				return
			}
			msg = cm
		case peerprotocol.Piece:
			var pm peerprotocol.PieceMessage
			err = binary.Read(p.buf, binary.BigEndian, &pm)
			if err != nil {
				return
			}
			var m int
			buf := blockPool.Get(int(length - 8))
			for {
				err = p.conn.SetReadDeadline(time.Now().Add(p.pieceTimeout))
				if err != nil {
					return
				}
				n, rerr := io.ReadFull(p.buf, buf.Data[m:])
				if rerr != nil {
					if nerr, ok := rerr.(net.Error); ok && nerr.Timeout() {
						// Peer didn't send the full block in allowed time.
						if n == 0 {
							// Disconnect if no bytes received.
							return
						}
						// Some bytes received, peer appears to be slow, keep receiving the rest.
						m += n
						continue
					}
					return
				}
				// Received full block.
				break
			}
			msg = Piece{PieceMessage: pm, Buffer: buf}
		case peerprotocol.HaveAll:
			if !first {
				err = errors.New("have_all can only be sent after handshake")
				return
			}
			msg = peerprotocol.HaveAllMessage{}
		case peerprotocol.HaveNone:
			if !first {
				err = errors.New("have_none can only be sent after handshake")
				return
			}
			msg = peerprotocol.HaveNoneMessage{}
		case peerprotocol.AllowedFast:
			var am peerprotocol.AllowedFastMessage
			err = binary.Read(p.buf, binary.BigEndian, &am)
			if err != nil {
				return
			}
			msg = am
		case peerprotocol.Extension:
			buf := make([]byte, length)
			_, err = io.ReadFull(p.buf, buf)
			if err != nil {
				return
			}
			var em peerprotocol.ExtensionMessage
			err = em.UnmarshalBinary(buf)
			if err != nil {
				return
			}
			msg = em.Payload
		default:
			p.log.Debugf("unhandled message type: %s", id)
			p.log.Debugln("Discarding", length, "bytes...")
			_, err = io.CopyN(ioutil.Discard, p.buf, int64(length))
			if err != nil {
				return
			}
			continue
		}
		if msg == nil {
			panic("msg unset")
		}
		// Only message types defined in BEP 3 are counted.
		if id < 9 {
			first = false
		}
		select {
		case p.messages <- msg:
		case <-p.stopC:
			return
		}
	}
}
<commit_msg>reduce max block size<commit_after>package peerreader

import (
	"bufio"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"time"

	"github.com/cenkalti/rain/internal/bufferpool"
	"github.com/cenkalti/rain/internal/logger"
	"github.com/cenkalti/rain/internal/peerprotocol"
	"github.com/cenkalti/rain/internal/piece"
)

const (
	maxBlockSize = 16 * 1024
	// time to wait for a message. peer must send keep-alive messages to keep connection alive.
	readTimeout = 2 * time.Minute
)

var blockPool = bufferpool.New(piece.BlockSize)

type PeerReader struct {
	conn         net.Conn
	buf          *bufio.Reader
	log          logger.Logger
	pieceTimeout time.Duration
	messages     chan interface{}
	stopC        chan struct{}
	doneC        chan struct{}
}

func New(conn net.Conn, l logger.Logger, pieceTimeout time.Duration, bufferSize int) *PeerReader {
	return &PeerReader{
		conn:         conn,
		buf:          bufio.NewReaderSize(conn, bufferSize),
		log:          l,
		pieceTimeout: pieceTimeout,
		messages:     make(chan interface{}),
		stopC:        make(chan struct{}),
		doneC:        make(chan struct{}),
	}
}

func (p *PeerReader) Messages() <-chan interface{} {
	return p.messages
}

func (p *PeerReader) Stop() {
	close(p.stopC)
}

func (p *PeerReader) Done() chan struct{} {
	return p.doneC
}

func (p *PeerReader) Run() {
	defer close(p.doneC)

	var err error
	defer func() {
		if err == nil {
			return
		} else if err == io.EOF { // peer closed the connection
			return
		} else if err == io.ErrUnexpectedEOF {
			return
		} else if _, ok := err.(*net.OpError); ok {
			return
		}
		select {
		case <-p.stopC: // don't log error if peer is stopped
		default:
			p.log.Error(err)
		}
	}()

	first := true
	for {
		err = p.conn.SetReadDeadline(time.Now().Add(readTimeout))
		if err != nil {
			return
		}

		var length uint32
		// p.log.Debug("Reading message...")
		err = binary.Read(p.buf, binary.BigEndian, &length)
		if err != nil {
			return
		}
		// p.log.Debugf("Received message of length: %d", length)

		if length == 0 { // keep-alive message
			p.log.Debug("Received message of type \"keep alive\"")
			continue
		}

		var id peerprotocol.MessageID
		err = binary.Read(p.buf, binary.BigEndian, &id)
		if err != nil {
			return
		}
		length--

		// p.log.Debugf("Received message of type: %q", id)

		var msg interface{}

		switch id {
		case peerprotocol.Choke:
			msg = peerprotocol.ChokeMessage{}
		case peerprotocol.Unchoke:
			msg = peerprotocol.UnchokeMessage{}
		case peerprotocol.Interested:
			msg = peerprotocol.InterestedMessage{}
		case peerprotocol.NotInterested:
			msg = peerprotocol.NotInterestedMessage{}
		case peerprotocol.Have:
			var hm peerprotocol.HaveMessage
			err = binary.Read(p.buf, binary.BigEndian, &hm)
			if err != nil {
				return
			}
			msg = hm
		case peerprotocol.Bitfield:
			if !first {
				err = errors.New("bitfield can only be sent after handshake")
				return
			}
			var bm peerprotocol.BitfieldMessage
			bm.Data = make([]byte, length)
			_, err = io.ReadFull(p.buf, bm.Data)
			if err != nil {
				return
			}
			msg = bm
		case peerprotocol.Request:
			var rm peerprotocol.RequestMessage
			err = binary.Read(p.buf, binary.BigEndian, &rm)
			if err != nil {
				return
			}
			// p.log.Debugf("Received Request: %+v", rm)

			if rm.Length > maxBlockSize {
				err = fmt.Errorf("received a request with block size larger than allowed (%d > %d)", rm.Length, maxBlockSize)
				return
			}
			msg = rm
		case peerprotocol.Reject:
			var rm peerprotocol.RejectMessage
			err = binary.Read(p.buf, binary.BigEndian, &rm)
			if err != nil {
				return
			}
			p.log.Debugf("Received Reject: %+v", rm)
			msg = rm
		case peerprotocol.Cancel:
			var cm peerprotocol.CancelMessage
			err = binary.Read(p.buf, binary.BigEndian, &cm)
			if err != nil {
				return
			}
			if cm.Length > maxBlockSize {
				err = fmt.Errorf("received a cancel with block size larger than allowed (%d > %d)", cm.Length, maxBlockSize)
				return
			}
			msg = cm
		case peerprotocol.Piece:
			var pm peerprotocol.PieceMessage
			err = binary.Read(p.buf, binary.BigEndian, &pm)
			if err != nil {
				return
			}
			var m int
			buf := blockPool.Get(int(length - 8))
			for {
				err = p.conn.SetReadDeadline(time.Now().Add(p.pieceTimeout))
				if err != nil {
					return
				}
				n, rerr := io.ReadFull(p.buf, buf.Data[m:])
				if rerr != nil {
					if nerr, ok := rerr.(net.Error); ok && nerr.Timeout() {
						// Peer didn't send the full block in allowed time.
						if n == 0 {
							// Disconnect if no bytes received.
							return
						}
						// Some bytes received, peer appears to be slow, keep receiving the rest.
						m += n
						continue
					}
					return
				}
				// Received full block.
				break
			}
			msg = Piece{PieceMessage: pm, Buffer: buf}
		case peerprotocol.HaveAll:
			if !first {
				err = errors.New("have_all can only be sent after handshake")
				return
			}
			msg = peerprotocol.HaveAllMessage{}
		case peerprotocol.HaveNone:
			if !first {
				err = errors.New("have_none can only be sent after handshake")
				return
			}
			msg = peerprotocol.HaveNoneMessage{}
		case peerprotocol.AllowedFast:
			var am peerprotocol.AllowedFastMessage
			err = binary.Read(p.buf, binary.BigEndian, &am)
			if err != nil {
				return
			}
			msg = am
		case peerprotocol.Extension:
			buf := make([]byte, length)
			_, err = io.ReadFull(p.buf, buf)
			if err != nil {
				return
			}
			var em peerprotocol.ExtensionMessage
			err = em.UnmarshalBinary(buf)
			if err != nil {
				return
			}
			msg = em.Payload
		default:
			p.log.Debugf("unhandled message type: %s", id)
			p.log.Debugln("Discarding", length, "bytes...")
			_, err = io.CopyN(ioutil.Discard, p.buf, int64(length))
			if err != nil {
				return
			}
			continue
		}
		if msg == nil {
			panic("msg unset")
		}
		// Only message types defined in BEP 3 are counted.
		if id < 9 {
			first = false
		}
		select {
		case p.messages <- msg:
		case <-p.stopC:
			return
		}
	}
}
<|endoftext|>


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

package build

// TODO(adg): test authentication

import (
	"appengine"
	"appengine/datastore"
	"bytes"
	"fmt"
	"http"
	"http/httptest"
	"io"
	"json"
	"os"
	"strings"
	"url"
)

func init() {
	http.HandleFunc("/buildtest", testHandler)
}

var testEntityKinds = []string{
	"Package",
	"Commit",
	"Result",
	"Log",
}

const testPkg = "code.google.com/p/go.more"

var testPackage = &Package{Name: "Test", Path: testPkg}

var testPackages = []*Package{
	{Name: "Go", Path: ""},
	testPackage,
}

var testRequests = []struct {
	path string
	vals url.Values
	req  interface{}
	res  interface{}
}{
	// Packages
	{"/packages", nil, nil, []*Package{testPackage}},

	// Go repo
	{"/commit", nil, &Commit{Hash: "0001", ParentHash: "0000"}, nil},
	{"/commit", nil, &Commit{Hash: "0002", ParentHash: "0001"}, nil},
	{"/commit", nil, &Commit{Hash: "0003", ParentHash: "0002"}, nil},
	{"/todo", url.Values{"builder": {"linux-386"}}, nil, "0003"},
	{"/todo", url.Values{"builder": {"linux-amd64"}}, nil, "0003"},
	{"/result", nil, &Result{Builder: "linux-386", Hash: "0001", OK: true}, nil},
	{"/todo", url.Values{"builder": {"linux-386"}}, nil, "0003"},
	{"/result", nil, &Result{Builder: "linux-386", Hash: "0002", OK: true}, nil},
	{"/todo", url.Values{"builder": {"linux-386"}}, nil, "0003"},

	// multiple builders
	{"/todo", url.Values{"builder": {"linux-amd64"}}, nil, "0003"},
	{"/result", nil, &Result{Builder: "linux-amd64", Hash: "0003", OK: true}, nil},
	{"/todo", url.Values{"builder": {"linux-386"}}, nil, "0003"},
	{"/todo", url.Values{"builder": {"linux-amd64"}}, nil, "0002"},

	// branches
	{"/commit", nil, &Commit{Hash: "0004", ParentHash: "0003"}, nil},
	{"/commit", nil, &Commit{Hash: "0005", ParentHash: "0002"}, nil},
	{"/todo", url.Values{"builder": {"linux-386"}}, nil, "0005"},
	{"/result", nil, &Result{Builder: "linux-386", Hash: "0005", OK: true}, nil},
	{"/todo", url.Values{"builder": {"linux-386"}}, nil, "0004"},
	{"/result", nil, &Result{Builder: "linux-386", Hash: "0004", OK: true}, nil},
	{"/todo", url.Values{"builder": {"linux-386"}}, nil, "0003"},

	// logs
	{"/result", nil, &Result{Builder: "linux-386", Hash: "0003", OK: false, Log: []byte("test")}, nil},
	{"/log/a94a8fe5ccb19ba61c4c0873d391e987982fbbd3", nil, nil, "test"},
	{"/todo", url.Values{"builder": {"linux-386"}}, nil, nil},

	// non-Go repos
	{"/commit", nil, &Commit{PackagePath: testPkg, Hash: "1001", ParentHash: "1000"}, nil},
	{"/commit", nil, &Commit{PackagePath: testPkg, Hash: "1002", ParentHash: "1001"}, nil},
	{"/commit", nil, &Commit{PackagePath: testPkg, Hash: "1003", ParentHash: "1002"}, nil},
	{"/todo", url.Values{"builder": {"linux-386"}, "packagePath": {testPkg}, "goHash": {"0001"}}, nil, "1003"},
	{"/result", nil, &Result{PackagePath: testPkg, Builder: "linux-386", Hash: "1003", GoHash: "0001", OK: true}, nil},
	{"/todo", url.Values{"builder": {"linux-386"}, "packagePath": {testPkg}, "goHash": {"0001"}}, nil, "1002"},
	{"/result", nil, &Result{PackagePath: testPkg, Builder: "linux-386", Hash: "1002", GoHash: "0001", OK: true}, nil},
	{"/todo", url.Values{"builder": {"linux-386"}, "packagePath": {testPkg}, "goHash": {"0001"}}, nil, "1001"},
	{"/result", nil, &Result{PackagePath: testPkg, Builder: "linux-386", Hash: "1001", GoHash: "0001", OK: true}, nil},
	{"/todo", url.Values{"builder": {"linux-386"}, "packagePath": {testPkg}, "goHash": {"0001"}}, nil, nil},
	{"/todo", url.Values{"builder": {"linux-386"}, "packagePath": {testPkg}, "goHash": {"0002"}}, nil, "1003"},
}

func testHandler(w http.ResponseWriter, r *http.Request) {
	if !appengine.IsDevAppServer() {
		fmt.Fprint(w, "These tests must be run under the dev_appserver.")
		return
	}
	c := appengine.NewContext(r)
	if err := nukeEntities(c, testEntityKinds); err != nil {
		logErr(w, r, err)
		return
	}

	for _, p := range testPackages {
		if _, err := datastore.Put(c, p.Key(c), p); err != nil {
			logErr(w, r, err)
			return
		}
	}

	for i, t := range testRequests {
		errorf := func(format string, args ...interface{}) {
			fmt.Fprintf(w, "%d %s: ", i, t.path)
			fmt.Fprintf(w, format, args...)
			fmt.Fprintln(w)
		}
		var body io.ReadWriter
		if t.req != nil {
			body = new(bytes.Buffer)
			json.NewEncoder(body).Encode(t.req)
		}
		url := "http://" + appengine.DefaultVersionHostname(c) + t.path
		if t.vals != nil {
			url += "?" + t.vals.Encode()
		}
		req, err := http.NewRequest("POST", url, body)
		if err != nil {
			logErr(w, r, err)
			return
		}
		if t.req != nil {
			req.Method = "POST"
		}
		req.Header = r.Header
		rec := httptest.NewRecorder()
		http.DefaultServeMux.ServeHTTP(rec, req)
		if rec.Code != 0 && rec.Code != 200 {
			errorf(rec.Body.String())
			return
		}
		resp := new(dashResponse)
		if strings.HasPrefix(t.path, "/log/") {
			resp.Response = rec.Body.String()
		} else {
			err := json.NewDecoder(rec.Body).Decode(resp)
			if err != nil {
				errorf("decoding response: %v", err)
				return
			}
		}
		if e, ok := t.res.(string); ok {
			g, ok := resp.Response.(string)
			if !ok {
				errorf("Response not string: %T", resp.Response)
				return
			}
			if g != e {
				errorf("response mismatch: got %q want %q", g, e)
				return
			}
		}
		if t.res == nil && resp.Response != nil {
			errorf("response mismatch: got %q expected <nil>",
				resp.Response)
			return
		}
	}
	fmt.Fprint(w, "PASS")
}

func nukeEntities(c appengine.Context, kinds []string) os.Error {
	if !appengine.IsDevAppServer() {
		return os.NewError("can't nuke production data")
	}
	var keys []*datastore.Key
	for _, kind := range kinds {
		q := datastore.NewQuery(kind).KeysOnly()
		for t := q.Run(c); ; {
			k, err := t.Next(nil)
			if err == datastore.Done {
				break
			}
			if err != nil {
				return err
			}
			keys = append(keys, k)
		}
	}
	return datastore.DeleteMulti(c, keys)
}
<commit_msg>misc/dashboard/app: revert gofix of app engine file<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package build

// TODO(adg): test authentication

import (
	"appengine"
	"appengine/datastore"
	"bytes"
	"fmt"
	"http"
	"http/httptest"
	"io"
	"json"
	"os"
	"strings"
	"url"
)

func init() {
	http.HandleFunc("/buildtest", testHandler)
}

var testEntityKinds = []string{
	"Package",
	"Commit",
	"Result",
	"Log",
}

const testPkg = "code.google.com/p/go.more"

var testPackage = &Package{Name: "Test", Path: testPkg}

var testPackages = []*Package{
	&Package{Name: "Go", Path: ""},
	testPackage,
}

var testRequests = []struct {
	path string
	vals url.Values
	req  interface{}
	res  interface{}
}{
	// Packages
	{"/packages", nil, nil, []*Package{testPackage}},

	// Go repo
	{"/commit", nil, &Commit{Hash: "0001", ParentHash: "0000"}, nil},
	{"/commit", nil, &Commit{Hash: "0002", ParentHash: "0001"}, nil},
	{"/commit", nil, &Commit{Hash: "0003", ParentHash: "0002"}, nil},
	{"/todo", url.Values{"builder": {"linux-386"}}, nil, "0003"},
	{"/todo", url.Values{"builder": {"linux-amd64"}}, nil, "0003"},
	{"/result", nil, &Result{Builder: "linux-386", Hash: "0001", OK: true}, nil},
	{"/todo", url.Values{"builder": {"linux-386"}}, nil, "0003"},
	{"/result", nil, &Result{Builder: "linux-386", Hash: "0002", OK: true}, nil},
	{"/todo", url.Values{"builder": {"linux-386"}}, nil, "0003"},

	// multiple builders
	{"/todo", url.Values{"builder": {"linux-amd64"}}, nil, "0003"},
	{"/result", nil, &Result{Builder: "linux-amd64", Hash: "0003", OK: true}, nil},
	{"/todo", url.Values{"builder": {"linux-386"}}, nil, "0003"},
	{"/todo", url.Values{"builder": {"linux-amd64"}}, nil, "0002"},

	// branches
	{"/commit", nil, &Commit{Hash: "0004", ParentHash: "0003"}, nil},
	{"/commit", nil, &Commit{Hash: "0005", ParentHash: "0002"}, nil},
	{"/todo", url.Values{"builder": {"linux-386"}}, nil, "0005"},
	{"/result", nil, &Result{Builder: "linux-386", Hash: "0005", OK: true}, nil},
	{"/todo", url.Values{"builder": {"linux-386"}}, nil, "0004"},
	{"/result", nil, &Result{Builder: "linux-386", Hash: "0004", OK: true}, nil},
	{"/todo", url.Values{"builder": {"linux-386"}}, nil, "0003"},

	// logs
	{"/result", nil, &Result{Builder: "linux-386", Hash: "0003", OK: false, Log: []byte("test")}, nil},
	{"/log/a94a8fe5ccb19ba61c4c0873d391e987982fbbd3", nil, nil, "test"},
	{"/todo", url.Values{"builder": {"linux-386"}}, nil, nil},

	// non-Go repos
	{"/commit", nil, &Commit{PackagePath: testPkg, Hash: "1001", ParentHash: "1000"}, nil},
	{"/commit", nil, &Commit{PackagePath: testPkg, Hash: "1002", ParentHash: "1001"}, nil},
	{"/commit", nil, &Commit{PackagePath: testPkg, Hash: "1003", ParentHash: "1002"}, nil},
	{"/todo", url.Values{"builder": {"linux-386"}, "packagePath": {testPkg}, "goHash": {"0001"}}, nil, "1003"},
	{"/result", nil, &Result{PackagePath: testPkg, Builder: "linux-386", Hash: "1003", GoHash: "0001", OK: true}, nil},
	{"/todo", url.Values{"builder": {"linux-386"}, "packagePath": {testPkg}, "goHash": {"0001"}}, nil, "1002"},
	{"/result", nil, &Result{PackagePath: testPkg, Builder: "linux-386", Hash: "1002", GoHash: "0001", OK: true}, nil},
	{"/todo", url.Values{"builder": {"linux-386"}, "packagePath": {testPkg}, "goHash": {"0001"}}, nil, "1001"},
	{"/result", nil, &Result{PackagePath: testPkg, Builder: "linux-386", Hash: "1001", GoHash: "0001", OK: true}, nil},
	{"/todo", url.Values{"builder": {"linux-386"}, "packagePath": {testPkg}, "goHash": {"0001"}}, nil, nil},
	{"/todo", url.Values{"builder": {"linux-386"}, "packagePath": {testPkg}, "goHash": {"0002"}}, nil, "1003"},
}

func testHandler(w http.ResponseWriter, r *http.Request) {
	if !appengine.IsDevAppServer() {
		fmt.Fprint(w, "These tests must be run under the dev_appserver.")
		return
	}
	c := appengine.NewContext(r)
	if err := nukeEntities(c, testEntityKinds); err != nil {
		logErr(w, r, err)
		return
	}

	for _, p := range testPackages {
		if _, err := datastore.Put(c, p.Key(c), p); err != nil {
			logErr(w, r, err)
			return
		}
	}

	for i, t := range testRequests {
		errorf := func(format string, args ...interface{}) {
			fmt.Fprintf(w, "%d %s: ", i, t.path)
			fmt.Fprintf(w, format, args...)
			fmt.Fprintln(w)
		}
		var body io.ReadWriter
		if t.req != nil {
			body = new(bytes.Buffer)
			json.NewEncoder(body).Encode(t.req)
		}
		url := "http://" + appengine.DefaultVersionHostname(c) + t.path
		if t.vals != nil {
			url += "?" + t.vals.Encode()
		}
		req, err := http.NewRequest("POST", url, body)
		if err != nil {
			logErr(w, r, err)
			return
		}
		if t.req != nil {
			req.Method = "POST"
		}
		req.Header = r.Header
		rec := httptest.NewRecorder()
		http.DefaultServeMux.ServeHTTP(rec, req)
		if rec.Code != 0 && rec.Code != 200 {
			errorf(rec.Body.String())
			return
		}
		resp := new(dashResponse)
		if strings.HasPrefix(t.path, "/log/") {
			resp.Response = rec.Body.String()
		} else {
			err := json.NewDecoder(rec.Body).Decode(resp)
			if err != nil {
				errorf("decoding response: %v", err)
				return
			}
		}
		if e, ok := t.res.(string); ok {
			g, ok := resp.Response.(string)
			if !ok {
				errorf("Response not string: %T", resp.Response)
				return
			}
			if g != e {
				errorf("response mismatch: got %q want %q", g, e)
				return
			}
		}
		if t.res == nil && resp.Response != nil {
			errorf("response mismatch: got %q expected <nil>",
				resp.Response)
			return
		}
	}
	fmt.Fprint(w, "PASS")
}

func nukeEntities(c appengine.Context, kinds []string) os.Error {
	if !appengine.IsDevAppServer() {
		return os.NewError("can't nuke production data")
	}
	var keys []*datastore.Key
	for _, kind := range kinds {
		q := datastore.NewQuery(kind).KeysOnly()
		for t := q.Run(c); ; {
			k, err := t.Next(nil)
			if err == datastore.Done {
				break
			}
			if err != nil {
				return err
			}
			keys = append(keys, k)
		}
	}
	return datastore.DeleteMulti(c, keys)
}
<|endoftext|>


<commit_before>package terraform

import (
	"fmt"
	"log"

	"github.com/hashicorp/hcl/v2"
	"github.com/hashicorp/terraform/internal/addrs"
	"github.com/hashicorp/terraform/internal/configs"
	"github.com/hashicorp/terraform/internal/dag"
	"github.com/hashicorp/terraform/internal/instances"
	"github.com/hashicorp/terraform/internal/lang"
	"github.com/hashicorp/terraform/internal/tfdiags"
	"github.com/zclconf/go-cty/cty"
	"github.com/zclconf/go-cty/cty/convert"
)

// nodeExpandModuleVariable is the placeholder for an variable that has not yet had
// its module path expanded.
type nodeExpandModuleVariable struct {
	Addr   addrs.InputVariable
	Module addrs.Module
	Config *configs.Variable
	Expr   hcl.Expression
}

var (
	_ GraphNodeDynamicExpandable = (*nodeExpandModuleVariable)(nil)
	_ GraphNodeReferenceOutside  = (*nodeExpandModuleVariable)(nil)
	_ GraphNodeReferenceable     = (*nodeExpandModuleVariable)(nil)
	_ GraphNodeReferencer        = (*nodeExpandModuleVariable)(nil)
	_ graphNodeTemporaryValue    = (*nodeExpandModuleVariable)(nil)
	_ graphNodeExpandsInstances  = (*nodeExpandModuleVariable)(nil)
)

func (n *nodeExpandModuleVariable) expandsInstances() {}

func (n *nodeExpandModuleVariable) temporaryValue() bool {
	return true
}

func (n *nodeExpandModuleVariable) DynamicExpand(ctx EvalContext) (*Graph, error) {
	var g Graph
	expander := ctx.InstanceExpander()
	for _, module := range expander.ExpandModule(n.Module) {
		o := &nodeModuleVariable{
			Addr:           n.Addr.Absolute(module),
			Config:         n.Config,
			Expr:           n.Expr,
			ModuleInstance: module,
		}
		g.Add(o)
	}
	return &g, nil
}

func (n *nodeExpandModuleVariable) Name() string {
	return fmt.Sprintf("%s.%s (expand)", n.Module, n.Addr.String())
}

// GraphNodeModulePath
func (n *nodeExpandModuleVariable) ModulePath() addrs.Module {
	return n.Module
}

// GraphNodeReferencer
func (n *nodeExpandModuleVariable) References() []*addrs.Reference {

	// If we have no value expression, we cannot depend on anything.
	if n.Expr == nil {
		return nil
	}

	// Variables in the root don't depend on anything, because their values
	// are gathered prior to the graph walk and recorded in the context.
	if len(n.Module) == 0 {
		return nil
	}

	// Otherwise, we depend on anything referenced by our value expression.
	// We ignore diagnostics here under the assumption that we'll re-eval
	// all these things later and catch them then; for our purposes here,
	// we only care about valid references.
	//
	// Due to our GraphNodeReferenceOutside implementation, the addresses
	// returned by this function are interpreted in the _parent_ module from
	// where our associated variable was declared, which is correct because
	// our value expression is assigned within a "module" block in the parent
	// module.
	refs, _ := lang.ReferencesInExpr(n.Expr)
	return refs
}

// GraphNodeReferenceOutside implementation
func (n *nodeExpandModuleVariable) ReferenceOutside() (selfPath, referencePath addrs.Module) {
	return n.Module, n.Module.Parent()
}

// GraphNodeReferenceable
func (n *nodeExpandModuleVariable) ReferenceableAddrs() []addrs.Referenceable {
	return []addrs.Referenceable{n.Addr}
}

// nodeModuleVariable represents a module variable input during
// the apply step.
type nodeModuleVariable struct {
	Addr   addrs.AbsInputVariableInstance
	Config *configs.Variable // Config is the var in the config
	Expr   hcl.Expression    // Expr is the value expression given in the call
	// ModuleInstance in order to create the appropriate context for evaluating
	// ModuleCallArguments, ex. so count.index and each.key can resolve
	ModuleInstance addrs.ModuleInstance
}

// Ensure that we are implementing all of the interfaces we think we are
// implementing.
var (
	_ GraphNodeModuleInstance = (*nodeModuleVariable)(nil)
	_ GraphNodeExecutable     = (*nodeModuleVariable)(nil)
	_ graphNodeTemporaryValue = (*nodeModuleVariable)(nil)
	_ dag.GraphNodeDotter     = (*nodeModuleVariable)(nil)
)

func (n *nodeModuleVariable) temporaryValue() bool {
	return true
}

func (n *nodeModuleVariable) Name() string {
	return n.Addr.String()
}

// GraphNodeModuleInstance
func (n *nodeModuleVariable) Path() addrs.ModuleInstance {
	// We execute in the parent scope (above our own module) because
	// expressions in our value are resolved in that context.
	return n.Addr.Module.Parent()
}

// GraphNodeModulePath
func (n *nodeModuleVariable) ModulePath() addrs.Module {
	return n.Addr.Module.Module()
}

// GraphNodeExecutable
func (n *nodeModuleVariable) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
	// If we have no value, do nothing
	if n.Expr == nil {
		return nil
	}

	// Otherwise, interpolate the value of this variable and set it
	// within the variables mapping.
	var vals map[string]cty.Value
	var err error

	switch op {
	case walkValidate:
		vals, err = n.evalModuleCallArgument(ctx, true)
		diags = diags.Append(err)
		if diags.HasErrors() {
			return diags
		}
	default:
		vals, err = n.evalModuleCallArgument(ctx, false)
		diags = diags.Append(err)
		if diags.HasErrors() {
			return diags
		}
	}

	// Set values for arguments of a child module call, for later retrieval
	// during expression evaluation.
	_, call := n.Addr.Module.CallInstance()
	ctx.SetModuleCallArguments(call, vals)

	return evalVariableValidations(n.Addr, n.Config, n.Expr, ctx)
}

// dag.GraphNodeDotter impl.
func (n *nodeModuleVariable) DotNode(name string, opts *dag.DotOpts) *dag.DotNode {
	return &dag.DotNode{
		Name: name,
		Attrs: map[string]string{
			"label": n.Name(),
			"shape": "note",
		},
	}
}

// evalModuleCallArgument produces the value for a particular variable as will
// be used by a child module instance.
//
// The result is written into a map, with its key set to the local name of the
// variable, disregarding the module instance address. A map is returned instead
// of a single value as a result of trying to be convenient for use with
// EvalContext.SetModuleCallArguments, which expects a map to merge in with any
// existing arguments.
//
// validateOnly indicates that this evaluation is only for config
// validation, and we will not have any expansion module instance
// repetition data.
func (n *nodeModuleVariable) evalModuleCallArgument(ctx EvalContext, validateOnly bool) (map[string]cty.Value, error) {
	name := n.Addr.Variable.Name
	expr := n.Expr

	if expr == nil {
		// Should never happen, but we'll bail out early here rather than
		// crash in case it does. We set no value at all in this case,
		// making a subsequent call to EvalContext.SetModuleCallArguments
		// a no-op.
		log.Printf("[ERROR] attempt to evaluate %s with nil expression", n.Addr.String())
		return nil, nil
	}

	var moduleInstanceRepetitionData instances.RepetitionData

	switch {
	case validateOnly:
		// the instance expander does not track unknown expansion values, so we
		// have to assume all RepetitionData is unknown.
		moduleInstanceRepetitionData = instances.RepetitionData{
			CountIndex: cty.UnknownVal(cty.Number),
			EachKey:    cty.UnknownVal(cty.String),
			EachValue:  cty.DynamicVal,
		}

	default:
		// Get the repetition data for this module instance,
		// so we can create the appropriate scope for evaluating our expression
		moduleInstanceRepetitionData = ctx.InstanceExpander().GetModuleInstanceRepetitionData(n.ModuleInstance)
	}

	scope := ctx.EvaluationScope(nil, moduleInstanceRepetitionData)
	val, diags := scope.EvalExpr(expr, cty.DynamicPseudoType)

	// We intentionally passed DynamicPseudoType to EvalExpr above because
	// now we can do our own local type conversion and produce an error message
	// with better context if it fails.
	var convErr error
	val, convErr = convert.Convert(val, n.Config.ConstraintType)
	if convErr != nil {
		diags = diags.Append(&hcl.Diagnostic{
			Severity: hcl.DiagError,
			Summary:  "Invalid value for module argument",
			Detail: fmt.Sprintf(
				"The given value is not suitable for child module variable %q defined at %s: %s.",
				name, n.Config.DeclRange.String(), convErr,
			),
			Subject: expr.Range().Ptr(),
		})
		// We'll return a placeholder unknown value to avoid producing
		// redundant downstream errors.
		val = cty.UnknownVal(n.Config.Type)
	}

	// If there is no default, we have to ensure that a null value is allowed
	// for this variable.
	if n.Config.Default == cty.NilVal && !n.Config.Nullable && val.IsNull() {
		// The value cannot be null, and there is no configured default.
		diags = diags.Append(&hcl.Diagnostic{
			Severity: hcl.DiagError,
			Summary:  `Invalid variable value`,
			Detail:   fmt.Sprintf(`The resolved value of variable %q cannot be null.`, n.Addr),
			Subject:  &n.Config.DeclRange,
		})
		// Stub out our return value so that the semantic checker doesn't
		// produce redundant downstream errors.
		val = cty.UnknownVal(n.Config.Type)
	}

	vals := make(map[string]cty.Value)
	vals[name] = val

	return vals, diags.ErrWithWarnings()
}
<commit_msg>update null variable error text<commit_after>package terraform

import (
	"fmt"
	"log"

	"github.com/hashicorp/hcl/v2"
	"github.com/hashicorp/terraform/internal/addrs"
	"github.com/hashicorp/terraform/internal/configs"
	"github.com/hashicorp/terraform/internal/dag"
	"github.com/hashicorp/terraform/internal/instances"
	"github.com/hashicorp/terraform/internal/lang"
	"github.com/hashicorp/terraform/internal/tfdiags"
	"github.com/zclconf/go-cty/cty"
	"github.com/zclconf/go-cty/cty/convert"
)

// nodeExpandModuleVariable is the placeholder for an variable that has not yet had
// its module path expanded.
type nodeExpandModuleVariable struct {
	Addr   addrs.InputVariable
	Module addrs.Module
	Config *configs.Variable
	Expr   hcl.Expression
}

var (
	_ GraphNodeDynamicExpandable = (*nodeExpandModuleVariable)(nil)
	_ GraphNodeReferenceOutside  = (*nodeExpandModuleVariable)(nil)
	_ GraphNodeReferenceable     = (*nodeExpandModuleVariable)(nil)
	_ GraphNodeReferencer        = (*nodeExpandModuleVariable)(nil)
	_ graphNodeTemporaryValue    = (*nodeExpandModuleVariable)(nil)
	_ graphNodeExpandsInstances  = (*nodeExpandModuleVariable)(nil)
)

func (n *nodeExpandModuleVariable) expandsInstances() {}

func (n *nodeExpandModuleVariable) temporaryValue() bool {
	return true
}

func (n *nodeExpandModuleVariable) DynamicExpand(ctx EvalContext) (*Graph, error) {
	var g Graph
	expander := ctx.InstanceExpander()
	for _, module := range expander.ExpandModule(n.Module) {
		o := &nodeModuleVariable{
			Addr:           n.Addr.Absolute(module),
			Config:         n.Config,
			Expr:           n.Expr,
			ModuleInstance: module,
		}
		g.Add(o)
	}
	return &g, nil
}

func (n *nodeExpandModuleVariable) Name() string {
	return fmt.Sprintf("%s.%s (expand)", n.Module, n.Addr.String())
}

// GraphNodeModulePath
func (n *nodeExpandModuleVariable) ModulePath() addrs.Module {
	return n.Module
}

// GraphNodeReferencer
func (n *nodeExpandModuleVariable) References() []*addrs.Reference {

	// If we have no value expression, we cannot depend on anything.
	if n.Expr == nil {
		return nil
	}

	// Variables in the root don't depend on anything, because their values
	// are gathered prior to the graph walk and recorded in the context.
	if len(n.Module) == 0 {
		return nil
	}

	// Otherwise, we depend on anything referenced by our value expression.
	// We ignore diagnostics here under the assumption that we'll re-eval
	// all these things later and catch them then; for our purposes here,
	// we only care about valid references.
	//
	// Due to our GraphNodeReferenceOutside implementation, the addresses
	// returned by this function are interpreted in the _parent_ module from
	// where our associated variable was declared, which is correct because
	// our value expression is assigned within a "module" block in the parent
	// module.
	refs, _ := lang.ReferencesInExpr(n.Expr)
	return refs
}

// GraphNodeReferenceOutside implementation
func (n *nodeExpandModuleVariable) ReferenceOutside() (selfPath, referencePath addrs.Module) {
	return n.Module, n.Module.Parent()
}

// GraphNodeReferenceable
func (n *nodeExpandModuleVariable) ReferenceableAddrs() []addrs.Referenceable {
	return []addrs.Referenceable{n.Addr}
}

// nodeModuleVariable represents a module variable input during
// the apply step.
type nodeModuleVariable struct {
	Addr   addrs.AbsInputVariableInstance
	Config *configs.Variable // Config is the var in the config
	Expr   hcl.Expression    // Expr is the value expression given in the call
	// ModuleInstance in order to create the appropriate context for evaluating
	// ModuleCallArguments, ex. so count.index and each.key can resolve
	ModuleInstance addrs.ModuleInstance
}

// Ensure that we are implementing all of the interfaces we think we are
// implementing.
var (
	_ GraphNodeModuleInstance = (*nodeModuleVariable)(nil)
	_ GraphNodeExecutable     = (*nodeModuleVariable)(nil)
	_ graphNodeTemporaryValue = (*nodeModuleVariable)(nil)
	_ dag.GraphNodeDotter     = (*nodeModuleVariable)(nil)
)

func (n *nodeModuleVariable) temporaryValue() bool {
	return true
}

func (n *nodeModuleVariable) Name() string {
	return n.Addr.String()
}

// GraphNodeModuleInstance
func (n *nodeModuleVariable) Path() addrs.ModuleInstance {
	// We execute in the parent scope (above our own module) because
	// expressions in our value are resolved in that context.
	return n.Addr.Module.Parent()
}

// GraphNodeModulePath
func (n *nodeModuleVariable) ModulePath() addrs.Module {
	return n.Addr.Module.Module()
}

// GraphNodeExecutable
func (n *nodeModuleVariable) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
	// If we have no value, do nothing
	if n.Expr == nil {
		return nil
	}

	// Otherwise, interpolate the value of this variable and set it
	// within the variables mapping.
	var vals map[string]cty.Value
	var err error

	switch op {
	case walkValidate:
		vals, err = n.evalModuleCallArgument(ctx, true)
		diags = diags.Append(err)
		if diags.HasErrors() {
			return diags
		}
	default:
		vals, err = n.evalModuleCallArgument(ctx, false)
		diags = diags.Append(err)
		if diags.HasErrors() {
			return diags
		}
	}

	// Set values for arguments of a child module call, for later retrieval
	// during expression evaluation.
	_, call := n.Addr.Module.CallInstance()
	ctx.SetModuleCallArguments(call, vals)

	return evalVariableValidations(n.Addr, n.Config, n.Expr, ctx)
}

// dag.GraphNodeDotter impl.
func (n *nodeModuleVariable) DotNode(name string, opts *dag.DotOpts) *dag.DotNode {
	return &dag.DotNode{
		Name: name,
		Attrs: map[string]string{
			"label": n.Name(),
			"shape": "note",
		},
	}
}

// evalModuleCallArgument produces the value for a particular variable as will
// be used by a child module instance.
//
// The result is written into a map, with its key set to the local name of the
// variable, disregarding the module instance address. A map is returned instead
// of a single value as a result of trying to be convenient for use with
// EvalContext.SetModuleCallArguments, which expects a map to merge in with any
// existing arguments.
//
// validateOnly indicates that this evaluation is only for config
// validation, and we will not have any expansion module instance
// repetition data.
func (n *nodeModuleVariable) evalModuleCallArgument(ctx EvalContext, validateOnly bool) (map[string]cty.Value, error) {
	name := n.Addr.Variable.Name
	expr := n.Expr

	if expr == nil {
		// Should never happen, but we'll bail out early here rather than
		// crash in case it does. We set no value at all in this case,
		// making a subsequent call to EvalContext.SetModuleCallArguments
		// a no-op.
		log.Printf("[ERROR] attempt to evaluate %s with nil expression", n.Addr.String())
		return nil, nil
	}

	var moduleInstanceRepetitionData instances.RepetitionData

	switch {
	case validateOnly:
		// the instance expander does not track unknown expansion values, so we
		// have to assume all RepetitionData is unknown.
		moduleInstanceRepetitionData = instances.RepetitionData{
			CountIndex: cty.UnknownVal(cty.Number),
			EachKey:    cty.UnknownVal(cty.String),
			EachValue:  cty.DynamicVal,
		}

	default:
		// Get the repetition data for this module instance,
		// so we can create the appropriate scope for evaluating our expression
		moduleInstanceRepetitionData = ctx.InstanceExpander().GetModuleInstanceRepetitionData(n.ModuleInstance)
	}

	scope := ctx.EvaluationScope(nil, moduleInstanceRepetitionData)
	val, diags := scope.EvalExpr(expr, cty.DynamicPseudoType)

	// We intentionally passed DynamicPseudoType to EvalExpr above because
	// now we can do our own local type conversion and produce an error message
	// with better context if it fails.
	var convErr error
	val, convErr = convert.Convert(val, n.Config.ConstraintType)
	if convErr != nil {
		diags = diags.Append(&hcl.Diagnostic{
			Severity: hcl.DiagError,
			Summary:  "Invalid value for module argument",
			Detail: fmt.Sprintf(
				"The given value is not suitable for child module variable %q defined at %s: %s.",
				name, n.Config.DeclRange.String(), convErr,
			),
			Subject: expr.Range().Ptr(),
		})
		// We'll return a placeholder unknown value to avoid producing
		// redundant downstream errors.
		val = cty.UnknownVal(n.Config.Type)
	}

	// If there is no default, we have to ensure that a null value is allowed
	// for this variable.
	if n.Config.Default == cty.NilVal && !n.Config.Nullable && val.IsNull() {
		// The value cannot be null, and there is no configured default.
		diags = diags.Append(&hcl.Diagnostic{
			Severity: hcl.DiagError,
			Summary:  `Invalid variable value`,
			Detail:   fmt.Sprintf(`The variable %q is required, but the given value resolved to null`, n.Addr),
			Subject:  &n.Config.DeclRange,
		})
		// Stub out our return value so that the semantic checker doesn't
		// produce redundant downstream errors.
		val = cty.UnknownVal(n.Config.Type)
	}

	vals := make(map[string]cty.Value)
	vals[name] = val

	return vals, diags.ErrWithWarnings()
}
<|endoftext|>


<commit_before>package controllers

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

	"github.com/robfig/revel"
	"github.com/zimmski/tirion"
	"github.com/zimmski/tirion/tirion-server/app"
)

type App struct {
	*revel.Controller
}

func (c App) Index() revel.Result {
	programs, err := app.Db.SearchPrograms()

	if err != nil {
		panic(err)
	}

	return c.Render(programs)
}

func (c App) ProgramIndex(programName string) revel.Result {
	runs, err := app.Db.SearchRuns(programName)

	if err != nil {
		panic(err)
	}

	if len(runs) == 0 {
		return c.NotFound("Program \"%s\" does not exists", programName)
	}

	return c.Render(programName, runs)
}

func (c App) ProgramRunIndex(programName string, runId int) revel.Result {
	run, err := app.Db.FindRun(programName, runId)

	if err != nil {
		panic(err)
	} else if run == nil {
		return c.NotFound("Run %d of program \"%s\" does not exists", runId, programName)
	}

	return c.Render(programName, run)
}

func (c App) ProgramRunMetric(programName string, runId int, metricName string) revel.Result {
	run, err := app.Db.FindRun(programName, runId)

	if err != nil {
		panic(err)
	} else if run == nil {
		return c.NotFound("Run %d of program \"%s\" does not exists", runId, programName)
	}

	metric, err := app.Db.SearchMetricOfRun(run, metricName)

	if err != nil {
		panic(err)
	}

	return c.RenderJson(metric)
}

func (c App) ProgramRunStart(programName string) revel.Result {
	var interval, err = strconv.ParseInt(c.Params.Get("interval"), 10, 32)

	if err != nil {
		return c.RenderJson(tirion.MessageReturnStart{Error: fmt.Sprintf("Cannot parse interval: %v", err)})
	}

	var run = tirion.Run{
		Name:          c.Params.Get("name"),
		SubName:       c.Params.Get("sub_name"),
		Interval:      int(interval),
		Prog:          c.Params.Get("prog"),
		ProgArguments: c.Params.Get("prog_arguments"),
	}

	if run.Name == "" {
		return c.RenderJson(tirion.MessageReturnStart{Error: fmt.Sprintf("No name defined")})
	} else if run.Prog == "" {
		return c.RenderJson(tirion.MessageReturnStart{Error: fmt.Sprintf("No prog defined")})
	}

	err = json.Unmarshal([]byte(c.Params.Get("metrics")), &run.Metrics)

	if err != nil {
		return c.RenderJson(tirion.MessageReturnStart{Error: fmt.Sprintf("Parse metrics file: %v", err)})
	}

	if len(run.Metrics) == 0 {
		return c.RenderJson(tirion.MessageReturnStart{Error: fmt.Sprintf("No metrics defined")})
	}

	var metricNames = make(map[string]int)

	for i, m := range run.Metrics {
		if m.Name == "" {
			panic(fmt.Sprintf("No name defined for metric[%d]", i))
		} else if v, ok := metricNames[m.Name]; ok {
			panic(fmt.Sprintf("Name \"%s\" of metric[%d] alreay used for metric[%d]", m.Name, i, v))
		} else if m.Type == "" {
			panic(fmt.Sprintf("No type defined for metric[%d]", i))
		} else if _, ok := tirion.MetricTypes[m.Type]; !ok {
			panic(fmt.Sprintf("Unknown metric type \"%s\" for metric[%d]", m.Type, i))
		}

		metricNames[m.Name] = i
	}

	err = app.Db.StartRun(&run)

	if err != nil {
		return c.RenderJson(tirion.MessageReturnStart{Error: fmt.Sprintf("%+v", err)})
	} else {
		return c.RenderJson(tirion.MessageReturnStart{Run: run.Id, Error: ""})
	}
}

func (c App) ProgramRunInsert(programName string, runId int) revel.Result {
	var metrics []tirion.MessageData

	var err = json.Unmarshal([]byte(c.Params.Get("metrics")), &metrics)

	if err != nil {
		return c.RenderJson(tirion.MessageReturnStart{Error: fmt.Sprintf("Parse metrics: %v", err)})
	}

	err = app.Db.CreateMetrics(runId, metrics)

	if err != nil {
		return c.RenderJson(tirion.MessageReturnInsert{Error: fmt.Sprintf("%+v", err)})
	} else {
		return c.RenderJson(tirion.MessageReturnInsert{Error: ""})
	}
}

func (c App) ProgramRunStop(programName string, runId int) revel.Result {
	var err = app.Db.StopRun(runId)

	if err != nil {
		return c.RenderJson(tirion.MessageReturnStop{Error: fmt.Sprintf("%+v", err)})
	} else {
		return c.RenderJson(tirion.MessageReturnStop{Error: ""})
	}
}

func (c App) ProgramRunTag(programName string, runId int) revel.Result {
	var t, err = strconv.ParseInt(c.Params.Get("time"), 10, 64)

	var tag = tirion.Tag{
		Tag:  c.Params.Get("tag"),
		Time: time.Unix(0, t),
	}

	err = app.Db.CreateTag(runId, &tag)

	if err != nil {
		return c.RenderJson(tirion.MessageReturnStop{Error: fmt.Sprintf("%+v", err)})
	} else {
		return c.RenderJson(tirion.MessageReturnStop{Error: ""})
	}
}

func (c App) ProgramRunTags(programName string, runId int) revel.Result {
	run, err := app.Db.FindRun(programName, runId)

	if err != nil {
		panic(err)
	} else if run == nil {
		return c.NotFound("Run %d of program \"%s\" does not exists", runId, programName)
	}

	tags, err := app.Db.SearchTagsOfRun(run)

	if err != nil {
		panic(err)
	}

	return c.RenderJson(tags)
}
<commit_msg>use correct message type for tag route<commit_after>package controllers

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

	"github.com/robfig/revel"
	"github.com/zimmski/tirion"
	"github.com/zimmski/tirion/tirion-server/app"
)

type App struct {
	*revel.Controller
}

func (c App) Index() revel.Result {
	programs, err := app.Db.SearchPrograms()

	if err != nil {
		panic(err)
	}

	return c.Render(programs)
}

func (c App) ProgramIndex(programName string) revel.Result {
	runs, err := app.Db.SearchRuns(programName)

	if err != nil {
		panic(err)
	}

	if len(runs) == 0 {
		return c.NotFound("Program \"%s\" does not exists", programName)
	}

	return c.Render(programName, runs)
}

func (c App) ProgramRunIndex(programName string, runId int) revel.Result {
	run, err := app.Db.FindRun(programName, runId)

	if err != nil {
		panic(err)
	} else if run == nil {
		return c.NotFound("Run %d of program \"%s\" does not exists", runId, programName)
	}

	return c.Render(programName, run)
}

func (c App) ProgramRunMetric(programName string, runId int, metricName string) revel.Result {
	run, err := app.Db.FindRun(programName, runId)

	if err != nil {
		panic(err)
	} else if run == nil {
		return c.NotFound("Run %d of program \"%s\" does not exists", runId, programName)
	}

	metric, err := app.Db.SearchMetricOfRun(run, metricName)

	if err != nil {
		panic(err)
	}

	return c.RenderJson(metric)
}

func (c App) ProgramRunStart(programName string) revel.Result {
	var interval, err = strconv.ParseInt(c.Params.Get("interval"), 10, 32)

	if err != nil {
		return c.RenderJson(tirion.MessageReturnStart{Error: fmt.Sprintf("Cannot parse interval: %v", err)})
	}

	var run = tirion.Run{
		Name:          c.Params.Get("name"),
		SubName:       c.Params.Get("sub_name"),
		Interval:      int(interval),
		Prog:          c.Params.Get("prog"),
		ProgArguments: c.Params.Get("prog_arguments"),
	}

	if run.Name == "" {
		return c.RenderJson(tirion.MessageReturnStart{Error: fmt.Sprintf("No name defined")})
	} else if run.Prog == "" {
		return c.RenderJson(tirion.MessageReturnStart{Error: fmt.Sprintf("No prog defined")})
	}

	err = json.Unmarshal([]byte(c.Params.Get("metrics")), &run.Metrics)

	if err != nil {
		return c.RenderJson(tirion.MessageReturnStart{Error: fmt.Sprintf("Parse metrics file: %v", err)})
	}

	if len(run.Metrics) == 0 {
		return c.RenderJson(tirion.MessageReturnStart{Error: fmt.Sprintf("No metrics defined")})
	}

	var metricNames = make(map[string]int)

	for i, m := range run.Metrics {
		if m.Name == "" {
			panic(fmt.Sprintf("No name defined for metric[%d]", i))
		} else if v, ok := metricNames[m.Name]; ok {
			panic(fmt.Sprintf("Name \"%s\" of metric[%d] alreay used for metric[%d]", m.Name, i, v))
		} else if m.Type == "" {
			panic(fmt.Sprintf("No type defined for metric[%d]", i))
		} else if _, ok := tirion.MetricTypes[m.Type]; !ok {
			panic(fmt.Sprintf("Unknown metric type \"%s\" for metric[%d]", m.Type, i))
		}

		metricNames[m.Name] = i
	}

	err = app.Db.StartRun(&run)

	if err != nil {
		return c.RenderJson(tirion.MessageReturnStart{Error: fmt.Sprintf("%+v", err)})
	} else {
		return c.RenderJson(tirion.MessageReturnStart{Run: run.Id, Error: ""})
	}
}

func (c App) ProgramRunInsert(programName string, runId int) revel.Result {
	var metrics []tirion.MessageData

	var err = json.Unmarshal([]byte(c.Params.Get("metrics")), &metrics)

	if err != nil {
		return c.RenderJson(tirion.MessageReturnStart{Error: fmt.Sprintf("Parse metrics: %v", err)})
	}

	err = app.Db.CreateMetrics(runId, metrics)

	if err != nil {
		return c.RenderJson(tirion.MessageReturnInsert{Error: fmt.Sprintf("%+v", err)})
	} else {
		return c.RenderJson(tirion.MessageReturnInsert{Error: ""})
	}
}

func (c App) ProgramRunStop(programName string, runId int) revel.Result {
	var err = app.Db.StopRun(runId)

	if err != nil {
		return c.RenderJson(tirion.MessageReturnStop{Error: fmt.Sprintf("%+v", err)})
	} else {
		return c.RenderJson(tirion.MessageReturnStop{Error: ""})
	}
}

func (c App) ProgramRunTag(programName string, runId int) revel.Result {
	var t, err = strconv.ParseInt(c.Params.Get("time"), 10, 64)

	var tag = tirion.Tag{
		Tag:  c.Params.Get("tag"),
		Time: time.Unix(0, t),
	}

	err = app.Db.CreateTag(runId, &tag)

	if err != nil {
		return c.RenderJson(tirion.MessageReturnTag{Error: fmt.Sprintf("%+v", err)})
	} else {
		return c.RenderJson(tirion.MessageReturnTag{Error: ""})
	}
}

func (c App) ProgramRunTags(programName string, runId int) revel.Result {
	run, err := app.Db.FindRun(programName, runId)

	if err != nil {
		panic(err)
	} else if run == nil {
		return c.NotFound("Run %d of program \"%s\" does not exists", runId, programName)
	}

	tags, err := app.Db.SearchTagsOfRun(run)

	if err != nil {
		panic(err)
	}

	return c.RenderJson(tags)
}
<|endoftext|>


<commit_before>package readers

import (
	"bytes"
	"errors"
	"testing"
	"time"

	"github.com/uluyol/fabbench/recorders"
)

func TestLatencyRecorderReaderRoundTrip(t *testing.T) {
	var rec recorders.Latency
	rec.Reset()
	rec.Record(0, nil)
	rec.Record(time.Nanosecond, nil)
	rec.Record(time.Microsecond, nil)
	rec.Record(time.Millisecond, nil)
	rec.Record(time.Second, nil)
	rec.Record(2000*time.Millisecond, nil)
	rec.Record(100000*time.Second, nil)
	rec.Record(123123123123, errors.New("dummy0"))
	rec.Record(123129993123, errors.New("dummy2"))
	rec.Record(0xffffffaaaf, errors.New("dummy3"))
	rec.Record(12317773, errors.New("dummy4"))

	var buf bytes.Buffer
	if err := rec.WriteTo(&buf); err != nil {
		t.Fatalf("unexpected error while writing: %v", err)
	}

	res, err := ReadLatency(&buf)
	if err != nil {
		t.Fatalf("unexpected error while reading: %v", err)
	}

	if !res.start.Equal(rec.Start()) {
		t.Errorf("different start times: %v vs %v", rec.Start(), res.start)
	}

	bucketTests := []struct {
		name    string
		wantLen int
		recVal  []uint16
		resVal  []uint16
	}{
		{"us", 4, rec.Micros(), res.us},
		{"ms", 2, rec.Millis(), res.ms},
		{"s", 1, rec.Seconds(), res.s},
	}

	for _, bt := range bucketTests {
		if bt.wantLen != len(bt.recVal) || bt.wantLen != len(bt.resVal) {
			t.Errorf("bucket %s: want %d vals, got rec %d res %d",
				bt.name, bt.wantLen, len(bt.recVal), len(bt.resVal))
		}
	}

	wantDurations := []time.Duration{
		-1,
		0,
		0,
		time.Microsecond,
		time.Millisecond,
		time.Second,
		2 * time.Second,
		time.Duration(^uint16(0)) * time.Second,
	}

	compareVals(t, res.AllVals(), wantDurations)

	if res.errs != 4 {
		t.Errorf("want 4 errors got %d", res.errs)
	}
}

func compareVals(t *testing.T, vals []HistVal, durations []time.Duration) {
	if len(vals) != len(durations) {
		t.Errorf("different lengths")
	}

	for i := range vals {
		if vals[i].Value != durations[i] {
			t.Errorf("position %d differs: want %s got %s", i, durations[i], vals[i].Value)
		}
	}
}
<commit_msg>readers: test writing, reading multiple dists<commit_after>package readers

import (
	"bytes"
	"errors"
	"testing"
	"time"

	"github.com/uluyol/fabbench/recorders"
)

func TestLatencyRecorderReaderRoundTrip(t *testing.T) {
	var rec recorders.Latency
	rec.Reset()
	rec.Record(0, nil)
	rec.Record(time.Nanosecond, nil)
	rec.Record(time.Microsecond, nil)
	rec.Record(time.Millisecond, nil)
	rec.Record(time.Second, nil)
	rec.Record(2000*time.Millisecond, nil)
	rec.Record(100000*time.Second, nil)
	rec.Record(123123123123, errors.New("dummy0"))
	rec.Record(123129993123, errors.New("dummy2"))
	rec.Record(0xffffffaaaf, errors.New("dummy3"))
	rec.Record(12317773, errors.New("dummy4"))

	var buf bytes.Buffer
	if err := rec.WriteTo(&buf); err != nil {
		t.Fatalf("unexpected error while writing: %v", err)
	}

	res, err := ReadLatency(&buf)
	if err != nil {
		t.Fatalf("unexpected error while reading: %v", err)
	}

	if !res.start.Equal(rec.Start()) {
		t.Errorf("different start times: %v vs %v", rec.Start(), res.start)
	}

	bucketTests := []struct {
		name    string
		wantLen int
		recVal  []uint16
		resVal  []uint16
	}{
		{"us", 4, rec.Micros(), res.us},
		{"ms", 2, rec.Millis(), res.ms},
		{"s", 1, rec.Seconds(), res.s},
	}

	for _, bt := range bucketTests {
		if bt.wantLen != len(bt.recVal) || bt.wantLen != len(bt.resVal) {
			t.Errorf("bucket %s: want %d vals, got rec %d res %d",
				bt.name, bt.wantLen, len(bt.recVal), len(bt.resVal))
		}
	}

	wantDurations := []time.Duration{
		-1,
		0,
		0,
		time.Microsecond,
		time.Millisecond,
		time.Second,
		2 * time.Second,
		time.Duration(^uint16(0)) * time.Second,
	}

	compareVals(t, res.AllVals(), wantDurations)

	if res.errs != 4 {
		t.Errorf("want 4 errors got %d", res.errs)
	}
}

func TestLatencyRecorderReaderMulti(t *testing.T) {
	var buf bytes.Buffer

	var rec recorders.Latency
	rec.Reset()
	start1 := rec.Start()
	rec.Record(0, nil)
	rec.Record(time.Nanosecond, nil)
	rec.Record(time.Microsecond, nil)
	rec.Record(time.Millisecond, nil)
	rec.Record(time.Second, nil)
	rec.Record(2000*time.Millisecond, nil)
	rec.Record(100000*time.Second, nil)
	rec.Record(123123123123, errors.New("dummy0"))

	if err := rec.WriteTo(&buf); err != nil {
		t.Fatalf("unexpected error while writing 1: %v", err)
	}

	if start1 != rec.Start() {
		t.Fatalf("unexpected start time difference after writing 1: first %v then %v", start1, rec.Start)
	}

	rec.Reset()
	start2 := rec.Start()
	rec.Record(time.Microsecond, nil)
	rec.Record(time.Millisecond, nil)
	rec.Record(time.Second, nil)
	rec.Record(2000*time.Millisecond, nil)
	rec.Record(100000*time.Second, nil)
	rec.Record(123123123123, errors.New("dummy0"))

	if err := rec.WriteTo(&buf); err != nil {
		t.Fatalf("unexpected error while writing 2: %v", err)
	}

	if start2 != rec.Start() {
		t.Fatalf("unexpected start time difference after writing 2: first %v then %v", start2, rec.Start)
	}

	rec.Reset()
	start3 := rec.Start()
	rec.Record(0, nil)
	rec.Record(time.Nanosecond, nil)
	rec.Record(time.Microsecond, nil)
	rec.Record(time.Millisecond, nil)
	rec.Record(100000*time.Second, nil)
	rec.Record(123123123123, errors.New("dummy0"))

	if err := rec.WriteTo(&buf); err != nil {
		t.Fatalf("unexpected error while writing 3: %v", err)
	}

	// check written data

	resTests := []struct {
		start time.Time
		len   int
	}{
		{start1, 8},
		{start2, 6},
		{start3, 6},
	}

	got := 0
	for i, test := range resTests {
		res, err := ReadLatency(&buf)
		if err != nil {
			t.Fatalf("unexpected error while reading %d: %v", i, err)
		}

		if !res.start.Equal(test.start) {
			t.Errorf("different start times for %d: want %v got %v", i, test.start, rec.Start())
		}

		if len(res.AllVals()) != test.len {
			t.Errorf("different lengths for %d: want %d got %d", i, test.len, len(res.AllVals()))
		}
		got++
	}

	if got != len(resTests) {
		t.Errorf("wrote %d got %d", got, len(resTests))
	}
}

func compareVals(t *testing.T, vals []HistVal, durations []time.Duration) {
	if len(vals) != len(durations) {
		t.Errorf("different lengths")
	}

	for i := range vals {
		if vals[i].Value != durations[i] {
			t.Errorf("position %d differs: want %s got %s", i, durations[i], vals[i].Value)
		}
	}
}
<|endoftext|>


<commit_before>package missinggo

import (
	"regexp"
	"runtime"
)

// It will be the one and only identifier after a package specifier.
var testNameRegexp = regexp.MustCompile(`\.(Test[\p{L}_\p{N}]*)$`)

// Returns the name of the test function from the call stack.
func GetTestName() string {
	pc := make([]uintptr, 32)
	n := runtime.Callers(0, pc)
	for i := 0; i < n; i++ {
		name := runtime.FuncForPC(pc[i]).Name()
		ms := testNameRegexp.FindStringSubmatch(name)
		if ms == nil {
			continue
		}
		return ms[1]
	}
	panic("test name could not be recovered")
}
<commit_msg>Code comment<commit_after>package missinggo

import (
	"regexp"
	"runtime"
)

// It will be the one and only identifier after a package specifier.
var testNameRegexp = regexp.MustCompile(`\.(Test[\p{L}_\p{N}]*)$`)

// Returns the name of the test function from the call stack. See
// http://stackoverflow.com/q/35535635/149482 for another method.
func GetTestName() string {
	pc := make([]uintptr, 32)
	n := runtime.Callers(0, pc)
	for i := 0; i < n; i++ {
		name := runtime.FuncForPC(pc[i]).Name()
		ms := testNameRegexp.FindStringSubmatch(name)
		if ms == nil {
			continue
		}
		return ms[1]
	}
	panic("test name could not be recovered")
}
<|endoftext|>


<commit_before>/*
Copyright 2017 Google Inc.

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 dbconnpool exposes a single DBConnection object
with wrapped access to a single DB connection, and a ConnectionPool
object to pool these DBConnections.
*/
package dbconnpool

import (
	"errors"
	"net"
	"sync"
	"time"

	"golang.org/x/net/context"

	"vitess.io/vitess/go/mysql"
	"vitess.io/vitess/go/pools"
	"vitess.io/vitess/go/stats"
	"vitess.io/vitess/go/vt/log"
)

var (
	// ErrConnPoolClosed is returned if the connection pool is closed.
	ErrConnPoolClosed = errors.New("connection pool is closed")
	// usedNames is for preventing expvar from panicking. Tests
	// create pool objects multiple time. If a name was previously
	// used, expvar initialization is skipped.
	// TODO(sougou): Find a way to still crash if this happened
	// through non-test code.
	usedNames = make(map[string]bool)
)

// ConnectionPool re-exposes ResourcePool as a pool of
// PooledDBConnection objects.
type ConnectionPool struct {
	mu                  sync.Mutex
	connections         *pools.ResourcePool
	capacity            int
	idleTimeout         time.Duration
	resolutionFrequency time.Duration

	// info and mysqlStats are set at Open() time
	info      *mysql.ConnParams
	addresses []net.IP

	ticker   *time.Ticker
	stop     chan struct{}
	wg       sync.WaitGroup
	hostIsIP bool

	mysqlStats *stats.Timings
}

// NewConnectionPool creates a new ConnectionPool. The name is used
// to publish stats only.
func NewConnectionPool(name string, capacity int, idleTimeout time.Duration, dnsResolutionFrequency time.Duration) *ConnectionPool {
	cp := &ConnectionPool{capacity: capacity, idleTimeout: idleTimeout, resolutionFrequency: dnsResolutionFrequency}
	if name == "" || usedNames[name] {
		return cp
	}
	usedNames[name] = true
	stats.NewGaugeFunc(name+"Capacity", "Connection pool capacity", cp.Capacity)
	stats.NewGaugeFunc(name+"Available", "Connection pool available", cp.Available)
	stats.NewGaugeFunc(name+"Active", "Connection pool active", cp.Active)
	stats.NewGaugeFunc(name+"InUse", "Connection pool in-use", cp.InUse)
	stats.NewGaugeFunc(name+"MaxCap", "Connection pool max cap", cp.MaxCap)
	stats.NewCounterFunc(name+"WaitCount", "Connection pool wait count", cp.WaitCount)
	stats.NewCounterDurationFunc(name+"WaitTime", "Connection pool wait time", cp.WaitTime)
	stats.NewGaugeDurationFunc(name+"IdleTimeout", "Connection pool idle timeout", cp.IdleTimeout)
	stats.NewGaugeFunc(name+"IdleClosed", "Connection pool idle closed", cp.IdleClosed)
	return cp
}

func (cp *ConnectionPool) pool() (p *pools.ResourcePool) {
	cp.mu.Lock()
	p = cp.connections
	cp.mu.Unlock()
	return p
}

func (cp *ConnectionPool) refreshdns() {
	cp.mu.Lock()
	host := cp.info.Host
	cp.mu.Unlock()

	addrs, err := net.LookupHost(host)
	if err != nil {
		log.Errorf("Error refreshing connection dns name: (%v)", err)
		return
	}
	naddr := make([]net.IP, len(addrs))
	for i, a := range addrs {
		naddr[i] = net.ParseIP(a)
	}
	cp.mu.Lock()
	cp.addresses = naddr
	cp.mu.Unlock()
}

func (cp *ConnectionPool) validAddress(addr net.IP) bool {
	cp.mu.Lock()
	defer cp.mu.Unlock()

	// If we have no valid addresses we always return true
	if len(cp.addresses) == 0 {
		return true
	}

	// Check each address to see if the current RemoteAddr is in the set
	for _, a := range cp.addresses {
		if addr.Equal(a) {
			return true
		}
	}
	return false
}

// Open must be call before starting to use the pool.
//
// For instance:
// mysqlStats := stats.NewTimings("Mysql")
// pool := dbconnpool.NewConnectionPool("name", 10, 30*time.Second)
// pool.Open(info, mysqlStats)
// ...
// conn, err := pool.Get()
// ...
func (cp *ConnectionPool) Open(info *mysql.ConnParams, mysqlStats *stats.Timings) {
	cp.mu.Lock()
	defer cp.mu.Unlock()
	cp.info = info
	cp.mysqlStats = mysqlStats
	cp.connections = pools.NewResourcePool(cp.connect, cp.capacity, cp.capacity, cp.idleTimeout)
	// Check if we need to resolve a hostname (The Host is not just an IP  address).
	if cp.resolutionFrequency > 0 && net.ParseIP(info.Host) == nil {
		cp.hostIsIP = true
		cp.ticker = time.NewTicker(cp.resolutionFrequency)
		cp.stop = make(chan struct{})
		cp.wg.Add(1)
		go func() {
			defer cp.wg.Done()
			for {
				select {
				case _ = <-cp.ticker.C:
					cp.refreshdns()
				case <-cp.stop:
					return
				}
			}

		}()
	}
}

// connect is used by the resource pool to create a new Resource.
func (cp *ConnectionPool) connect() (pools.Resource, error) {
	c, err := NewDBConnection(cp.info, cp.mysqlStats)
	if err != nil {
		return nil, err
	}
	return &PooledDBConnection{
		DBConnection: c,
		pool:         cp,
	}, nil
}

// Close will close the pool and wait for connections to be returned before
// exiting.
func (cp *ConnectionPool) Close() {
	p := cp.pool()
	if p == nil {
		return
	}
	// We should not hold the lock while calling Close
	// because it waits for connections to be returned.
	p.Close()
	cp.mu.Lock()
	cp.connections = nil
	cp.addresses = nil
	cp.hostIsIP = false
	if cp.ticker != nil {
		cp.ticker.Stop()
		close(cp.stop)
	}
	cp.mu.Unlock()
	cp.wg.Wait()
}

// Get returns a connection.
// You must call Recycle on the PooledDBConnection once done.
func (cp *ConnectionPool) Get(ctx context.Context) (*PooledDBConnection, error) {
	p := cp.pool()
	if p == nil {
		return nil, ErrConnPoolClosed
	}
	r, err := p.Get(ctx)
	if err != nil {
		return nil, err
	}

	// Check that the RemoteAddr is still a valid Address
	if cp.resolutionFrequency > 0 &&
		cp.hostIsIP &&
		!cp.validAddress(net.ParseIP(r.(*PooledDBConnection).RemoteAddr().String())) {
		err := r.(*PooledDBConnection).Reconnect()
		if err != nil {
			p.Put(r)
			return nil, err
		}
	}
	return r.(*PooledDBConnection), nil
}

// Put puts a connection into the pool.
func (cp *ConnectionPool) Put(conn *PooledDBConnection) {
	p := cp.pool()
	if p == nil {
		panic(ErrConnPoolClosed)
	}
	if conn == nil {
		// conn has a type, if we just Put(conn), we end up
		// putting an interface with a nil value, that is not
		// equal to a nil value. So just put a plain nil.
		p.Put(nil)
		return
	}
	p.Put(conn)
}

// SetCapacity alters the size of the pool at runtime.
func (cp *ConnectionPool) SetCapacity(capacity int) (err error) {
	cp.mu.Lock()
	defer cp.mu.Unlock()
	if cp.connections != nil {
		err = cp.connections.SetCapacity(capacity)
		if err != nil {
			return err
		}
	}
	cp.capacity = capacity
	return nil
}

// SetIdleTimeout sets the idleTimeout on the pool.
func (cp *ConnectionPool) SetIdleTimeout(idleTimeout time.Duration) {
	cp.mu.Lock()
	defer cp.mu.Unlock()
	if cp.connections != nil {
		cp.connections.SetIdleTimeout(idleTimeout)
	}
	cp.idleTimeout = idleTimeout
}

// StatsJSON returns the pool stats as a JSOn object.
func (cp *ConnectionPool) StatsJSON() string {
	p := cp.pool()
	if p == nil {
		return "{}"
	}
	return p.StatsJSON()
}

// Capacity returns the pool capacity.
func (cp *ConnectionPool) Capacity() int64 {
	p := cp.pool()
	if p == nil {
		return 0
	}
	return p.Capacity()
}

// Available returns the number of available connections in the pool
func (cp *ConnectionPool) Available() int64 {
	p := cp.pool()
	if p == nil {
		return 0
	}
	return p.Available()
}

// Active returns the number of active connections in the pool
func (cp *ConnectionPool) Active() int64 {
	p := cp.pool()
	if p == nil {
		return 0
	}
	return p.Active()
}

// InUse returns the number of in-use connections in the pool
func (cp *ConnectionPool) InUse() int64 {
	p := cp.pool()
	if p == nil {
		return 0
	}
	return p.InUse()
}

// MaxCap returns the maximum size of the pool
func (cp *ConnectionPool) MaxCap() int64 {
	p := cp.pool()
	if p == nil {
		return 0
	}
	return p.MaxCap()
}

// WaitCount returns how many clients are waiting for a connection
func (cp *ConnectionPool) WaitCount() int64 {
	p := cp.pool()
	if p == nil {
		return 0
	}
	return p.WaitCount()
}

// WaitTime return the pool WaitTime.
func (cp *ConnectionPool) WaitTime() time.Duration {
	p := cp.pool()
	if p == nil {
		return 0
	}
	return p.WaitTime()
}

// IdleTimeout returns the idle timeout for the pool.
func (cp *ConnectionPool) IdleTimeout() time.Duration {
	p := cp.pool()
	if p == nil {
		return 0
	}
	return p.IdleTimeout()
}

// IdleClosed returns the number of closed connections for the pool.
func (cp *ConnectionPool) IdleClosed() int64 {
	p := cp.pool()
	if p == nil {
		return 0
	}
	return p.IdleClosed()
}
<commit_msg>Renaming flag for IP to more logical name<commit_after>/*
Copyright 2017 Google Inc.

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 dbconnpool exposes a single DBConnection object
with wrapped access to a single DB connection, and a ConnectionPool
object to pool these DBConnections.
*/
package dbconnpool

import (
	"errors"
	"net"
	"sync"
	"time"

	"golang.org/x/net/context"

	"vitess.io/vitess/go/mysql"
	"vitess.io/vitess/go/pools"
	"vitess.io/vitess/go/stats"
	"vitess.io/vitess/go/vt/log"
)

var (
	// ErrConnPoolClosed is returned if the connection pool is closed.
	ErrConnPoolClosed = errors.New("connection pool is closed")
	// usedNames is for preventing expvar from panicking. Tests
	// create pool objects multiple time. If a name was previously
	// used, expvar initialization is skipped.
	// TODO(sougou): Find a way to still crash if this happened
	// through non-test code.
	usedNames = make(map[string]bool)
)

// ConnectionPool re-exposes ResourcePool as a pool of
// PooledDBConnection objects.
type ConnectionPool struct {
	mu                  sync.Mutex
	connections         *pools.ResourcePool
	capacity            int
	idleTimeout         time.Duration
	resolutionFrequency time.Duration

	// info and mysqlStats are set at Open() time
	info      *mysql.ConnParams
	addresses []net.IP

	ticker      *time.Ticker
	stop        chan struct{}
	wg          sync.WaitGroup
	hostIsNotIP bool

	mysqlStats *stats.Timings
}

// NewConnectionPool creates a new ConnectionPool. The name is used
// to publish stats only.
func NewConnectionPool(name string, capacity int, idleTimeout time.Duration, dnsResolutionFrequency time.Duration) *ConnectionPool {
	cp := &ConnectionPool{capacity: capacity, idleTimeout: idleTimeout, resolutionFrequency: dnsResolutionFrequency}
	if name == "" || usedNames[name] {
		return cp
	}
	usedNames[name] = true
	stats.NewGaugeFunc(name+"Capacity", "Connection pool capacity", cp.Capacity)
	stats.NewGaugeFunc(name+"Available", "Connection pool available", cp.Available)
	stats.NewGaugeFunc(name+"Active", "Connection pool active", cp.Active)
	stats.NewGaugeFunc(name+"InUse", "Connection pool in-use", cp.InUse)
	stats.NewGaugeFunc(name+"MaxCap", "Connection pool max cap", cp.MaxCap)
	stats.NewCounterFunc(name+"WaitCount", "Connection pool wait count", cp.WaitCount)
	stats.NewCounterDurationFunc(name+"WaitTime", "Connection pool wait time", cp.WaitTime)
	stats.NewGaugeDurationFunc(name+"IdleTimeout", "Connection pool idle timeout", cp.IdleTimeout)
	stats.NewGaugeFunc(name+"IdleClosed", "Connection pool idle closed", cp.IdleClosed)
	return cp
}

func (cp *ConnectionPool) pool() (p *pools.ResourcePool) {
	cp.mu.Lock()
	p = cp.connections
	cp.mu.Unlock()
	return p
}

func (cp *ConnectionPool) refreshdns() {
	cp.mu.Lock()
	host := cp.info.Host
	cp.mu.Unlock()

	addrs, err := net.LookupHost(host)
	if err != nil {
		log.Errorf("Error refreshing connection dns name: (%v)", err)
		return
	}
	naddr := make([]net.IP, len(addrs))
	for i, a := range addrs {
		naddr[i] = net.ParseIP(a)
	}
	cp.mu.Lock()
	cp.addresses = naddr
	cp.mu.Unlock()
}

func (cp *ConnectionPool) validAddress(addr net.IP) bool {
	cp.mu.Lock()
	defer cp.mu.Unlock()

	// If we have no valid addresses we always return true
	if len(cp.addresses) == 0 {
		return true
	}

	// Check each address to see if the current RemoteAddr is in the set
	for _, a := range cp.addresses {
		if addr.Equal(a) {
			return true
		}
	}
	return false
}

// Open must be call before starting to use the pool.
//
// For instance:
// mysqlStats := stats.NewTimings("Mysql")
// pool := dbconnpool.NewConnectionPool("name", 10, 30*time.Second)
// pool.Open(info, mysqlStats)
// ...
// conn, err := pool.Get()
// ...
func (cp *ConnectionPool) Open(info *mysql.ConnParams, mysqlStats *stats.Timings) {
	cp.mu.Lock()
	defer cp.mu.Unlock()
	cp.info = info
	cp.mysqlStats = mysqlStats
	cp.connections = pools.NewResourcePool(cp.connect, cp.capacity, cp.capacity, cp.idleTimeout)
	// Check if we need to resolve a hostname (The Host is not just an IP  address).
	if cp.resolutionFrequency > 0 && net.ParseIP(info.Host) == nil {
		cp.hostIsNotIP = true
		cp.ticker = time.NewTicker(cp.resolutionFrequency)
		cp.stop = make(chan struct{})
		cp.wg.Add(1)
		go func() {
			defer cp.wg.Done()
			for {
				select {
				case _ = <-cp.ticker.C:
					cp.refreshdns()
				case <-cp.stop:
					return
				}
			}

		}()
	}
}

// connect is used by the resource pool to create a new Resource.
func (cp *ConnectionPool) connect() (pools.Resource, error) {
	c, err := NewDBConnection(cp.info, cp.mysqlStats)
	if err != nil {
		return nil, err
	}
	return &PooledDBConnection{
		DBConnection: c,
		pool:         cp,
	}, nil
}

// Close will close the pool and wait for connections to be returned before
// exiting.
func (cp *ConnectionPool) Close() {
	p := cp.pool()
	if p == nil {
		return
	}
	// We should not hold the lock while calling Close
	// because it waits for connections to be returned.
	p.Close()
	cp.mu.Lock()
	cp.connections = nil
	cp.addresses = nil
	cp.hostIsNotIP = false
	if cp.ticker != nil {
		cp.ticker.Stop()
		close(cp.stop)
	}
	cp.mu.Unlock()
	cp.wg.Wait()
}

// Get returns a connection.
// You must call Recycle on the PooledDBConnection once done.
func (cp *ConnectionPool) Get(ctx context.Context) (*PooledDBConnection, error) {
	p := cp.pool()
	if p == nil {
		return nil, ErrConnPoolClosed
	}
	r, err := p.Get(ctx)
	if err != nil {
		return nil, err
	}

	// Check that the RemoteAddr is still a valid Address
	if cp.resolutionFrequency > 0 &&
		cp.hostIsNotIP &&
		!cp.validAddress(net.ParseIP(r.(*PooledDBConnection).RemoteAddr().String())) {
		err := r.(*PooledDBConnection).Reconnect()
		if err != nil {
			p.Put(r)
			return nil, err
		}
	}
	return r.(*PooledDBConnection), nil
}

// Put puts a connection into the pool.
func (cp *ConnectionPool) Put(conn *PooledDBConnection) {
	p := cp.pool()
	if p == nil {
		panic(ErrConnPoolClosed)
	}
	if conn == nil {
		// conn has a type, if we just Put(conn), we end up
		// putting an interface with a nil value, that is not
		// equal to a nil value. So just put a plain nil.
		p.Put(nil)
		return
	}
	p.Put(conn)
}

// SetCapacity alters the size of the pool at runtime.
func (cp *ConnectionPool) SetCapacity(capacity int) (err error) {
	cp.mu.Lock()
	defer cp.mu.Unlock()
	if cp.connections != nil {
		err = cp.connections.SetCapacity(capacity)
		if err != nil {
			return err
		}
	}
	cp.capacity = capacity
	return nil
}

// SetIdleTimeout sets the idleTimeout on the pool.
func (cp *ConnectionPool) SetIdleTimeout(idleTimeout time.Duration) {
	cp.mu.Lock()
	defer cp.mu.Unlock()
	if cp.connections != nil {
		cp.connections.SetIdleTimeout(idleTimeout)
	}
	cp.idleTimeout = idleTimeout
}

// StatsJSON returns the pool stats as a JSOn object.
func (cp *ConnectionPool) StatsJSON() string {
	p := cp.pool()
	if p == nil {
		return "{}"
	}
	return p.StatsJSON()
}

// Capacity returns the pool capacity.
func (cp *ConnectionPool) Capacity() int64 {
	p := cp.pool()
	if p == nil {
		return 0
	}
	return p.Capacity()
}

// Available returns the number of available connections in the pool
func (cp *ConnectionPool) Available() int64 {
	p := cp.pool()
	if p == nil {
		return 0
	}
	return p.Available()
}

// Active returns the number of active connections in the pool
func (cp *ConnectionPool) Active() int64 {
	p := cp.pool()
	if p == nil {
		return 0
	}
	return p.Active()
}

// InUse returns the number of in-use connections in the pool
func (cp *ConnectionPool) InUse() int64 {
	p := cp.pool()
	if p == nil {
		return 0
	}
	return p.InUse()
}

// MaxCap returns the maximum size of the pool
func (cp *ConnectionPool) MaxCap() int64 {
	p := cp.pool()
	if p == nil {
		return 0
	}
	return p.MaxCap()
}

// WaitCount returns how many clients are waiting for a connection
func (cp *ConnectionPool) WaitCount() int64 {
	p := cp.pool()
	if p == nil {
		return 0
	}
	return p.WaitCount()
}

// WaitTime return the pool WaitTime.
func (cp *ConnectionPool) WaitTime() time.Duration {
	p := cp.pool()
	if p == nil {
		return 0
	}
	return p.WaitTime()
}

// IdleTimeout returns the idle timeout for the pool.
func (cp *ConnectionPool) IdleTimeout() time.Duration {
	p := cp.pool()
	if p == nil {
		return 0
	}
	return p.IdleTimeout()
}

// IdleClosed returns the number of closed connections for the pool.
func (cp *ConnectionPool) IdleClosed() int64 {
	p := cp.pool()
	if p == nil {
		return 0
	}
	return p.IdleClosed()
}
<|endoftext|>


<commit_before>package faketopo

import (
	"fmt"
	"testing"
	"time"

	"github.com/youtube/vitess/go/vt/key"
	"github.com/youtube/vitess/go/vt/logutil"
	"github.com/youtube/vitess/go/vt/mysqlctl"
	"github.com/youtube/vitess/go/vt/tabletmanager/tmclient"
	"github.com/youtube/vitess/go/vt/topo"
	"github.com/youtube/vitess/go/vt/wrangler"
	"golang.org/x/net/context"
)

const (
	// TestShard is the shard we use in tests
	TestShard = "0"

	// TestKeyspace is the keyspace we use in tests
	TestKeyspace = "test_keyspace"
)

func newKeyRange(value string) key.KeyRange {
	_, result, err := topo.ValidateShardName(value)
	if err != nil {
		panic(err)
	}
	return result
}

type tabletPack struct {
	*topo.Tablet
	mysql *mysqlctl.FakeMysqlDaemon
}

// Fixture is a fixture that provides a fresh topology, to which you
// can add tablets that react to events and have fake MySQL
// daemons. It uses an in memory fake ZooKeeper to store its
// data. When you are done with the fixture you have to call its
// TearDown method.
type Fixture struct {
	*testing.T
	tablets  map[int]*tabletPack
	done     chan struct{}
	Topo     topo.Server
	Wrangler *wrangler.Wrangler
}

// New creates a topology fixture.
func New(t *testing.T, logger logutil.Logger, ts topo.Server, cells []string) *Fixture {
	wr := wrangler.New(logger, ts, tmclient.NewTabletManagerClient(), 1*time.Second)

	return &Fixture{
		T:        t,
		Topo:     ts,
		Wrangler: wr,
		done:     make(chan struct{}, 1),
		tablets:  make(map[int]*tabletPack),
	}
}

// TearDown releases any resources used by the fixture.
func (fix *Fixture) TearDown() {
	close(fix.done)
}

// AddTablet adds a new tablet to the topology and starts its event
// loop.
func (fix *Fixture) AddTablet(uid int, cell string, tabletType topo.TabletType) *topo.Tablet {
	tablet := &topo.Tablet{
		Alias:    topo.TabletAlias{Cell: cell, Uid: uint32(uid)},
		Hostname: fmt.Sprintf("%vbsr%v", cell, uid),
		IPAddr:   fmt.Sprintf("212.244.218.%v", uid),
		Portmap: map[string]int{
			"vt":    3333 + 10*uid,
			"mysql": 3334 + 10*uid,
		},
		Keyspace: TestKeyspace,
		Type:     tabletType,
		Shard:    TestShard,
		KeyRange: newKeyRange(TestShard),
	}

	if err := fix.Wrangler.InitTablet(context.Background(), tablet, true, true, false); err != nil {
		fix.Fatalf("CreateTablet: %v", err)
	}
	mysqlDaemon := &mysqlctl.FakeMysqlDaemon{}
	mysqlDaemon.MysqlPort = 3334 + 10*uid

	pack := &tabletPack{Tablet: tablet, mysql: mysqlDaemon}
	fix.tablets[uid] = pack

	return tablet
}

// GetTablet returns a fresh copy of the tablet identified by uid.
func (fix *Fixture) GetTablet(uid int) *topo.TabletInfo {
	tablet, ok := fix.tablets[uid]
	if !ok {
		panic("bad tablet uid")
	}
	ti, err := fix.Topo.GetTablet(context.Background(), tablet.Alias)
	if err != nil {
		fix.Fatalf("GetTablet %v: %v", tablet.Alias, err)
	}
	return ti

}
<commit_msg>Removing topo/faketopo/fixture.go, has a nasty dependency on wrangler. It was only used in one place, copying the relevant code there. For higher level unit tests, wrangler/testlib is preferred.<commit_after><|endoftext|>


<commit_before>package ipc

import (
	"sync"
	"testing"
	"time"

	"veyron/runtimes/google/testing/mocks/runtime"
	"veyron/runtimes/google/vtrace"

	"veyron2/context"
)

// We need a special way to create contexts for tests.  We
// can't create a real runtime in the runtime implementation
// so we use a fake one that panics if used.  The runtime
// implementation should not ever use the Runtime from a context.
func testContext() context.T {
	ctx := InternalNewContext(&runtime.PanicRuntime{})
	ctx, _ = vtrace.WithNewSpan(ctx, "Root")
	return ctx
}

func testCancel(t *testing.T, ctx context.T, cancel context.CancelFunc) {
	select {
	case <-ctx.Done():
		t.Errorf("Done closed when deadline not yet passed")
	default:
	}
	ch := make(chan bool, 0)
	go func() {
		cancel()
		close(ch)
	}()
	select {
	case <-ch:
	case <-time.After(3 * time.Second):
		t.Fatal("timed out witing for cancel.")
	}

	select {
	case <-ctx.Done():
	case <-time.After(3 * time.Second):
		t.Fatal("timed out witing for cancellation.")
	}
	if err := ctx.Err(); err != context.Canceled {
		t.Errorf("Unexpected error want %v, got %v", context.Canceled, err)
	}
}

func TestCancelContext(t *testing.T) {
	ctx, cancel := testContext().WithCancel()
	testCancel(t, ctx, cancel)
}

func TestMultiLevelCancelContext(t *testing.T) {
	c0, c0Cancel := testContext().WithCancel()
	c1, _ := c0.WithCancel()
	c2, _ := c1.WithCancel()
	c3, _ := c2.WithCancel()
	testCancel(t, c3, c0Cancel)
}

type nonStandardContext struct {
	context.T
}

func (n *nonStandardContext) WithCancel() (ctx context.T, cancel context.CancelFunc) {
	return newCancelContext(n)
}
func (n *nonStandardContext) WithDeadline(deadline time.Time) (context.T, context.CancelFunc) {
	return newDeadlineContext(n, deadline)
}
func (n *nonStandardContext) WithTimeout(timeout time.Duration) (context.T, context.CancelFunc) {
	return newDeadlineContext(n, time.Now().Add(timeout))
}
func (n *nonStandardContext) WithValue(key interface{}, val interface{}) context.T {
	return newValueContext(n, key, val)
}

func TestCancelContextWithNonStandard(t *testing.T) {
	c0, c0Cancel := testContext().WithCancel()
	c1 := &nonStandardContext{c0}
	c2 := &nonStandardContext{c1}
	c3, _ := c2.WithCancel()
	testCancel(t, c3, c0Cancel)
}

func testDeadline(t *testing.T, ctx context.T, start time.Time, desiredTimeout time.Duration) {
	<-ctx.Done()
	if delta := time.Now().Sub(start); delta < desiredTimeout {
		t.Errorf("Deadline too short want %s got %s", desiredTimeout, delta)
	}
	if err := ctx.Err(); err != context.DeadlineExceeded {
		t.Errorf("Unexpected error want %s, got %s", context.DeadlineExceeded, err)
	}
}

func TestDeadlineContext(t *testing.T) {
	cases := []time.Duration{
		10 * time.Millisecond,
		0,
	}
	for _, desiredTimeout := range cases {
		start := time.Now()
		ctx, _ := testContext().WithDeadline(start.Add(desiredTimeout))
		testDeadline(t, ctx, start, desiredTimeout)
	}

	ctx, cancel := testContext().WithDeadline(time.Now().Add(100 * time.Hour))
	testCancel(t, ctx, cancel)
}

func TestDeadlineContextWithRace(t *testing.T) {
	ctx, cancel := testContext().WithDeadline(time.Now().Add(100 * time.Hour))
	var wg sync.WaitGroup
	wg.Add(10)
	for i := 0; i < 10; i++ {
		go func() {
			cancel()
			wg.Done()
		}()
	}
	wg.Wait()
	<-ctx.Done()
	if err := ctx.Err(); err != context.Canceled {
		t.Errorf("Unexpected error want %v, got %v", context.Canceled, err)
	}
}

func TestValueContext(t *testing.T) {
	type testContextKey int
	const (
		key1 = testContextKey(iota)
		key2
		key3
		key4
	)
	const (
		val1 = iota
		val2
		val3
	)
	ctx1 := testContext().WithValue(key1, val1)
	ctx2 := ctx1.WithValue(key2, val2)
	ctx3 := ctx2.WithValue(key3, val3)

	expected := map[interface{}]interface{}{
		key1: val1,
		key2: val2,
		key3: val3,
		key4: nil,
	}
	for k, v := range expected {
		if got := ctx3.Value(k); got != v {
			t.Errorf("Got wrong value for %v: want %v got %v", k, v, got)
		}
	}

}
<commit_msg>Set a reasonable deadline for the tests to see whether it fixes the TestProxy failures.<commit_after>package ipc

import (
	"sync"
	"testing"
	"time"

	"veyron/runtimes/google/testing/mocks/runtime"
	"veyron/runtimes/google/vtrace"

	"veyron2/context"
)

// We need a special way to create contexts for tests.  We
// can't create a real runtime in the runtime implementation
// so we use a fake one that panics if used.  The runtime
// implementation should not ever use the Runtime from a context.
func testContext() context.T {
	ctx := InternalNewContext(&runtime.PanicRuntime{})
	ctx, _ = vtrace.WithNewSpan(ctx, "Root")
	ctx, _ = ctx.WithDeadline(time.Now().Add(20 * time.Second))
	return ctx
}

func testCancel(t *testing.T, ctx context.T, cancel context.CancelFunc) {
	select {
	case <-ctx.Done():
		t.Errorf("Done closed when deadline not yet passed")
	default:
	}
	ch := make(chan bool, 0)
	go func() {
		cancel()
		close(ch)
	}()
	select {
	case <-ch:
	case <-time.After(3 * time.Second):
		t.Fatal("timed out witing for cancel.")
	}

	select {
	case <-ctx.Done():
	case <-time.After(3 * time.Second):
		t.Fatal("timed out witing for cancellation.")
	}
	if err := ctx.Err(); err != context.Canceled {
		t.Errorf("Unexpected error want %v, got %v", context.Canceled, err)
	}
}

func TestCancelContext(t *testing.T) {
	ctx, cancel := testContext().WithCancel()
	testCancel(t, ctx, cancel)
}

func TestMultiLevelCancelContext(t *testing.T) {
	c0, c0Cancel := testContext().WithCancel()
	c1, _ := c0.WithCancel()
	c2, _ := c1.WithCancel()
	c3, _ := c2.WithCancel()
	testCancel(t, c3, c0Cancel)
}

type nonStandardContext struct {
	context.T
}

func (n *nonStandardContext) WithCancel() (ctx context.T, cancel context.CancelFunc) {
	return newCancelContext(n)
}
func (n *nonStandardContext) WithDeadline(deadline time.Time) (context.T, context.CancelFunc) {
	return newDeadlineContext(n, deadline)
}
func (n *nonStandardContext) WithTimeout(timeout time.Duration) (context.T, context.CancelFunc) {
	return newDeadlineContext(n, time.Now().Add(timeout))
}
func (n *nonStandardContext) WithValue(key interface{}, val interface{}) context.T {
	return newValueContext(n, key, val)
}

func TestCancelContextWithNonStandard(t *testing.T) {
	c0, c0Cancel := testContext().WithCancel()
	c1 := &nonStandardContext{c0}
	c2 := &nonStandardContext{c1}
	c3, _ := c2.WithCancel()
	testCancel(t, c3, c0Cancel)
}

func testDeadline(t *testing.T, ctx context.T, start time.Time, desiredTimeout time.Duration) {
	<-ctx.Done()
	if delta := time.Now().Sub(start); delta < desiredTimeout {
		t.Errorf("Deadline too short want %s got %s", desiredTimeout, delta)
	}
	if err := ctx.Err(); err != context.DeadlineExceeded {
		t.Errorf("Unexpected error want %s, got %s", context.DeadlineExceeded, err)
	}
}

func TestDeadlineContext(t *testing.T) {
	cases := []time.Duration{
		10 * time.Millisecond,
		0,
	}
	for _, desiredTimeout := range cases {
		start := time.Now()
		ctx, _ := testContext().WithDeadline(start.Add(desiredTimeout))
		testDeadline(t, ctx, start, desiredTimeout)
	}

	ctx, cancel := testContext().WithDeadline(time.Now().Add(100 * time.Hour))
	testCancel(t, ctx, cancel)
}

func TestDeadlineContextWithRace(t *testing.T) {
	ctx, cancel := testContext().WithDeadline(time.Now().Add(100 * time.Hour))
	var wg sync.WaitGroup
	wg.Add(10)
	for i := 0; i < 10; i++ {
		go func() {
			cancel()
			wg.Done()
		}()
	}
	wg.Wait()
	<-ctx.Done()
	if err := ctx.Err(); err != context.Canceled {
		t.Errorf("Unexpected error want %v, got %v", context.Canceled, err)
	}
}

func TestValueContext(t *testing.T) {
	type testContextKey int
	const (
		key1 = testContextKey(iota)
		key2
		key3
		key4
	)
	const (
		val1 = iota
		val2
		val3
	)
	ctx1 := testContext().WithValue(key1, val1)
	ctx2 := ctx1.WithValue(key2, val2)
	ctx3 := ctx2.WithValue(key3, val3)

	expected := map[interface{}]interface{}{
		key1: val1,
		key2: val2,
		key3: val3,
		key4: nil,
	}
	for k, v := range expected {
		if got := ctx3.Value(k); got != v {
			t.Errorf("Got wrong value for %v: want %v got %v", k, v, got)
		}
	}

}
<|endoftext|>