<commit_before>package aero

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"mime"
	"net/http"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/OneOfOne/xxhash"
	"github.com/aerogo/session"
	"github.com/fatih/color"
	"github.com/julienschmidt/httprouter"
	cache "github.com/patrickmn/go-cache"
	"github.com/tomasen/realip"
	"github.com/valyala/fasthttp"
)

// This should be close to the MTU size of a TCP packet.
// Regarding performance it makes no sense to compress smaller files.
// Bandwidth can be saved however the savings are minimal for small files
// and the overhead of compressing can lead up to a 75% reduction
// in server speed under high load. Therefore in this case
// we're trying to optimize for performance, not bandwidth.
const gzipThreshold = 1450

const (
	serverHeader                  = "Server"
	server                        = "Aero"
	cacheControlHeader            = "Cache-Control"
	cacheControlAlwaysValidate    = "must-revalidate"
	cacheControlMedia             = "public, max-age=864000"
	contentTypeOptionsHeader      = "X-Content-Type-Options"
	contentTypeOptions            = "nosniff"
	xssProtectionHeader           = "X-XSS-Protection"
	xssProtection                 = "1; mode=block"
	etagHeader                    = "ETag"
	contentTypeHeader             = "Content-Type"
	contentTypeHTML               = "text/html; charset=utf-8"
	contentTypeJSON               = "application/json; charset=utf-8"
	contentTypePlainText          = "text/plain; charset=utf-8"
	contentEncodingHeader         = "Content-Encoding"
	contentEncodingGzip           = "gzip"
	contentLengthHeader           = "Content-Length"
	responseTimeHeader            = "X-Response-Time"
	ifNoneMatchHeader             = "If-None-Match"
	xFrameOptionsHeader           = "X-Frame-Options"
	xFrameOptions                 = "SAMEORIGIN"
	referrerPolicyHeader          = "Referrer-Policy"
	referrerPolicySameOrigin      = "no-referrer"
	strictTransportSecurityHeader = "Strict-Transport-Security"
	strictTransportSecurity       = "max-age=31536000; includeSubDomains; preload"
	contentSecurityPolicyHeader   = "Content-Security-Policy"
)

// Context ...
type Context struct {
	// net/http
	request  *http.Request
	response http.ResponseWriter
	params   httprouter.Params

	// A pointer to the application this request occured on.
	App *Application

	// Status code
	StatusCode int

	// Start time
	start time.Time

	// User session
	session *session.Session
}

// Handle ...
type Handle func(*Context) string

// Session returns the session of the context or creates and caches a new session.
func (ctx *Context) Session() *session.Session {
	// Return cached session if available.
	if ctx.session != nil {
		return ctx.session
	}

	// Check if the client has a session cookie already.
	cookie, err := ctx.request.Cookie("sid")

	if err == nil {
		sid := cookie.Value

		if session.IsValidID(sid) {
			ctx.session, err = ctx.App.Sessions.Store.Get(sid)

			if err != nil {
				color.Red(err.Error())
			}

			if ctx.session != nil {
				return ctx.session
			}
		}
	}

	// Create a new session
	ctx.session = ctx.App.Sessions.New()

	// Create a session cookie in the client
	ctx.createSessionCookie()

	return ctx.session
}

// createSessionCookie creates a session cookie in the client.
func (ctx *Context) createSessionCookie() {
	sessionCookie := http.Cookie{
		Name:     "sid",
		Value:    ctx.session.ID(),
		HttpOnly: true,
		Secure:   true,
		MaxAge:   ctx.App.Sessions.Duration,
		Path:     "/",
	}

	http.SetCookie(ctx.response, &sessionCookie)

	// HACK: Add SameSite attribute
	// Remove this once it's available inside http.Cookie
	cookieData := ctx.response.Header().Get("Set-Cookie")
	cookieData += "; SameSite=lax"
	ctx.response.Header().Set("Set-Cookie", cookieData)
}

// HasSession indicates whether the client has a valid session or not.
func (ctx *Context) HasSession() bool {
	if ctx.session != nil {
		return true
	}

	cookie, err := ctx.request.Cookie("sid")

	if err != nil || !session.IsValidID(cookie.Value) {
		return false
	}

	ctx.session, _ = ctx.App.Sessions.Store.Get(cookie.Value)

	return ctx.session != nil
}

// JSON encodes the object to a JSON string and responds.
func (ctx *Context) JSON(value interface{}) string {
	bytes, _ := json.Marshal(value)

	ctx.SetResponseHeader(contentTypeHeader, contentTypeJSON)
	return string(bytes)
}

// HTML sends a HTML string.
func (ctx *Context) HTML(html string) string {
	ctx.SetResponseHeader(contentTypeHeader, contentTypeHTML)
	ctx.SetResponseHeader(contentTypeOptionsHeader, contentTypeOptions)
	ctx.SetResponseHeader(xssProtectionHeader, xssProtection)
	ctx.SetResponseHeader(xFrameOptionsHeader, xFrameOptions)
	ctx.SetResponseHeader(referrerPolicyHeader, referrerPolicySameOrigin)

	if ctx.App.Security.Certificate != "" {
		ctx.SetResponseHeader(strictTransportSecurityHeader, strictTransportSecurity)
		ctx.SetResponseHeader(contentSecurityPolicyHeader, ctx.App.contentSecurityPolicy)
	}

	return html
}

// Text sends a plain text string.
func (ctx *Context) Text(text string) string {
	ctx.SetResponseHeader(contentTypeHeader, contentTypePlainText)
	return text
}

// File sends the contents of a local file and determines its mime type by extension.
func (ctx *Context) File(file string) string {
	extension := filepath.Ext(file)
	mimeType := mime.TypeByExtension(extension)
	data, _ := ioutil.ReadFile(file)

	if mimeType == "" {
		mimeType = http.DetectContentType(data)
	}

	ctx.SetResponseHeader(contentTypeHeader, mimeType)
	return string(data)
}

// TryWebP tries to serve a WebP image but will fall back to the specified extension if needed.
func (ctx *Context) TryWebP(path string, extension string) string {
	if ctx.CanUseWebP() {
		extension = ".webp"
	}

	return ctx.File(path + extension)
}

// Error should be used for sending error messages to the user.
func (ctx *Context) Error(statusCode int, explanation string, err error) string {
	ctx.StatusCode = statusCode
	ctx.SetResponseHeader(contentTypeHeader, contentTypeHTML)
	// ctx.App.Logger.Error(
	// 	color.RedString(explanation),
	// 	zap.String("error", err.Error()),
	// 	zap.String("url", ctx.request.RequestURI),
	// )
	if err != nil {
		detailed := err.Error()
		color.Red(detailed)
		return fmt.Sprintf("%s (%s)", explanation, detailed)
	}

	return explanation
}

// GetRequestHeader retrieves the value for the request header.
func (ctx *Context) GetRequestHeader(header string) string {
	return ctx.request.Header.Get(header)
}

// SetResponseHeader sets response header to value.
func (ctx *Context) SetResponseHeader(header string, value string) {
	ctx.response.Header().Set(header, value)
}

// URI returns the relative path, e.g. /blog/post/123.
func (ctx *Context) URI() string {
	return ctx.request.URL.Path
}

// SetURI sets the relative path, e.g. /blog/post/123.
func (ctx *Context) SetURI(b string) {
	ctx.request.URL.Path = b
}

// Get retrieves an URL parameter.
func (ctx *Context) Get(param string) string {
	return ctx.params.ByName(param)
}

// GetInt retrieves an URL parameter as an integer.
func (ctx *Context) GetInt(param string) (int, error) {
	return strconv.Atoi(ctx.Get(param))
}

// RequestBody returns the request body as a string.
func (ctx *Context) RequestBody() []byte {
	body, err := ioutil.ReadAll(ctx.request.Body)

	if err != nil {
		panic(err)
	}

	return body
}

// RealIP tries to determine the real IP address of the request.
func (ctx *Context) RealIP() string {
	return realip.RealIP(ctx.request)
}

// UserAgent retrieves the user agent for the given request.
func (ctx *Context) UserAgent() string {
	ctx.request.URL.Query()
	return ctx.request.UserAgent()
}

// Query retrieves the value for the given URL query parameter.
func (ctx *Context) Query(param string) string {
	return ctx.request.URL.Query().Get(param)
}

// Redirect redirects to the given URL using status code 302.
func (ctx *Context) Redirect(url string) string {
	ctx.StatusCode = http.StatusFound
	ctx.SetResponseHeader("Location", url)
	return ""
}

// RedirectPermanently redirects to the given URL and indicates that this is a permanent change using status code 301.
func (ctx *Context) RedirectPermanently(url string) string {
	ctx.StatusCode = http.StatusPermanentRedirect
	ctx.SetResponseHeader("Location", url)
	return ""
}

// CanUseWebP checks the Accept header to find out if WebP is supported by the client's browser.
func (ctx *Context) CanUseWebP() bool {
	accept := ctx.GetRequestHeader("Accept")

	if strings.Index(accept, "image/webp") != -1 {
		return true
	}

	return false
}

// IsMediaResponse returns whether the given context has already set its content type to a media type.
func (ctx *Context) IsMediaResponse() bool {
	contentType := ctx.response.Header().Get(contentTypeHeader)
	return strings.HasPrefix(contentType, "image/") || strings.HasPrefix(contentType, "video/")
}

// Respond responds either with raw code or gzipped if the
// code length is greater than the gzip threshold.
func (ctx *Context) Respond(code string) {
	ctx.RespondBytes(StringToBytesUnsafe(code))
}

// RespondBytes responds either with raw code or gzipped if the
// code length is greater than the gzip threshold. Requires a byte slice.
func (ctx *Context) RespondBytes(b []byte) {
	response := ctx.response
	header := response.Header()
	isMedia := ctx.IsMediaResponse()

	// Headers
	if isMedia {
		header.Set(cacheControlHeader, cacheControlMedia)
	} else {
		header.Set(cacheControlHeader, cacheControlAlwaysValidate)
		header.Set(serverHeader, server)
		header.Set(responseTimeHeader, strconv.FormatInt(time.Since(ctx.start).Nanoseconds()/1000, 10)+" us")
	}

	// Small response
	if len(b) < gzipThreshold {
		header.Set(contentLengthHeader, strconv.Itoa(len(b)))
		response.WriteHeader(ctx.StatusCode)
		response.Write(b)
		return
	}

	// ETag generation
	h := xxhash.NewS64(0)
	h.Write(b)
	etag := strconv.FormatUint(h.Sum64(), 16)

	// If client cache is up to date, send 304 with no response body.
	clientETag := ctx.request.Header.Get(ifNoneMatchHeader)

	if etag == clientETag {
		response.WriteHeader(304)
		return
	}

	// Set ETag
	header.Set(etagHeader, etag)

	// No GZip?
	if !ctx.App.Config.GZip || isMedia {
		header.Set(contentLengthHeader, strconv.Itoa(len(b)))
		response.WriteHeader(ctx.StatusCode)
		response.Write(b)
		return
	}

	// GZip
	header.Set(contentEncodingHeader, contentEncodingGzip)

	if ctx.App.Config.GZipCache {
		cachedResponse, found := ctx.App.gzipCache.Get(etag)

		if found {
			cachedResponseBytes := cachedResponse.([]byte)
			header.Set(contentLengthHeader, strconv.Itoa(len(cachedResponseBytes)))
			response.WriteHeader(ctx.StatusCode)
			response.Write(cachedResponseBytes)
			return
		}
	}

	var buffer bytes.Buffer
	writer := bufio.NewWriter(&buffer)
	fasthttp.WriteGzipLevel(writer, b, 9)
	writer.Flush()
	gzippedBytes := buffer.Bytes()

	header.Set(contentLengthHeader, strconv.Itoa(len(gzippedBytes)))
	response.WriteHeader(ctx.StatusCode)
	response.Write(gzippedBytes)

	if ctx.App.Config.GZipCache {
		ctx.App.gzipCache.Set(etag, gzippedBytes, cache.DefaultExpiration)
	}
}
<commit_msg>Remove SameSite cookie<commit_after>package aero

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"mime"
	"net/http"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/OneOfOne/xxhash"
	"github.com/aerogo/session"
	"github.com/fatih/color"
	"github.com/julienschmidt/httprouter"
	cache "github.com/patrickmn/go-cache"
	"github.com/tomasen/realip"
	"github.com/valyala/fasthttp"
)

// This should be close to the MTU size of a TCP packet.
// Regarding performance it makes no sense to compress smaller files.
// Bandwidth can be saved however the savings are minimal for small files
// and the overhead of compressing can lead up to a 75% reduction
// in server speed under high load. Therefore in this case
// we're trying to optimize for performance, not bandwidth.
const gzipThreshold = 1450

const (
	serverHeader                  = "Server"
	server                        = "Aero"
	cacheControlHeader            = "Cache-Control"
	cacheControlAlwaysValidate    = "must-revalidate"
	cacheControlMedia             = "public, max-age=864000"
	contentTypeOptionsHeader      = "X-Content-Type-Options"
	contentTypeOptions            = "nosniff"
	xssProtectionHeader           = "X-XSS-Protection"
	xssProtection                 = "1; mode=block"
	etagHeader                    = "ETag"
	contentTypeHeader             = "Content-Type"
	contentTypeHTML               = "text/html; charset=utf-8"
	contentTypeJSON               = "application/json; charset=utf-8"
	contentTypePlainText          = "text/plain; charset=utf-8"
	contentEncodingHeader         = "Content-Encoding"
	contentEncodingGzip           = "gzip"
	contentLengthHeader           = "Content-Length"
	responseTimeHeader            = "X-Response-Time"
	ifNoneMatchHeader             = "If-None-Match"
	xFrameOptionsHeader           = "X-Frame-Options"
	xFrameOptions                 = "SAMEORIGIN"
	referrerPolicyHeader          = "Referrer-Policy"
	referrerPolicySameOrigin      = "no-referrer"
	strictTransportSecurityHeader = "Strict-Transport-Security"
	strictTransportSecurity       = "max-age=31536000; includeSubDomains; preload"
	contentSecurityPolicyHeader   = "Content-Security-Policy"
)

// Context ...
type Context struct {
	// net/http
	request  *http.Request
	response http.ResponseWriter
	params   httprouter.Params

	// A pointer to the application this request occured on.
	App *Application

	// Status code
	StatusCode int

	// Start time
	start time.Time

	// User session
	session *session.Session
}

// Handle ...
type Handle func(*Context) string

// Session returns the session of the context or creates and caches a new session.
func (ctx *Context) Session() *session.Session {
	// Return cached session if available.
	if ctx.session != nil {
		return ctx.session
	}

	// Check if the client has a session cookie already.
	cookie, err := ctx.request.Cookie("sid")

	if err == nil {
		sid := cookie.Value

		if session.IsValidID(sid) {
			ctx.session, err = ctx.App.Sessions.Store.Get(sid)

			if err != nil {
				color.Red(err.Error())
			}

			if ctx.session != nil {
				return ctx.session
			}
		}
	}

	// Create a new session
	ctx.session = ctx.App.Sessions.New()

	// Create a session cookie in the client
	ctx.createSessionCookie()

	return ctx.session
}

// createSessionCookie creates a session cookie in the client.
func (ctx *Context) createSessionCookie() {
	sessionCookie := http.Cookie{
		Name:     "sid",
		Value:    ctx.session.ID(),
		HttpOnly: true,
		Secure:   true,
		MaxAge:   ctx.App.Sessions.Duration,
		Path:     "/",
	}

	http.SetCookie(ctx.response, &sessionCookie)

	// HACK: Add SameSite attribute
	// Remove this once it's available inside http.Cookie
	// cookieData := ctx.response.Header().Get("Set-Cookie")
	// cookieData += "; SameSite=lax"
	// ctx.response.Header().Set("Set-Cookie", cookieData)
}

// HasSession indicates whether the client has a valid session or not.
func (ctx *Context) HasSession() bool {
	if ctx.session != nil {
		return true
	}

	cookie, err := ctx.request.Cookie("sid")

	if err != nil || !session.IsValidID(cookie.Value) {
		return false
	}

	ctx.session, _ = ctx.App.Sessions.Store.Get(cookie.Value)

	return ctx.session != nil
}

// JSON encodes the object to a JSON string and responds.
func (ctx *Context) JSON(value interface{}) string {
	bytes, _ := json.Marshal(value)

	ctx.SetResponseHeader(contentTypeHeader, contentTypeJSON)
	return string(bytes)
}

// HTML sends a HTML string.
func (ctx *Context) HTML(html string) string {
	ctx.SetResponseHeader(contentTypeHeader, contentTypeHTML)
	ctx.SetResponseHeader(contentTypeOptionsHeader, contentTypeOptions)
	ctx.SetResponseHeader(xssProtectionHeader, xssProtection)
	ctx.SetResponseHeader(xFrameOptionsHeader, xFrameOptions)
	ctx.SetResponseHeader(referrerPolicyHeader, referrerPolicySameOrigin)

	if ctx.App.Security.Certificate != "" {
		ctx.SetResponseHeader(strictTransportSecurityHeader, strictTransportSecurity)
		ctx.SetResponseHeader(contentSecurityPolicyHeader, ctx.App.contentSecurityPolicy)
	}

	return html
}

// Text sends a plain text string.
func (ctx *Context) Text(text string) string {
	ctx.SetResponseHeader(contentTypeHeader, contentTypePlainText)
	return text
}

// File sends the contents of a local file and determines its mime type by extension.
func (ctx *Context) File(file string) string {
	extension := filepath.Ext(file)
	mimeType := mime.TypeByExtension(extension)
	data, _ := ioutil.ReadFile(file)

	if mimeType == "" {
		mimeType = http.DetectContentType(data)
	}

	ctx.SetResponseHeader(contentTypeHeader, mimeType)
	return string(data)
}

// TryWebP tries to serve a WebP image but will fall back to the specified extension if needed.
func (ctx *Context) TryWebP(path string, extension string) string {
	if ctx.CanUseWebP() {
		extension = ".webp"
	}

	return ctx.File(path + extension)
}

// Error should be used for sending error messages to the user.
func (ctx *Context) Error(statusCode int, explanation string, err error) string {
	ctx.StatusCode = statusCode
	ctx.SetResponseHeader(contentTypeHeader, contentTypeHTML)
	// ctx.App.Logger.Error(
	// 	color.RedString(explanation),
	// 	zap.String("error", err.Error()),
	// 	zap.String("url", ctx.request.RequestURI),
	// )
	if err != nil {
		detailed := err.Error()
		color.Red(detailed)
		return fmt.Sprintf("%s (%s)", explanation, detailed)
	}

	return explanation
}

// GetRequestHeader retrieves the value for the request header.
func (ctx *Context) GetRequestHeader(header string) string {
	return ctx.request.Header.Get(header)
}

// SetResponseHeader sets response header to value.
func (ctx *Context) SetResponseHeader(header string, value string) {
	ctx.response.Header().Set(header, value)
}

// URI returns the relative path, e.g. /blog/post/123.
func (ctx *Context) URI() string {
	return ctx.request.URL.Path
}

// SetURI sets the relative path, e.g. /blog/post/123.
func (ctx *Context) SetURI(b string) {
	ctx.request.URL.Path = b
}

// Get retrieves an URL parameter.
func (ctx *Context) Get(param string) string {
	return ctx.params.ByName(param)
}

// GetInt retrieves an URL parameter as an integer.
func (ctx *Context) GetInt(param string) (int, error) {
	return strconv.Atoi(ctx.Get(param))
}

// RequestBody returns the request body as a string.
func (ctx *Context) RequestBody() []byte {
	body, err := ioutil.ReadAll(ctx.request.Body)

	if err != nil {
		panic(err)
	}

	return body
}

// RealIP tries to determine the real IP address of the request.
func (ctx *Context) RealIP() string {
	return realip.RealIP(ctx.request)
}

// UserAgent retrieves the user agent for the given request.
func (ctx *Context) UserAgent() string {
	ctx.request.URL.Query()
	return ctx.request.UserAgent()
}

// Query retrieves the value for the given URL query parameter.
func (ctx *Context) Query(param string) string {
	return ctx.request.URL.Query().Get(param)
}

// Redirect redirects to the given URL using status code 302.
func (ctx *Context) Redirect(url string) string {
	ctx.StatusCode = http.StatusFound
	ctx.SetResponseHeader("Location", url)
	return ""
}

// RedirectPermanently redirects to the given URL and indicates that this is a permanent change using status code 301.
func (ctx *Context) RedirectPermanently(url string) string {
	ctx.StatusCode = http.StatusPermanentRedirect
	ctx.SetResponseHeader("Location", url)
	return ""
}

// CanUseWebP checks the Accept header to find out if WebP is supported by the client's browser.
func (ctx *Context) CanUseWebP() bool {
	accept := ctx.GetRequestHeader("Accept")

	if strings.Index(accept, "image/webp") != -1 {
		return true
	}

	return false
}

// IsMediaResponse returns whether the given context has already set its content type to a media type.
func (ctx *Context) IsMediaResponse() bool {
	contentType := ctx.response.Header().Get(contentTypeHeader)
	return strings.HasPrefix(contentType, "image/") || strings.HasPrefix(contentType, "video/")
}

// Respond responds either with raw code or gzipped if the
// code length is greater than the gzip threshold.
func (ctx *Context) Respond(code string) {
	ctx.RespondBytes(StringToBytesUnsafe(code))
}

// RespondBytes responds either with raw code or gzipped if the
// code length is greater than the gzip threshold. Requires a byte slice.
func (ctx *Context) RespondBytes(b []byte) {
	response := ctx.response
	header := response.Header()
	isMedia := ctx.IsMediaResponse()

	// Headers
	if isMedia {
		header.Set(cacheControlHeader, cacheControlMedia)
	} else {
		header.Set(cacheControlHeader, cacheControlAlwaysValidate)
		header.Set(serverHeader, server)
		header.Set(responseTimeHeader, strconv.FormatInt(time.Since(ctx.start).Nanoseconds()/1000, 10)+" us")
	}

	// Small response
	if len(b) < gzipThreshold {
		header.Set(contentLengthHeader, strconv.Itoa(len(b)))
		response.WriteHeader(ctx.StatusCode)
		response.Write(b)
		return
	}

	// ETag generation
	h := xxhash.NewS64(0)
	h.Write(b)
	etag := strconv.FormatUint(h.Sum64(), 16)

	// If client cache is up to date, send 304 with no response body.
	clientETag := ctx.request.Header.Get(ifNoneMatchHeader)

	if etag == clientETag {
		response.WriteHeader(304)
		return
	}

	// Set ETag
	header.Set(etagHeader, etag)

	// No GZip?
	if !ctx.App.Config.GZip || isMedia {
		header.Set(contentLengthHeader, strconv.Itoa(len(b)))
		response.WriteHeader(ctx.StatusCode)
		response.Write(b)
		return
	}

	// GZip
	header.Set(contentEncodingHeader, contentEncodingGzip)

	if ctx.App.Config.GZipCache {
		cachedResponse, found := ctx.App.gzipCache.Get(etag)

		if found {
			cachedResponseBytes := cachedResponse.([]byte)
			header.Set(contentLengthHeader, strconv.Itoa(len(cachedResponseBytes)))
			response.WriteHeader(ctx.StatusCode)
			response.Write(cachedResponseBytes)
			return
		}
	}

	var buffer bytes.Buffer
	writer := bufio.NewWriter(&buffer)
	fasthttp.WriteGzipLevel(writer, b, 9)
	writer.Flush()
	gzippedBytes := buffer.Bytes()

	header.Set(contentLengthHeader, strconv.Itoa(len(gzippedBytes)))
	response.WriteHeader(ctx.StatusCode)
	response.Write(gzippedBytes)

	if ctx.App.Config.GZipCache {
		ctx.App.gzipCache.Set(etag, gzippedBytes, cache.DefaultExpiration)
	}
}
<|endoftext|>


<commit_before>package peco

import (
	"bytes"
	"fmt"
	"runtime"
	"sync"
	"testing"
	"time"

	"github.com/nsf/termbox-go"
	"github.com/peco/peco/internal/util"
	"github.com/stretchr/testify/assert"
	"golang.org/x/net/context"
)

type interceptorArgs []interface{}
type interceptor struct {
	m      sync.Mutex
	events map[string][]interceptorArgs
}

func newInterceptor() *interceptor {
	return &interceptor{
		events: make(map[string][]interceptorArgs),
	}
}

func (i *interceptor) reset() {
	i.m.Lock()
	defer i.m.Unlock()

	i.events = make(map[string][]interceptorArgs)
}

func (i *interceptor) record(name string, args []interface{}) {
	i.m.Lock()
	defer i.m.Unlock()

	events := i.events
	v, ok := events[name]
	if !ok {
		v = []interceptorArgs{}
	}

	events[name] = append(v, interceptorArgs(args))
}

func newPeco() *Peco {
	_, file, _, _ := runtime.Caller(0)
	state := New()
	state.Argv = []string{"peco", file}
	state.screen = NewDummyScreen()
	return state
}

type dummyScreen struct {
	*interceptor
	width  int
	height int
	pollCh chan termbox.Event
}

func NewDummyScreen() *dummyScreen {
	return &dummyScreen{
		interceptor: newInterceptor(),
		width:       80,
		height:      10,
		pollCh:      make(chan termbox.Event),
	}
}

func (d dummyScreen) Init() error {
	return nil
}

func (d dummyScreen) Close() error {
	return nil
}

func (d dummyScreen) Print(args PrintArgs) int {
	return screenPrint(d, args)
}

func (d dummyScreen) SendEvent(e termbox.Event) {
	d.pollCh <- e
}

func (d dummyScreen) SetCell(x, y int, ch rune, fg, bg termbox.Attribute) {
	d.record("SetCell", interceptorArgs{x, y, ch, fg, bg})
}
func (d dummyScreen) Flush() error {
	d.record("Flush", interceptorArgs{})
	return nil
}
func (d dummyScreen) PollEvent() chan termbox.Event {
	return d.pollCh
}
func (d dummyScreen) Size() (int, int) {
	return d.width, d.height
}

func TestIDGen(t *testing.T) {
	idgen := newIDGen()
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	go idgen.Run(ctx)

	lines := []*RawLine{}
	for i := 0; i < 1000000; i++ {
		lines = append(lines, NewRawLine(idgen.next(), fmt.Sprintf("%d", i), false))
	}

	sel := NewSelection()
	for _, l := range lines {
		if sel.Has(l) {
			t.Errorf("Collision detected %d", l.ID())
		}
		sel.Add(l)
	}
}

func TestPeco(t *testing.T) {
	p := newPeco()
	ctx, cancel := context.WithCancel(context.Background())
	time.AfterFunc(time.Second, cancel)
	if !assert.NoError(t, p.Run(ctx), "p.Run() succeeds") {
		return
	}
}

type testCauser interface {
	Cause() error
}
type testIgnorableError interface {
	Ignorable() bool
}

func TestPecoHelp(t *testing.T) {
	p := newPeco()
	p.Argv = []string{"peco", "-h"}
	p.Stdout = &bytes.Buffer{}
	ctx, cancel := context.WithCancel(context.Background())
	time.AfterFunc(time.Second, cancel)

	err := p.Run(ctx)
	if !assert.True(t, util.IsIgnorableError(err), "p.Run() should return error with Ignorable() method, and it should return true") {
		return
	}
}
<commit_msg>Add a very very rudimentary test<commit_after>package peco

import (
	"bytes"
	"fmt"
	"runtime"
	"sync"
	"testing"
	"time"

	"github.com/nsf/termbox-go"
	"github.com/peco/peco/internal/util"
	"github.com/stretchr/testify/assert"
	"golang.org/x/net/context"
)

type interceptorArgs []interface{}
type interceptor struct {
	m      sync.Mutex
	events map[string][]interceptorArgs
}

func newInterceptor() *interceptor {
	return &interceptor{
		events: make(map[string][]interceptorArgs),
	}
}

func (i *interceptor) reset() {
	i.m.Lock()
	defer i.m.Unlock()

	i.events = make(map[string][]interceptorArgs)
}

func (i *interceptor) record(name string, args []interface{}) {
	i.m.Lock()
	defer i.m.Unlock()

	events := i.events
	v, ok := events[name]
	if !ok {
		v = []interceptorArgs{}
	}

	events[name] = append(v, interceptorArgs(args))
}

func newPeco() *Peco {
	_, file, _, _ := runtime.Caller(0)
	state := New()
	state.Argv = []string{"peco", file}
	state.screen = NewDummyScreen()
	return state
}

type dummyScreen struct {
	*interceptor
	width  int
	height int
	pollCh chan termbox.Event
}

func NewDummyScreen() *dummyScreen {
	return &dummyScreen{
		interceptor: newInterceptor(),
		width:       80,
		height:      10,
		pollCh:      make(chan termbox.Event),
	}
}

func (d dummyScreen) Init() error {
	return nil
}

func (d dummyScreen) Close() error {
	return nil
}

func (d dummyScreen) Print(args PrintArgs) int {
	return screenPrint(d, args)
}

func (d dummyScreen) SendEvent(e termbox.Event) {
	d.pollCh <- e
}

func (d dummyScreen) SetCell(x, y int, ch rune, fg, bg termbox.Attribute) {
	d.record("SetCell", interceptorArgs{x, y, ch, fg, bg})
}
func (d dummyScreen) Flush() error {
	d.record("Flush", interceptorArgs{})
	return nil
}
func (d dummyScreen) PollEvent() chan termbox.Event {
	return d.pollCh
}
func (d dummyScreen) Size() (int, int) {
	return d.width, d.height
}

func TestIDGen(t *testing.T) {
	idgen := newIDGen()
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	go idgen.Run(ctx)

	lines := []*RawLine{}
	for i := 0; i < 1000000; i++ {
		lines = append(lines, NewRawLine(idgen.next(), fmt.Sprintf("%d", i), false))
	}

	sel := NewSelection()
	for _, l := range lines {
		if sel.Has(l) {
			t.Errorf("Collision detected %d", l.ID())
		}
		sel.Add(l)
	}
}

func TestPeco(t *testing.T) {
	p := newPeco()
	ctx, cancel := context.WithCancel(context.Background())
	time.AfterFunc(time.Second, cancel)
	if !assert.NoError(t, p.Run(ctx), "p.Run() succeeds") {
		return
	}
}

type testCauser interface {
	Cause() error
}
type testIgnorableError interface {
	Ignorable() bool
}

func TestPecoHelp(t *testing.T) {
	p := newPeco()
	p.Argv = []string{"peco", "-h"}
	p.Stdout = &bytes.Buffer{}
	ctx, cancel := context.WithCancel(context.Background())
	time.AfterFunc(time.Second, cancel)

	err := p.Run(ctx)
	if !assert.True(t, util.IsIgnorableError(err), "p.Run() should return error with Ignorable() method, and it should return true") {
		return
	}
}

func TestGHIssue331(t *testing.T) {
	// Note: we should check that the drawing process did not
	// use cached display, but ATM this seemed hard to do,
	// so we just check that the proper fields were populated
	// when peco was instantiated
	ctx, cancel := context.WithCancel(context.Background())
	time.AfterFunc(time.Second, cancel)

	p := newPeco()
	p.Run(ctx)

	if !assert.NotEmpty(t, p.singleKeyJumpPrefixes, "singleKeyJumpPrefixes is not empty") {
		return
	}
	if !assert.NotEmpty(t, p.singleKeyJumpPrefixMap, "singleKeyJumpPrefixMap is not empty") {
		return
	}
}
<|endoftext|>


<commit_before>package transport

import (
	"fmt"
	"strconv"
	"testing"
	"time"

	"github.com/stefankopieczek/gossip/base"
)

type endpoint struct {
	host string
	port uint16
}

var alice endpoint = endpoint{"127.0.0.1", 10862}
var bob endpoint = endpoint{"127.0.0.1", 10863}

func TestMassUDP(t *testing.T) {
	NUM_MSGS := 10000
	from, _ := NewManager("udp")
	to, _ := NewManager("udp")
	to.Listen(fmt.Sprintf("%s:%d", alice.host, alice.port))
	receiver := to.GetChannel()

	receivedIDs := make([]int, 0)
	result := make(chan bool)

	go func() {
	recvloop:
		for {
			select {
			case msg, ok := <-receiver:
				if !ok {
					break recvloop
				}
				id, _ := strconv.ParseInt(msg.GetBody(), 10, 32)
				receivedIDs = append(receivedIDs, int(id))
				if len(receivedIDs) >= NUM_MSGS {
					break recvloop
				}
			case <-time.After(time.Second / 10):
				break recvloop
			}
		}

		if !(len(receivedIDs) == NUM_MSGS) {
			t.Errorf("Error - received an unexpected number of messages: %d", len(receivedIDs))
		} else {
			seenSet := make(map[int]bool)
			for _, val := range receivedIDs {
				if _, match := seenSet[val]; match {
					t.Errorf("Duplicate message received: %d", val)
				}
				seenSet[val] = true
			}
			if len(seenSet) != NUM_MSGS {
				t.Errorf("Unexpected number of messages received: %d", len(seenSet))
			}
		}
		result <- true
	}()

	go func() {
		uri := base.SipUri{User: base.String{"alice"}, Host: "127.0.0.1", Port: nil}
		for ii := 1; ii <= NUM_MSGS; ii++ {
			from.Send(fmt.Sprintf("%s:%d", alice.host, alice.port),
				base.NewRequest(base.ACK, &uri, "SIP/2.0",
					[]base.SipHeader{base.ContentLength(len(fmt.Sprintf("%d", ii)))},
					fmt.Sprintf("%d", ii)))

			if ii%100 == 0 {
				<-time.After(time.Millisecond)
			}
		}
	}()

	_ = <-result
	return
}

func sendAndCheckReceipt(from *Manager, to string,
	receiver chan base.SipMessage,
	msg base.SipMessage, timeout time.Duration) bool {
	from.Send(to, msg)

	select {
	case msgIn, ok := <-receiver:
		if !ok {
			return false
		}

		return msgIn.String() == msg.String()

	case <-time.After(timeout):
		return false
	}
}
<commit_msg>Fix up MassUDP test.<commit_after>package transport

import (
	"fmt"
	"strconv"
	"testing"
	"time"

	"github.com/stefankopieczek/gossip/base"
)

type endpoint struct {
	host string
	port uint16
}

var alice endpoint = endpoint{"127.0.0.1", 10862}
var bob endpoint = endpoint{"127.0.0.1", 10863}

func TestMassUDP(t *testing.T) {
	NUM_MSGS := 10000
	from, _ := NewManager("udp")
	to, _ := NewManager("udp")
	to.Listen(fmt.Sprintf("%s:%d", alice.host, alice.port))
	receiver := to.GetChannel()

	receivedIDs := make([]int, 0)
	result := make(chan bool)

	go func() {
	recvloop:
		for {
			select {
			case msg, ok := <-receiver:
				if !ok {
					break recvloop
				}
				id, _ := strconv.ParseInt(msg.GetBody(), 10, 32)
				receivedIDs = append(receivedIDs, int(id))
				if len(receivedIDs) >= NUM_MSGS {
					break recvloop
				}
			case <-time.After(time.Second / 10):
				break recvloop
			}
		}

		if !(len(receivedIDs) == NUM_MSGS) {
			t.Errorf("Error - received an unexpected number of messages: %d", len(receivedIDs))
		} else {
			seenSet := make(map[int]bool)
			for _, val := range receivedIDs {
				if _, match := seenSet[val]; match {
					t.Errorf("Duplicate message received: %d", val)
				}
				seenSet[val] = true
			}
			if len(seenSet) != NUM_MSGS {
				t.Errorf("Unexpected number of messages received: %d", len(seenSet))
			}
		}
		result <- true
	}()

	go func() {
		uri := base.SipUri{User: base.String{"alice"}, Host: "127.0.0.1", Port: nil, UriParams: base.NewParams(), Headers: base.NewParams()}
		for ii := 1; ii <= NUM_MSGS; ii++ {
			from.Send(fmt.Sprintf("%s:%d", alice.host, alice.port),
				base.NewRequest(base.ACK, &uri, "SIP/2.0",
					[]base.SipHeader{base.ContentLength(len(fmt.Sprintf("%d", ii)))},
					fmt.Sprintf("%d", ii)))

			if ii%100 == 0 {
				<-time.After(time.Millisecond)
			}
		}
	}()

	_ = <-result
	return
}

func sendAndCheckReceipt(from *Manager, to string,
	receiver chan base.SipMessage,
	msg base.SipMessage, timeout time.Duration) bool {
	from.Send(to, msg)

	select {
	case msgIn, ok := <-receiver:
		if !ok {
			return false
		}

		return msgIn.String() == msg.String()

	case <-time.After(timeout):
		return false
	}
}
<|endoftext|>


<commit_before>package winio

import (
	"bufio"
	"io"
	"net"
	"os"
	"syscall"
	"testing"
	"time"
)

var testPipeName = `\\.\pipe\winiotestpipe`

func TestDialUnknownFailsImmediately(t *testing.T) {
	_, err := DialPipe(testPipeName, nil)
	if err.(*os.PathError).Err != syscall.ENOENT {
		t.Fatalf("expected ENOENT got %v", err)
	}
}

func TestDialListenerTimesOut(t *testing.T) {
	l, err := ListenPipe(testPipeName, nil)
	if err != nil {
		t.Fatal(err)
	}
	defer l.Close()
	var d = time.Duration(10 * time.Millisecond)
	_, err = DialPipe(testPipeName, &d)
	if err != ErrTimeout {
		t.Fatalf("expected ErrTimeout, got %v", err)
	}
}

func TestDialAccessDeniedWithRestrictedSD(t *testing.T) {
	c := PipeConfig{
		SecurityDescriptor: "D:P(A;;0x1200FF;;;WD)",
	}
	l, err := ListenPipe(testPipeName, &c)
	if err != nil {
		t.Fatal(err)
	}
	defer l.Close()
	_, err = DialPipe(testPipeName, nil)
	if err.(*os.PathError).Err != syscall.ERROR_ACCESS_DENIED {
		t.Fatalf("expected ERROR_ACCESS_DENIED, got %v", err)
	}
}

func getConnection(cfg *PipeConfig) (client net.Conn, server net.Conn, err error) {
	l, err := ListenPipe(testPipeName, cfg)
	if err != nil {
		return
	}
	defer l.Close()

	type response struct {
		c   net.Conn
		err error
	}
	ch := make(chan response)
	go func() {
		c, err := l.Accept()
		ch <- response{c, err}
	}()

	c, err := DialPipe(testPipeName, nil)
	if err != nil {
		return
	}

	r := <-ch
	if err = r.err; err != nil {
		c.Close()
		return
	}

	client = c
	server = r.c
	return
}

func TestReadTimeout(t *testing.T) {
	c, s, err := getConnection(nil)
	if err != nil {
		t.Fatal(err)
	}
	defer c.Close()
	defer s.Close()

	c.SetReadDeadline(time.Now().Add(10 * time.Millisecond))

	buf := make([]byte, 10)
	_, err = c.Read(buf)
	if err != ErrTimeout {
		t.Fatalf("expected ErrTimeout, got %v", err)
	}
}

func server(l net.Listener, ch chan int) {
	c, err := l.Accept()
	if err != nil {
		panic(err)
	}
	rw := bufio.NewReadWriter(bufio.NewReader(c), bufio.NewWriter(c))
	s, err := rw.ReadString('\n')
	if err != nil {
		panic(err)
	}
	_, err = rw.WriteString("got " + s)
	if err != nil {
		panic(err)
	}
	err = rw.Flush()
	if err != nil {
		panic(err)
	}
	c.Close()
	ch <- 1
}

func TestFullListenDialReadWrite(t *testing.T) {
	l, err := ListenPipe(testPipeName, nil)
	if err != nil {
		t.Fatal(err)
	}
	defer l.Close()

	ch := make(chan int)
	go server(l, ch)

	c, err := DialPipe(testPipeName, nil)
	if err != nil {
		t.Fatal(err)
	}
	defer c.Close()

	rw := bufio.NewReadWriter(bufio.NewReader(c), bufio.NewWriter(c))
	_, err = rw.WriteString("hello world\n")
	if err != nil {
		t.Fatal(err)
	}
	err = rw.Flush()
	if err != nil {
		t.Fatal(err)
	}

	s, err := rw.ReadString('\n')
	if err != nil {
		t.Fatal(err)
	}
	ms := "got hello world\n"
	if s != ms {
		t.Errorf("expected '%s', got '%s'", ms, s)
	}

	<-ch
}

func TestCloseAbortsListen(t *testing.T) {
	l, err := ListenPipe(testPipeName, nil)
	if err != nil {
		t.Fatal(err)
	}

	ch := make(chan error)
	go func() {
		_, err := l.Accept()
		ch <- err
	}()

	time.Sleep(30 * time.Millisecond)
	l.Close()

	err = <-ch
	if err != ErrPipeListenerClosed {
		t.Fatalf("expected ErrPipeListenerClosed, got %v", err)
	}
}

func ensureEOFOnClose(t *testing.T, r io.Reader, w io.Closer) {
	b := make([]byte, 10)
	w.Close()
	n, err := r.Read(b)
	if n > 0 {
		t.Errorf("unexpected byte count %d", n)
	}
	if err != io.EOF {
		t.Errorf("expected EOF: %v", err)
	}
}

func TestCloseClientEOFServer(t *testing.T) {
	c, s, err := getConnection(nil)
	if err != nil {
		t.Fatal(err)
	}
	defer c.Close()
	defer s.Close()
	ensureEOFOnClose(t, c, s)
}

func TestCloseServerEOFClient(t *testing.T) {
	c, s, err := getConnection(nil)
	if err != nil {
		t.Fatal(err)
	}
	defer c.Close()
	defer s.Close()
	ensureEOFOnClose(t, s, c)
}

func TestCloseWriteEOF(t *testing.T) {
	cfg := &PipeConfig{
		MessageMode: true,
	}
	c, s, err := getConnection(cfg)
	if err != nil {
		t.Fatal(err)
	}
	defer c.Close()
	defer s.Close()

	type closeWriter interface {
		CloseWrite() error
	}

	err = c.(closeWriter).CloseWrite()
	if err != nil {
		t.Fatal(err)
	}

	b := make([]byte, 10)
	_, err = s.Read(b)
	if err != io.EOF {
		t.Fatal(err)
	}
}

func TestAcceptAfterCloseFails(t *testing.T) {
	l, err := ListenPipe(testPipeName, nil)
	if err != nil {
		t.Fatal(err)
	}
	l.Close()
	_, err = l.Accept()
	if err != ErrPipeListenerClosed {
		t.Fatalf("expected ErrPipeListenerClosed, got %v", err)
	}
}

func TestDialTimesOutByDefault(t *testing.T) {
	l, err := ListenPipe(testPipeName, nil)
	if err != nil {
		t.Fatal(err)
	}
	defer l.Close()
	_, err = DialPipe(testPipeName, nil)
	if err != ErrTimeout {
		t.Fatalf("expected ErrTimeout, got %v", err)
	}
}
<commit_msg>Introduces a test that does an echo using message mode named pipes<commit_after>package winio

import (
	"bufio"
	"io"
	"net"
	"os"
	"syscall"
	"testing"
	"time"
)

var testPipeName = `\\.\pipe\winiotestpipe`

func TestDialUnknownFailsImmediately(t *testing.T) {
	_, err := DialPipe(testPipeName, nil)
	if err.(*os.PathError).Err != syscall.ENOENT {
		t.Fatalf("expected ENOENT got %v", err)
	}
}

func TestDialListenerTimesOut(t *testing.T) {
	l, err := ListenPipe(testPipeName, nil)
	if err != nil {
		t.Fatal(err)
	}
	defer l.Close()
	var d = time.Duration(10 * time.Millisecond)
	_, err = DialPipe(testPipeName, &d)
	if err != ErrTimeout {
		t.Fatalf("expected ErrTimeout, got %v", err)
	}
}

func TestDialAccessDeniedWithRestrictedSD(t *testing.T) {
	c := PipeConfig{
		SecurityDescriptor: "D:P(A;;0x1200FF;;;WD)",
	}
	l, err := ListenPipe(testPipeName, &c)
	if err != nil {
		t.Fatal(err)
	}
	defer l.Close()
	_, err = DialPipe(testPipeName, nil)
	if err.(*os.PathError).Err != syscall.ERROR_ACCESS_DENIED {
		t.Fatalf("expected ERROR_ACCESS_DENIED, got %v", err)
	}
}

func getConnection(cfg *PipeConfig) (client net.Conn, server net.Conn, err error) {
	l, err := ListenPipe(testPipeName, cfg)
	if err != nil {
		return
	}
	defer l.Close()

	type response struct {
		c   net.Conn
		err error
	}
	ch := make(chan response)
	go func() {
		c, err := l.Accept()
		ch <- response{c, err}
	}()

	c, err := DialPipe(testPipeName, nil)
	if err != nil {
		return
	}

	r := <-ch
	if err = r.err; err != nil {
		c.Close()
		return
	}

	client = c
	server = r.c
	return
}

func TestReadTimeout(t *testing.T) {
	c, s, err := getConnection(nil)
	if err != nil {
		t.Fatal(err)
	}
	defer c.Close()
	defer s.Close()

	c.SetReadDeadline(time.Now().Add(10 * time.Millisecond))

	buf := make([]byte, 10)
	_, err = c.Read(buf)
	if err != ErrTimeout {
		t.Fatalf("expected ErrTimeout, got %v", err)
	}
}

func server(l net.Listener, ch chan int) {
	c, err := l.Accept()
	if err != nil {
		panic(err)
	}
	rw := bufio.NewReadWriter(bufio.NewReader(c), bufio.NewWriter(c))
	s, err := rw.ReadString('\n')
	if err != nil {
		panic(err)
	}
	_, err = rw.WriteString("got " + s)
	if err != nil {
		panic(err)
	}
	err = rw.Flush()
	if err != nil {
		panic(err)
	}
	c.Close()
	ch <- 1
}

func TestFullListenDialReadWrite(t *testing.T) {
	l, err := ListenPipe(testPipeName, nil)
	if err != nil {
		t.Fatal(err)
	}
	defer l.Close()

	ch := make(chan int)
	go server(l, ch)

	c, err := DialPipe(testPipeName, nil)
	if err != nil {
		t.Fatal(err)
	}
	defer c.Close()

	rw := bufio.NewReadWriter(bufio.NewReader(c), bufio.NewWriter(c))
	_, err = rw.WriteString("hello world\n")
	if err != nil {
		t.Fatal(err)
	}
	err = rw.Flush()
	if err != nil {
		t.Fatal(err)
	}

	s, err := rw.ReadString('\n')
	if err != nil {
		t.Fatal(err)
	}
	ms := "got hello world\n"
	if s != ms {
		t.Errorf("expected '%s', got '%s'", ms, s)
	}

	<-ch
}

func TestCloseAbortsListen(t *testing.T) {
	l, err := ListenPipe(testPipeName, nil)
	if err != nil {
		t.Fatal(err)
	}

	ch := make(chan error)
	go func() {
		_, err := l.Accept()
		ch <- err
	}()

	time.Sleep(30 * time.Millisecond)
	l.Close()

	err = <-ch
	if err != ErrPipeListenerClosed {
		t.Fatalf("expected ErrPipeListenerClosed, got %v", err)
	}
}

func ensureEOFOnClose(t *testing.T, r io.Reader, w io.Closer) {
	b := make([]byte, 10)
	w.Close()
	n, err := r.Read(b)
	if n > 0 {
		t.Errorf("unexpected byte count %d", n)
	}
	if err != io.EOF {
		t.Errorf("expected EOF: %v", err)
	}
}

func TestCloseClientEOFServer(t *testing.T) {
	c, s, err := getConnection(nil)
	if err != nil {
		t.Fatal(err)
	}
	defer c.Close()
	defer s.Close()
	ensureEOFOnClose(t, c, s)
}

func TestCloseServerEOFClient(t *testing.T) {
	c, s, err := getConnection(nil)
	if err != nil {
		t.Fatal(err)
	}
	defer c.Close()
	defer s.Close()
	ensureEOFOnClose(t, s, c)
}

func TestCloseWriteEOF(t *testing.T) {
	cfg := &PipeConfig{
		MessageMode: true,
	}
	c, s, err := getConnection(cfg)
	if err != nil {
		t.Fatal(err)
	}
	defer c.Close()
	defer s.Close()

	type closeWriter interface {
		CloseWrite() error
	}

	err = c.(closeWriter).CloseWrite()
	if err != nil {
		t.Fatal(err)
	}

	b := make([]byte, 10)
	_, err = s.Read(b)
	if err != io.EOF {
		t.Fatal(err)
	}
}

func TestAcceptAfterCloseFails(t *testing.T) {
	l, err := ListenPipe(testPipeName, nil)
	if err != nil {
		t.Fatal(err)
	}
	l.Close()
	_, err = l.Accept()
	if err != ErrPipeListenerClosed {
		t.Fatalf("expected ErrPipeListenerClosed, got %v", err)
	}
}

func TestDialTimesOutByDefault(t *testing.T) {
	l, err := ListenPipe(testPipeName, nil)
	if err != nil {
		t.Fatal(err)
	}
	defer l.Close()
	_, err = DialPipe(testPipeName, nil)
	if err != ErrTimeout {
		t.Fatalf("expected ErrTimeout, got %v", err)
	}
}

type CloseWriter interface {
	CloseWrite() error
}

func TestEchoWithMessaging(t *testing.T) {
	c := PipeConfig{
		MessageMode:      true,  // Use message mode so that CloseWrite() is supported
		InputBufferSize:  65536, // Use 64KB buffers to improve performance
		OutputBufferSize: 65536,
	}
	l, err := ListenPipe(testPipeName, &c)

	if err != nil {
		t.Fatal(err)
	}
	defer l.Close()
	listenerDone := make(chan bool)
	clientDone := make(chan bool)
	go func() {
		// server echo
		conn, e := l.Accept()
		if e != nil {
			t.Fatal(e)
		}
		time.Sleep(500 * time.Millisecond) // make *sure* we don't begin to read before eof signal is sent
		io.Copy(conn, conn)
		conn.(CloseWriter).CloseWrite()
		close(listenerDone)
	}()
	timeout := 1 * time.Second
	client, err := DialPipe(testPipeName, &timeout)
	if err != nil {
		t.Fatal(err)
	}
	defer client.Close()

	go func() {
		// client read back
		bytes := make([]byte, 2)
		n, e := client.Read(bytes)
		if e != nil {
			t.Fatal(e)
		}
		if n != 2 {
			t.Fatalf("expected 2 bytes, got %v", n)
		}
		close(clientDone)
	}()

	payload := make([]byte, 2)
	payload[0] = 0
	payload[1] = 1

	n, err := client.Write(payload)
	if err != nil {
		t.Fatal(err)
	}
	if n != 2 {
		t.Fatalf("expected 2 bytes, got %v", n)
	}
	client.(CloseWriter).CloseWrite()
	<-listenerDone
	<-clientDone
}
<|endoftext|>


<commit_before>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package wrappers

import (
	"bytes"
	"testing"
)

const (
	ByteSentinal  = 0
	ShortSentinal = 0
	IntSentinal   = 0
	LongSentinal  = 0
)

func TestPackerPackByte(t *testing.T) {
	p := Packer{MaxSize: 1}

	p.PackByte(0x01)

	if p.Errored() {
		t.Fatal(p.Err)
	}

	if size := len(p.Bytes); size != 1 {
		t.Fatalf("Packer.PackByte wrote %d byte(s) but expected %d byte(s)", size, 1)
	}

	expected := []byte{0x01}
	if !bytes.Equal(p.Bytes, expected) {
		t.Fatalf("Packer.PackByte wrote:\n%v\nExpected:\n%v", p.Bytes, expected)
	}

	p.PackByte(0x02)
	if !p.Errored() {
		t.Fatal("Packer.PackByte did not fail when attempt was beyond p.MaxSize")
	}
}

func TestPackerUnpackByte(t *testing.T) {
	var (
		p                = Packer{Bytes: []byte{0x01}, Offset: 0}
		actual           = p.UnpackByte()
		expected    byte = 1
		expectedLen      = ByteLen
	)
	if p.Errored() {
		t.Fatalf("Packer.UnpackByte unexpectedly raised %s", p.Err)
	} else if actual != expected {
		t.Fatalf("Packer.UnpackByte returned %d, but expected %d", actual, expected)
	} else if p.Offset != expectedLen {
		t.Fatalf("Packer.UnpackByte left Offset %d, expected %d", p.Offset, expectedLen)
	}

	actual = p.UnpackByte()
	if !p.Errored() {
		t.Fatalf("Packer.UnpackByte should have set error, due to attempted out of bounds read")
	} else if actual != ByteSentinal {
		t.Fatalf("Packer.UnpackByte returned %d, expected sentinal value %d", actual, ByteSentinal)
	}
}

func TestPackerPackShort(t *testing.T) {
	p := Packer{MaxSize: 2}

	p.PackShort(0x0102)

	if p.Errored() {
		t.Fatal(p.Err)
	}

	if size := len(p.Bytes); size != 2 {
		t.Fatalf("Packer.PackShort wrote %d byte(s) but expected %d byte(s)", size, 2)
	}

	expected := []byte{0x01, 0x02}
	if !bytes.Equal(p.Bytes, expected) {
		t.Fatalf("Packer.PackShort wrote:\n%v\nExpected:\n%v", p.Bytes, expected)
	}
}

func TestPackerUnpackShort(t *testing.T) {
	var (
		p                  = Packer{Bytes: []byte{0x01, 0x02}, Offset: 0}
		actual             = p.UnpackShort()
		expected    uint16 = 0x0102
		expectedLen        = ShortLen
	)
	if p.Errored() {
		t.Fatalf("Packer.UnpackShort unexpectedly raised %s", p.Err)
	} else if actual != expected {
		t.Fatalf("Packer.UnpackShort returned %d, but expected %d", actual, expected)
	} else if p.Offset != expectedLen {
		t.Fatalf("Packer.UnpackShort left Offset %d, expected %d", p.Offset, expectedLen)
	}

	actual = p.UnpackShort()
	if !p.Errored() {
		t.Fatalf("Packer.UnpackShort should have set error, due to attempted out of bounds read")
	} else if actual != ShortSentinal {
		t.Fatalf("Packer.UnpackShort returned %d, expected sentinal value %d", actual, ShortSentinal)
	}
}

func TestPackerPackInt(t *testing.T) {
	p := Packer{MaxSize: 4}

	p.PackInt(0x01020304)

	if p.Errored() {
		t.Fatal(p.Err)
	}

	if size := len(p.Bytes); size != 4 {
		t.Fatalf("Packer.PackInt wrote %d byte(s) but expected %d byte(s)", size, 4)
	}

	expected := []byte{0x01, 0x02, 0x03, 0x04}
	if !bytes.Equal(p.Bytes, expected) {
		t.Fatalf("Packer.PackInt wrote:\n%v\nExpected:\n%v", p.Bytes, expected)
	}

	p.PackInt(0x05060708)
	if !p.Errored() {
		t.Fatal("Packer.PackInt did not fail when attempt was beyond p.MaxSize")
	}
}

func TestPackerUnpackInt(t *testing.T) {
	var (
		p                  = Packer{Bytes: []byte{0x01, 0x02, 0x03, 0x04}, Offset: 0}
		actual             = p.UnpackInt()
		expected    uint32 = 0x01020304
		expectedLen        = IntLen
	)
	if p.Errored() {
		t.Fatalf("Packer.UnpackInt unexpectedly raised %s", p.Err)
	} else if actual != expected {
		t.Fatalf("Packer.UnpackInt returned %d, but expected %d", actual, expected)
	} else if p.Offset != expectedLen {
		t.Fatalf("Packer.UnpackInt left Offset %d, expected %d", p.Offset, expectedLen)
	}

	actual = p.UnpackInt()
	if !p.Errored() {
		t.Fatalf("Packer.UnpackInt should have set error, due to attempted out of bounds read")
	} else if actual != IntSentinal {
		t.Fatalf("Packer.UnpackInt returned %d, expected sentinal value %d", actual, IntSentinal)
	}
}

func TestPackerPackLong(t *testing.T) {
	p := Packer{MaxSize: 8}

	p.PackLong(0x0102030405060708)

	if p.Errored() {
		t.Fatal(p.Err)
	}

	if size := len(p.Bytes); size != 8 {
		t.Fatalf("Packer.PackLong wrote %d byte(s) but expected %d byte(s)", size, 8)
	}

	expected := []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}
	if !bytes.Equal(p.Bytes, expected) {
		t.Fatalf("Packer.PackLong wrote:\n%v\nExpected:\n%v", p.Bytes, expected)
	}

	p.PackLong(0x090a0b0c0d0e0f00)
	if !p.Errored() {
		t.Fatal("Packer.PackLong did not fail when attempt was beyond p.MaxSize")
	}
}

func TestPackerUnpackLong(t *testing.T) {
	var (
		p                  = Packer{Bytes: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, Offset: 0}
		actual             = p.UnpackLong()
		expected    uint64 = 0x0102030405060708
		expectedLen        = LongLen
	)
	if p.Errored() {
		t.Fatalf("Packer.UnpackLong unexpectedly raised %s", p.Err)
	} else if actual != expected {
		t.Fatalf("Packer.UnpackLong returned %d, but expected %d", actual, expected)
	} else if p.Offset != expectedLen {
		t.Fatalf("Packer.UnpackLong left Offset %d, expected %d", p.Offset, expectedLen)
	}

	actual = p.UnpackLong()
	if !p.Errored() {
		t.Fatalf("Packer.UnpackLong should have set error, due to attempted out of bounds read")
	} else if actual != LongSentinal {
		t.Fatalf("Packer.UnpackLong returned %d, expected sentinal value %d", actual, LongSentinal)
	}
}

func TestPackerString(t *testing.T) {
	p := Packer{MaxSize: 5}

	p.PackStr("Ava")

	if p.Errored() {
		t.Fatal(p.Err)
	}

	if size := len(p.Bytes); size != 5 {
		t.Fatalf("Packer.PackStr wrote %d byte(s) but expected %d byte(s)", size, 5)
	}

	expected := []byte{0x00, 0x03, 0x41, 0x76, 0x61}
	if !bytes.Equal(p.Bytes, expected) {
		t.Fatalf("Packer.PackStr wrote:\n%v\nExpected:\n%v", p.Bytes, expected)
	}
}

func TestPacker(t *testing.T) {
	packer := Packer{
		MaxSize: 3,
	}

	if packer.Errored() {
		t.Fatalf("Packer has error %s", packer.Err)
	}

	packer.PackShort(17)
	if len(packer.Bytes) != 2 {
		t.Fatalf("Wrong byte length")
	}

	packer.PackShort(1)
	if !packer.Errored() {
		t.Fatalf("Packer should have error")
	}

	newPacker := Packer{
		Bytes: packer.Bytes,
	}

	if newPacker.UnpackShort() != 17 {
		t.Fatalf("Unpacked wrong value")
	}
}

func TestPackBool(t *testing.T) {
	p := Packer{MaxSize: 3}
	p.PackBool(false)
	p.PackBool(true)
	p.PackBool(false)
	if p.Errored() {
		t.Fatal("should have been able to pack 3 bools")
	}

	p2 := Packer{Bytes: p.Bytes}
	bool1, bool2, bool3 := p2.UnpackBool(), p2.UnpackBool(), p2.UnpackBool()

	if p.Errored() {
		t.Fatalf("errors while unpacking bools: %v", p.Errs)
	}

	if bool1 || !bool2 || bool3 {
		t.Fatal("got back wrong values")
	}
}
<commit_msg>utils: Add tests for Packer.PackFixedBytes & UnpackFixedBytes<commit_after>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package wrappers

import (
	"bytes"
	"testing"
)

const (
	ByteSentinal  = 0
	ShortSentinal = 0
	IntSentinal   = 0
	LongSentinal  = 0
)

func TestPackerPackByte(t *testing.T) {
	p := Packer{MaxSize: 1}

	p.PackByte(0x01)

	if p.Errored() {
		t.Fatal(p.Err)
	}

	if size := len(p.Bytes); size != 1 {
		t.Fatalf("Packer.PackByte wrote %d byte(s) but expected %d byte(s)", size, 1)
	}

	expected := []byte{0x01}
	if !bytes.Equal(p.Bytes, expected) {
		t.Fatalf("Packer.PackByte wrote:\n%v\nExpected:\n%v", p.Bytes, expected)
	}

	p.PackByte(0x02)
	if !p.Errored() {
		t.Fatal("Packer.PackByte did not fail when attempt was beyond p.MaxSize")
	}
}

func TestPackerUnpackByte(t *testing.T) {
	var (
		p                = Packer{Bytes: []byte{0x01}, Offset: 0}
		actual           = p.UnpackByte()
		expected    byte = 1
		expectedLen      = ByteLen
	)
	if p.Errored() {
		t.Fatalf("Packer.UnpackByte unexpectedly raised %s", p.Err)
	} else if actual != expected {
		t.Fatalf("Packer.UnpackByte returned %d, but expected %d", actual, expected)
	} else if p.Offset != expectedLen {
		t.Fatalf("Packer.UnpackByte left Offset %d, expected %d", p.Offset, expectedLen)
	}

	actual = p.UnpackByte()
	if !p.Errored() {
		t.Fatalf("Packer.UnpackByte should have set error, due to attempted out of bounds read")
	} else if actual != ByteSentinal {
		t.Fatalf("Packer.UnpackByte returned %d, expected sentinal value %d", actual, ByteSentinal)
	}
}

func TestPackerPackShort(t *testing.T) {
	p := Packer{MaxSize: 2}

	p.PackShort(0x0102)

	if p.Errored() {
		t.Fatal(p.Err)
	}

	if size := len(p.Bytes); size != 2 {
		t.Fatalf("Packer.PackShort wrote %d byte(s) but expected %d byte(s)", size, 2)
	}

	expected := []byte{0x01, 0x02}
	if !bytes.Equal(p.Bytes, expected) {
		t.Fatalf("Packer.PackShort wrote:\n%v\nExpected:\n%v", p.Bytes, expected)
	}
}

func TestPackerUnpackShort(t *testing.T) {
	var (
		p                  = Packer{Bytes: []byte{0x01, 0x02}, Offset: 0}
		actual             = p.UnpackShort()
		expected    uint16 = 0x0102
		expectedLen        = ShortLen
	)
	if p.Errored() {
		t.Fatalf("Packer.UnpackShort unexpectedly raised %s", p.Err)
	} else if actual != expected {
		t.Fatalf("Packer.UnpackShort returned %d, but expected %d", actual, expected)
	} else if p.Offset != expectedLen {
		t.Fatalf("Packer.UnpackShort left Offset %d, expected %d", p.Offset, expectedLen)
	}

	actual = p.UnpackShort()
	if !p.Errored() {
		t.Fatalf("Packer.UnpackShort should have set error, due to attempted out of bounds read")
	} else if actual != ShortSentinal {
		t.Fatalf("Packer.UnpackShort returned %d, expected sentinal value %d", actual, ShortSentinal)
	}
}

func TestPackerPackInt(t *testing.T) {
	p := Packer{MaxSize: 4}

	p.PackInt(0x01020304)

	if p.Errored() {
		t.Fatal(p.Err)
	}

	if size := len(p.Bytes); size != 4 {
		t.Fatalf("Packer.PackInt wrote %d byte(s) but expected %d byte(s)", size, 4)
	}

	expected := []byte{0x01, 0x02, 0x03, 0x04}
	if !bytes.Equal(p.Bytes, expected) {
		t.Fatalf("Packer.PackInt wrote:\n%v\nExpected:\n%v", p.Bytes, expected)
	}

	p.PackInt(0x05060708)
	if !p.Errored() {
		t.Fatal("Packer.PackInt did not fail when attempt was beyond p.MaxSize")
	}
}

func TestPackerUnpackInt(t *testing.T) {
	var (
		p                  = Packer{Bytes: []byte{0x01, 0x02, 0x03, 0x04}, Offset: 0}
		actual             = p.UnpackInt()
		expected    uint32 = 0x01020304
		expectedLen        = IntLen
	)
	if p.Errored() {
		t.Fatalf("Packer.UnpackInt unexpectedly raised %s", p.Err)
	} else if actual != expected {
		t.Fatalf("Packer.UnpackInt returned %d, but expected %d", actual, expected)
	} else if p.Offset != expectedLen {
		t.Fatalf("Packer.UnpackInt left Offset %d, expected %d", p.Offset, expectedLen)
	}

	actual = p.UnpackInt()
	if !p.Errored() {
		t.Fatalf("Packer.UnpackInt should have set error, due to attempted out of bounds read")
	} else if actual != IntSentinal {
		t.Fatalf("Packer.UnpackInt returned %d, expected sentinal value %d", actual, IntSentinal)
	}
}

func TestPackerPackLong(t *testing.T) {
	p := Packer{MaxSize: 8}

	p.PackLong(0x0102030405060708)

	if p.Errored() {
		t.Fatal(p.Err)
	}

	if size := len(p.Bytes); size != 8 {
		t.Fatalf("Packer.PackLong wrote %d byte(s) but expected %d byte(s)", size, 8)
	}

	expected := []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}
	if !bytes.Equal(p.Bytes, expected) {
		t.Fatalf("Packer.PackLong wrote:\n%v\nExpected:\n%v", p.Bytes, expected)
	}

	p.PackLong(0x090a0b0c0d0e0f00)
	if !p.Errored() {
		t.Fatal("Packer.PackLong did not fail when attempt was beyond p.MaxSize")
	}
}

func TestPackerUnpackLong(t *testing.T) {
	var (
		p                  = Packer{Bytes: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, Offset: 0}
		actual             = p.UnpackLong()
		expected    uint64 = 0x0102030405060708
		expectedLen        = LongLen
	)
	if p.Errored() {
		t.Fatalf("Packer.UnpackLong unexpectedly raised %s", p.Err)
	} else if actual != expected {
		t.Fatalf("Packer.UnpackLong returned %d, but expected %d", actual, expected)
	} else if p.Offset != expectedLen {
		t.Fatalf("Packer.UnpackLong left Offset %d, expected %d", p.Offset, expectedLen)
	}

	actual = p.UnpackLong()
	if !p.Errored() {
		t.Fatalf("Packer.UnpackLong should have set error, due to attempted out of bounds read")
	} else if actual != LongSentinal {
		t.Fatalf("Packer.UnpackLong returned %d, expected sentinal value %d", actual, LongSentinal)
	}
}

func TestPackerPackFixedBytes(t *testing.T) {
	p := Packer{MaxSize: 3}

	p.PackFixedBytes([]byte("Ava"))

	if p.Errored() {
		t.Fatal(p.Err)
	}

	if size := len(p.Bytes); size != 3 {
		t.Fatalf("Packer.PackFixedBytes wrote %d byte(s) but expected %d byte(s)", size, 3)
	}

	expected := []byte("Ava")
	if !bytes.Equal(p.Bytes, expected) {
		t.Fatalf("Packer.PackFixedBytes wrote:\n%v\nExpected:\n%v", p.Bytes, expected)
	}

	p.PackFixedBytes([]byte("Ava"))
	if !p.Errored() {
		t.Fatal("Packer.PackFixedBytes did not fail when attempt was beyond p.MaxSize")
	}
}

func TestPackerUnpackFixedBytes(t *testing.T) {
	var (
		p           = Packer{Bytes: []byte("Ava")}
		actual      = p.UnpackFixedBytes(3)
		expected    = []byte("Ava")
		expectedLen = 3
	)
	if p.Errored() {
		t.Fatalf("Packer.UnpackFixedBytes unexpectedly raised %s", p.Err)
	} else if !bytes.Equal(actual, expected) {
		t.Fatalf("Packer.UnpackFixedBytes returned %d, but expected %d", actual, expected)
	} else if p.Offset != expectedLen {
		t.Fatalf("Packer.UnpackFixedBytes left Offset %d, expected %d", p.Offset, expectedLen)
	}

	actual = p.UnpackFixedBytes(3)
	if !p.Errored() {
		t.Fatalf("Packer.UnpackFixedBytes should have set error, due to attempted out of bounds read")
	} else if actual != nil {
		t.Fatalf("Packer.UnpackFixedBytes returned %v, expected sentinal value %v", actual, nil)
	}
}

func TestPackerString(t *testing.T) {
	p := Packer{MaxSize: 5}

	p.PackStr("Ava")

	if p.Errored() {
		t.Fatal(p.Err)
	}

	if size := len(p.Bytes); size != 5 {
		t.Fatalf("Packer.PackStr wrote %d byte(s) but expected %d byte(s)", size, 5)
	}

	expected := []byte{0x00, 0x03, 0x41, 0x76, 0x61}
	if !bytes.Equal(p.Bytes, expected) {
		t.Fatalf("Packer.PackStr wrote:\n%v\nExpected:\n%v", p.Bytes, expected)
	}
}

func TestPacker(t *testing.T) {
	packer := Packer{
		MaxSize: 3,
	}

	if packer.Errored() {
		t.Fatalf("Packer has error %s", packer.Err)
	}

	packer.PackShort(17)
	if len(packer.Bytes) != 2 {
		t.Fatalf("Wrong byte length")
	}

	packer.PackShort(1)
	if !packer.Errored() {
		t.Fatalf("Packer should have error")
	}

	newPacker := Packer{
		Bytes: packer.Bytes,
	}

	if newPacker.UnpackShort() != 17 {
		t.Fatalf("Unpacked wrong value")
	}
}

func TestPackBool(t *testing.T) {
	p := Packer{MaxSize: 3}
	p.PackBool(false)
	p.PackBool(true)
	p.PackBool(false)
	if p.Errored() {
		t.Fatal("should have been able to pack 3 bools")
	}

	p2 := Packer{Bytes: p.Bytes}
	bool1, bool2, bool3 := p2.UnpackBool(), p2.UnpackBool(), p2.UnpackBool()

	if p.Errored() {
		t.Fatalf("errors while unpacking bools: %v", p.Errs)
	}

	if bool1 || !bool2 || bool3 {
		t.Fatal("got back wrong values")
	}
}
<|endoftext|>


<commit_before>package vagrant

import (
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceVagrantVm() *schema.Resource {
	return &schema.Resource{
		Create: resourceVagrantVmCreate,
		Read:   resourceVagrantVmRead,
		Update: resourceVagrantVmUpdate,
		Delete: resourceVagrantVmDelete,

		Schema: map[string]*schema.Schema{
			"boot_timeout": &schema.Schema{
				Type:        schema.TypeInt,
				Optional:    true,
				Default:     300,
				Description: "The time in seconds that Vagrant will wait for the machine to boot.",
			},
			"box": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Description: "Installed box name or Atlas box shorthand name to use.",
			},
			"box_check_update": &schema.Schema{
				Type:        schema.TypeBool,
				Optional:    true,
				Default:     true,
				Description: "Whether or not to check for updates to the box on each `vagrant up`.",
			},
			"box_download_checksum": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Description: "The expected checksum of the box file.",
			},
			"box_download_checksum_type": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Description: "The type of checksum specified by `box_download_checksum`. Should be `md5`, `sha1`, or `sha256`.",
			},
			"box_url": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Description: "The URL to download the box.",
			},
			"box_version": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Description: "The version of the box to use.",
			},
			"hostname": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Description: "The hostname the machine should have.",
			},
			"networks": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"type": &schema.Schema{
							Type:        schema.TypeString,
							Required:    true,
							Description: "The type of network, one of `forwarded_port`, `private_network`, or `public_network`.",
						},

						// forwarded_port
						"guest": &schema.Schema{
							Type:        schema.TypeInt,
							Optional:    true,
							Description: "The port on the guest you want to be exposed on the host.",
						},
						"guest_ip": &schema.Schema{
							Type:        schema.TypeInt,
							Optional:    true,
							Description: "The IP the forwarded port should be bound to within the guest.",
						},
						"host": &schema.Schema{
							Type:        schema.TypeInt,
							Optional:    true,
							Description: "The port on the host used to access the port on the guest.",
						},
						"host_ip": &schema.Schema{
							Type:        schema.TypeInt,
							Optional:    true,
							Description: "The IP the forwarded port should be bound to on the host.",
						},
						"protocol": &schema.Schema{
							Type:        schema.TypeString,
							Optional:    true,
							Description: "The network protcol to use, one of `tcp` or `udp`.",
						},
						"auto_correct": &schema.Schema{
							Type:        schema.TypeBool,
							Optional:    true,
							Description: "Whether or not to automatically resolve port collisions on the host.",
						},

						// private_network and public_network
						"dhcp": &schema.Schema{
							Type:        schema.TypeString,
							Optional:    true,
							Description: "The static IP to assign the interface on the host. Do not set this to use DHCP instead.",
						},
					},
				},
				Set: func(v interface{}) int {
					return 0
				},
			},
		},
	}
}

func resourceVagrantVmCreate(data *schema.ResourceData, meta interface{}) error {
	return nil
}

func resourceVagrantVmRead(data *schema.ResourceData, meta interface{}) error {
	return nil
}

func resourceVagrantVmUpdate(data *schema.ResourceData, meta interface{}) error {
	return nil
}

func resourceVagrantVmDelete(data *schema.ResourceData, meta interface{}) error {
	return nil
}
<commit_msg>dhcp field should be ip.<commit_after>package vagrant

import (
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceVagrantVm() *schema.Resource {
	return &schema.Resource{
		Create: resourceVagrantVmCreate,
		Read:   resourceVagrantVmRead,
		Update: resourceVagrantVmUpdate,
		Delete: resourceVagrantVmDelete,

		Schema: map[string]*schema.Schema{
			"boot_timeout": &schema.Schema{
				Type:        schema.TypeInt,
				Optional:    true,
				Default:     300,
				Description: "The time in seconds that Vagrant will wait for the machine to boot.",
			},
			"box": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Description: "Installed box name or Atlas box shorthand name to use.",
			},
			"box_check_update": &schema.Schema{
				Type:        schema.TypeBool,
				Optional:    true,
				Default:     true,
				Description: "Whether or not to check for updates to the box on each `vagrant up`.",
			},
			"box_download_checksum": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Description: "The expected checksum of the box file.",
			},
			"box_download_checksum_type": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Description: "The type of checksum specified by `box_download_checksum`. Should be `md5`, `sha1`, or `sha256`.",
			},
			"box_url": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Description: "The URL to download the box.",
			},
			"box_version": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Description: "The version of the box to use.",
			},
			"hostname": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Description: "The hostname the machine should have.",
			},
			"networks": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"type": &schema.Schema{
							Type:        schema.TypeString,
							Required:    true,
							Description: "The type of network, one of `forwarded_port`, `private_network`, or `public_network`.",
						},

						// forwarded_port
						"guest": &schema.Schema{
							Type:        schema.TypeInt,
							Optional:    true,
							Description: "The port on the guest you want to be exposed on the host.",
						},
						"guest_ip": &schema.Schema{
							Type:        schema.TypeInt,
							Optional:    true,
							Description: "The IP the forwarded port should be bound to within the guest.",
						},
						"host": &schema.Schema{
							Type:        schema.TypeInt,
							Optional:    true,
							Description: "The port on the host used to access the port on the guest.",
						},
						"host_ip": &schema.Schema{
							Type:        schema.TypeInt,
							Optional:    true,
							Description: "The IP the forwarded port should be bound to on the host.",
						},
						"protocol": &schema.Schema{
							Type:        schema.TypeString,
							Optional:    true,
							Description: "The network protcol to use, one of `tcp` or `udp`.",
						},
						"auto_correct": &schema.Schema{
							Type:        schema.TypeBool,
							Optional:    true,
							Description: "Whether or not to automatically resolve port collisions on the host.",
						},

						// private_network and public_network
						"ip": &schema.Schema{
							Type:        schema.TypeString,
							Optional:    true,
							Description: "The static IP to assign the interface on the host. Do not set this to use DHCP instead.",
						},
					},
				},
				Set: func(v interface{}) int {
					return 0
				},
			},
		},
	}
}

func resourceVagrantVmCreate(data *schema.ResourceData, meta interface{}) error {
	return nil
}

func resourceVagrantVmRead(data *schema.ResourceData, meta interface{}) error {
	return nil
}

func resourceVagrantVmUpdate(data *schema.ResourceData, meta interface{}) error {
	return nil
}

func resourceVagrantVmDelete(data *schema.ResourceData, meta interface{}) error {
	return nil
}
<|endoftext|>


<commit_before>package tests

import (
	"github.com/gojp/nihongo/app/models"
	"github.com/robfig/revel"
)

type ModelsTest struct {
	revel.TestSuite
}

func (s *ModelsTest) Before() {
}

func (s *ModelsTest) After() {
}

func (s *ModelsTest) TestHighlightQuery() {
	// some basic checks
	w := models.Word{
		English:  []string{"test"},
		Furigana: "テスト",
		Japanese: "テスト",
	}
	w.HighlightQuery("tesuto")
	s.Assert(w.English[0] == "test")
	s.Assert(w.EnglishHL[0] == "test")
	s.Assert(w.Furigana == "テスト")
	s.Assert(w.FuriganaHL == "テスト")
	s.Assert(w.Japanese == "テスト")
	s.Assert(w.JapaneseHL == "テスト")
}
<commit_msg>Test romaji and katakana input to highlightQuery<commit_after>package tests

import (
	"github.com/gojp/nihongo/app/models"
	"github.com/robfig/revel"
)

type ModelsTest struct {
	revel.TestSuite
}

func (s *ModelsTest) Before() {
}

func (s *ModelsTest) After() {
}

func (s *ModelsTest) TestHighlightQuery() {
	// some basic checks
	w := models.Word{
		English:  []string{"test"},
		Furigana: "テスト",
		Japanese: "テスト",
	}
	w.HighlightQuery("tesuto")
	s.Assert(w.English[0] == "test")
	s.Assert(w.EnglishHL[0] == "test")
	s.Assert(w.Furigana == "テスト")
	s.Assert(w.FuriganaHL == "テスト")
	s.Assert(w.Japanese == "テスト")
	s.Assert(w.JapaneseHL == "テスト")

	w.HighlightQuery("テスト")
	s.Assert(w.English[0] == "test")
	s.Assert(w.EnglishHL[0] == "test")
	s.Assert(w.Furigana == "テスト")
	s.Assert(w.FuriganaHL == "テスト")
	s.Assert(w.Japanese == "テスト")
	s.Assert(w.JapaneseHL == "テスト")

	w.HighlightQuery("test")
	s.Assert(w.English[0] == "test")
	s.Assert(w.EnglishHL[0] == "test")
	s.Assert(w.Furigana == "テスト")
	s.Assert(w.FuriganaHL == "テスト")
	s.Assert(w.Japanese == "テスト")
	s.Assert(w.JapaneseHL == "テスト")
}
<|endoftext|>


<commit_before>package abp

import (
	"bytes"
	"runtime"
	"sync"

	"testing"
)

func TestPoolBasic(t *testing.T) {
	size := 10
	backlog := 20
	expected := 10
	overflow := 1.0

	content := []byte("foobar")
	p := NewAveragedBufferPool(size, backlog, expected, overflow)
	defer p.Close()
	for i := 0; i < backlog; i++ {
		buf := p.Get()
		buf.Write(content)
		_ = buf.String()
		p.Put(buf)
	}

	for i := 0; i < backlog; i++ {
		go func() {
			buf := p.Get()
			buf.Write(content)
			p.Put(buf)
		}()
	}
}

func TestPoolAverage(t *testing.T) {
	// this test is a little bit pointless, because it is impossible to predict how much
	// the go runtime will grow an buffer after writing over capacity
	size := 10
	backlog := 20
	expected := 20
	overflow := 1.0

	content := []byte("01234567890123456789")
	p := NewAveragedBufferPool(size, backlog, expected, overflow)
	defer p.Close()

	ca := p.currentAverage
	if ca != expected {
		t.Errorf("Expected current average to be %d but was %d", expected, ca)
	}

	cs := p.currentSum
	if cs != expected*backlog {
		t.Errorf("Expected current sum to be %d but was %d", expected*backlog, cs)
	}

	for i := 0; i < backlog; i++ {
		buf := p.Get()
		buf.Write(content)
		_ = buf.String()
		p.Put(buf)
	}

	// time.Sleep(1 * time.Second)
	p.lock.RLock()
	ca = p.currentAverage
	p.lock.RUnlock()
	if ca != len(content) {
		t.Errorf("Expected current average to be %d but was %d", len(content), ca)
	}

}

func TestCap(t *testing.T) {
	size := 10
	backlog := 20
	expected := 10
	overflow := 1.0

	runner := runtime.NumCPU()
	var wg sync.WaitGroup

	content := []byte("01234567890123456789")
	p := NewAveragedBufferPool(size, backlog, expected, overflow)
	defer p.Close()

	if cap(p.bufferChannel) != size {
		t.Errorf("Expected buffer size to be %d but was %d", size, cap(p.bufferChannel))
	}

	if len(p.bufferChannel) != 0 {
		t.Errorf("Expected buffer channel to be empty, but has %d buffers", len(p.bufferChannel))
	}

	wg.Add(runner)

	// just take buffers out

	for i := 0; i < runner; i++ {
		go func() {
			defer wg.Done()
			buffers := make([]*bytes.Buffer, backlog)
			for j := 0; j < backlog; j++ {
				buf := p.Get()
				buf.Write(content)
				_ = buf.String()
				buffers[j] = buf
				// p.Put(buf)
			}
		}()
	}
	wg.Wait()

	if len(p.bufferChannel) != 0 {
		t.Errorf("Channel should be empty, but there are %d elements", len(p.bufferChannel))
	}

	// take out and push all of them back in

	var wait sync.WaitGroup
	wg.Add(runner)
	wait.Add(runner)
	for i := 0; i < runner; i++ {
		go func() {
			buffers := make([]*bytes.Buffer, backlog)
			for j := 0; j < backlog; j++ {
				buf := p.Get()
				buf.Write(content)
				_ = buf.String()
				buffers[j] = buf
				// p.Put(buf)
			}
			wait.Done()
			wait.Wait()
			for _, buf := range buffers {
				p.Put(buf)
			}
			wg.Done()
		}()
	}
	wg.Wait()

	if len(p.bufferChannel) != size {
		t.Errorf("Channel should be full, but there just %d elements", len(p.bufferChannel))
	}

}
<commit_msg>added synctetic benchmark<commit_after>package abp

import (
	"bytes"
	"runtime"
	"sync"

	"testing"
)

func TestPoolBasic(t *testing.T) {
	size := 10
	backlog := 20
	expected := 10
	overflow := 1.0

	content := []byte("foobar")
	p := NewAveragedBufferPool(size, backlog, expected, overflow)
	defer p.Close()
	for i := 0; i < backlog; i++ {
		buf := p.Get()
		buf.Write(content)
		_ = buf.String()
		p.Put(buf)
	}

	for i := 0; i < backlog; i++ {
		go func() {
			buf := p.Get()
			buf.Write(content)
			p.Put(buf)
		}()
	}
}

func TestPoolAverage(t *testing.T) {
	// this test is a little bit pointless, because it is impossible to predict how much
	// the go runtime will grow an buffer after writing over capacity
	size := 10
	backlog := 20
	expected := 20
	overflow := 1.0

	content := []byte("01234567890123456789")
	p := NewAveragedBufferPool(size, backlog, expected, overflow)
	defer p.Close()

	ca := p.currentAverage
	if ca != expected {
		t.Errorf("Expected current average to be %d but was %d", expected, ca)
	}

	cs := p.currentSum
	if cs != expected*backlog {
		t.Errorf("Expected current sum to be %d but was %d", expected*backlog, cs)
	}

	for i := 0; i < backlog; i++ {
		buf := p.Get()
		buf.Write(content)
		_ = buf.String()
		p.Put(buf)
	}

	// time.Sleep(1 * time.Second)
	p.lock.RLock()
	ca = p.currentAverage
	p.lock.RUnlock()
	if ca != len(content) {
		t.Errorf("Expected current average to be %d but was %d", len(content), ca)
	}

}

func TestCap(t *testing.T) {
	size := 10
	backlog := 20
	expected := 10
	overflow := 1.0

	runner := runtime.NumCPU()
	var wg sync.WaitGroup

	content := []byte("01234567890123456789")
	p := NewAveragedBufferPool(size, backlog, expected, overflow)
	defer p.Close()

	if cap(p.bufferChannel) != size {
		t.Errorf("Expected buffer size to be %d but was %d", size, cap(p.bufferChannel))
	}

	if len(p.bufferChannel) != 0 {
		t.Errorf("Expected buffer channel to be empty, but has %d buffers", len(p.bufferChannel))
	}

	wg.Add(runner)

	// just take buffers out

	for i := 0; i < runner; i++ {
		go func() {
			defer wg.Done()
			buffers := make([]*bytes.Buffer, backlog)
			for j := 0; j < backlog; j++ {
				buf := p.Get()
				buf.Write(content)
				_ = buf.String()
				buffers[j] = buf
				// p.Put(buf)
			}
		}()
	}
	wg.Wait()

	if len(p.bufferChannel) != 0 {
		t.Errorf("Channel should be empty, but there are %d elements", len(p.bufferChannel))
	}

	// take out and push all of them back in

	var wait sync.WaitGroup
	wg.Add(runner)
	wait.Add(runner)
	for i := 0; i < runner; i++ {
		go func() {
			buffers := make([]*bytes.Buffer, backlog)
			for j := 0; j < backlog; j++ {
				buf := p.Get()
				buf.Write(content)
				_ = buf.String()
				buffers[j] = buf
				// p.Put(buf)
			}
			wait.Done()
			wait.Wait()
			for _, buf := range buffers {
				p.Put(buf)
			}
			wg.Done()
		}()
	}
	wg.Wait()

	if len(p.bufferChannel) != size {
		t.Errorf("Channel should be full, but there just %d elements", len(p.bufferChannel))
	}

}

func benchmarkSimplePool(i int, b *testing.B) {
	backlog := 1000
	expected := 5
	overflow := 1.0

	content := []byte("01234567890123456789")
	p := NewAveragedBufferPool(i, backlog, expected, overflow)
	defer p.Close()

	for j := 0; j < b.N; j++ {
		buf := p.Get()
		buf.Write(content)
		_ = buf.String()
		p.Put(buf)
	}
}

func BenchmarkSimplePool100(b *testing.B) {
	benchmarkSimplePool(100, b)
}

func BenchmarkSimplePool1000(b *testing.B) {
	benchmarkSimplePool(1000, b)
}

func BenchmarkSimplePool10000(b *testing.B) {
	benchmarkSimplePool(10000, b)
}

func benchmarkParallelPool(i int, b *testing.B) {
	backlog := 1000
	expected := 5
	overflow := 1.0

	content := []byte("01234567890123456789")
	p := NewAveragedBufferPool(i, backlog, expected, overflow)
	defer p.Close()

	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			buf := p.Get()
			buf.Write(content)
			_ = buf.String()
			p.Put(buf)
		}
	})
}

func BenchmarkParallelPool100(b *testing.B) {
	benchmarkParallelPool(100, b)
}

func BenchmarkParallelPool1000(b *testing.B) {
	benchmarkParallelPool(1000, b)
}

func BenchmarkParallelPool10000(b *testing.B) {
	benchmarkParallelPool(10000, b)
}
<|endoftext|>


<commit_before>package pool

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"net/url"
	"testing"
	"time"
)

var (
	numWorkers int64 = 4
	t10ms            = time.Duration(10) * time.Millisecond
)

func testHandler(w http.ResponseWriter, _ *http.Request) {
	fmt.Fprint(w, "Test page")
}

func testHandlerWithTimeout(w http.ResponseWriter, _ *http.Request) {
	time.Sleep(t10ms)
	fmt.Fprint(w, "Test page with timeout")
}

func TestQueue(t *testing.T) {
	queue := newRingQueue()
	testTask := &Task{
		Hostname: "",
	}
	queue.put(testTask)
	if queue.cnt != 1 {
		t.Errorf("Got %v error, want %v", queue.cnt, 1)
	}
	queue.put(testTask)
	_, ok := queue.get()
	if !ok {
		t.Errorf("Got %v error, want %v", ok, true)
	}
}

func TestClosedInputTaskChanByTimeout(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(testHandler))
	defer ts.Close()

	p := New(2)
	p.SetQuitTimeout(10)
	p.Add(ts.URL, nil)
	time.Sleep(time.Duration(30) * time.Millisecond)
	err := p.Add(ts.URL, nil)
	if err == nil {
		t.Errorf("Got %v error, want %v", nil, errNotRun)
	}
}

func TestNoServer(t *testing.T) {
	p := New(numWorkers)
	if p.numWorkers != numWorkers {
		t.Errorf("Got %v numWorkers, want %v", p.numWorkers, numWorkers)
	}
	err := p.Add("", nil)
	if err != errEmptyTarget {
		t.Errorf("Got %v error, want %v", err, errEmptyTarget)
	}
	err = p.Add(":", nil)
	if err == nil {
		t.Errorf("Got %v error, want hostname error", err)
	}
	if !p.poolIsRunning() {
		t.Errorf("Got %v error, want true", p.poolIsRunning())
	}
	err = p.Add("http://127.0.0.1:80/", nil)
	if err != nil {
		t.Errorf("Got %v error, want nil error", err)
	}
	task := <-p.ResultChan
	if task.Error == nil {
		t.Error("Got nil error, want net error")
	}
	if p.GetAddedTasks() != 1 {
		t.Errorf("Wrong input jobs. Want 1, got %v", p.GetAddedTasks())
	}
	if p.getFreeWorkers() != numWorkers {
		t.Errorf("Wrong free workers. Want %v, got %v", numWorkers, p.getFreeWorkers())
	}
	proxy, _ := url.Parse("http://127.0.0.1:80/")
	err = p.Add("http://127.0.0.1:80/", proxy)
	if err != nil {
		t.Errorf("Got %v error, want nil error", err)
	}
	task = <-p.ResultChan
	if task.Error == nil {
		t.Error("Got nil error, want net error")
	}
	p.Quit()
	if p.poolIsRunning() {
		t.Errorf("Got %v error, want false", p.poolIsRunning())
	}
}

func TestWithServer(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(testHandler))
	defer ts.Close()

	p := New(numWorkers)
	_ = p.Add(ts.URL, nil)
	task, ok := <-p.ResultChan
	if !ok {
		t.Error("Channel is closed'")
	}
	if string(task.Body) != "Test page" {
		t.Errorf("Got %v error, want 'Test page'", string(task.Body))
	}
	p.EndWaitingTasks()
	err := p.Add(ts.URL, nil)
	if err != errNotWait {
		t.Errorf("Got %v error, want %v", err, errNotWait)
	}
	if p.GetCompletedTasks() == 0 {
		t.Errorf("Got %v error, want %v", 0, 1)
	}
	if !p.isCompleteJobs() {
		t.Errorf("Got %v error, want %v", false, true)
	}
}

func TestWithTimeout(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(testHandlerWithTimeout))
	defer ts.Close()

	p := New(1)
	p.SetTimeout(100)
	err := p.Add(ts.URL, nil)
	if err != nil {
		t.Errorf("Got %v error, want %v", err, nil)
	}
	task, ok := <-p.ResultChan
	if !ok {
		t.Error("Channel is closed'")
	}
	if string(task.Body) != "Test page with timeout" {
		t.Errorf("Got %v error, want 'Test page with timeout'", string(task.Body))
	}
	p.timeout = time.Duration(1) * time.Millisecond
	err = p.Add(ts.URL, nil)
	if err != nil {
		t.Errorf("Got %v error, want %v", err, nil)
	}
	task, ok = <-p.ResultChan
	if !ok {
		t.Error("Channel is closed'")
	}
	if task.Error == nil {
		t.Errorf("Got no error, want %v", task.Error)
	}
	_ = p.Add(ts.URL, nil)
	p.Quit()
	if p.GetCompletedTasks() != 2 {
		t.Errorf("Got %v error, want %v", p.GetCompletedTasks(), 2)
	}
	task, ok = <-p.ResultChan
	if ok {
		t.Errorf("Got %v error, want %v", ok, false)
	}
	if task != nil {
		t.Errorf("Got %v error, want %v", task, nil)
	}
	if p.poolIsRunning() {
		t.Errorf("Got %v error, want %v", !p.poolIsRunning(), false)
	}
	err = p.Add(ts.URL, nil)
	if err != errNotRun {
		t.Errorf("Got %v error, want %v", err, errNotRun)
	}
}

func TestQuitTimeout(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(testHandlerWithTimeout))
	defer ts.Close()

	p := New(1)
	p.SetTimeout(30)
	p.SetQuitTimeout(2)
	_ = p.Add(ts.URL, nil)
	_ = p.Add(ts.URL, nil)
	for range p.ResultChan {
	}
	if p.GetCompletedTasks() != 2 {
		t.Errorf("Got %v error, want %v", p.GetCompletedTasks(), 1)
	}
}

func TestWaitingTasks(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(testHandler))
	defer ts.Close()

	p := New(1)
	_ = p.Add(ts.URL, nil)
	_ = p.Add(ts.URL, nil)
	p.EndWaitingTasks()
	for range p.ResultChan {
	}
	if p.GetCompletedTasks() != 2 {
		t.Errorf("Got %v error, want %v", p.GetCompletedTasks(), 1)
	}
}

func BenchmarkAccumulate(b *testing.B) {
	ts := httptest.NewServer(http.HandlerFunc(testHandler))
	defer ts.Close()
	b.ResetTimer()

	p := New(numWorkers)
	n := b.N
	for i := 0; i < n; i++ {
		err := p.Add(ts.URL, nil)
		if err != nil {
			b.Errorf("Got %v error, want %v", err, nil)
		}
	}
	for i := 0; i < n; i++ {
		task := <-p.ResultChan
		err := task.Error
		if err != nil {
			b.Error("Error", err)
		}
	}
}

func BenchmarkParallel(b *testing.B) {
	ts := httptest.NewServer(http.HandlerFunc(testHandler))
	defer ts.Close()
	b.ResetTimer()

	p := New(numWorkers)
	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			err := p.Add(ts.URL, nil)
			if err != nil {
				b.Errorf("Got %v error, want %v", err, nil)
			}
		}
	})
	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			task := <-p.ResultChan
			_ = task.Error
			// if err != nil {
			// 	b.Error("Error", err)
			// }
		}
	})
}
<commit_msg>missing check error<commit_after>package pool

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"net/url"
	"testing"
	"time"
)

var (
	numWorkers int64 = 4
	t10ms            = time.Duration(10) * time.Millisecond
)

func testHandler(w http.ResponseWriter, _ *http.Request) {
	fmt.Fprint(w, "Test page")
}

func testHandlerWithTimeout(w http.ResponseWriter, _ *http.Request) {
	time.Sleep(t10ms)
	fmt.Fprint(w, "Test page with timeout")
}

func TestQueue(t *testing.T) {
	queue := newRingQueue()
	testTask := &Task{
		Hostname: "",
	}
	queue.put(testTask)
	if queue.cnt != 1 {
		t.Errorf("Got %v error, want %v", queue.cnt, 1)
	}
	queue.put(testTask)
	_, ok := queue.get()
	if !ok {
		t.Errorf("Got %v error, want %v", ok, true)
	}
}

func TestClosedInputTaskChanByTimeout(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(testHandler))
	defer ts.Close()

	p := New(2)
	p.SetQuitTimeout(10)
	err := p.Add(ts.URL, nil)
	if err != nil {
		t.Errorf("Got %v error, want %v", nil, errNotRun)
	}
	time.Sleep(time.Duration(30) * time.Millisecond)
	err = p.Add(ts.URL, nil)
	if err == nil {
		t.Errorf("Got %v error, want %v", nil, errNotRun)
	}
}

func TestNoServer(t *testing.T) {
	p := New(numWorkers)
	if p.numWorkers != numWorkers {
		t.Errorf("Got %v numWorkers, want %v", p.numWorkers, numWorkers)
	}
	err := p.Add("", nil)
	if err != errEmptyTarget {
		t.Errorf("Got %v error, want %v", err, errEmptyTarget)
	}
	err = p.Add(":", nil)
	if err == nil {
		t.Errorf("Got %v error, want hostname error", err)
	}
	if !p.poolIsRunning() {
		t.Errorf("Got %v error, want true", p.poolIsRunning())
	}
	err = p.Add("http://127.0.0.1:80/", nil)
	if err != nil {
		t.Errorf("Got %v error, want nil error", err)
	}
	task := <-p.ResultChan
	if task.Error == nil {
		t.Error("Got nil error, want net error")
	}
	if p.GetAddedTasks() != 1 {
		t.Errorf("Wrong input jobs. Want 1, got %v", p.GetAddedTasks())
	}
	if p.getFreeWorkers() != numWorkers {
		t.Errorf("Wrong free workers. Want %v, got %v", numWorkers, p.getFreeWorkers())
	}
	proxy, _ := url.Parse("http://127.0.0.1:80/")
	err = p.Add("http://127.0.0.1:80/", proxy)
	if err != nil {
		t.Errorf("Got %v error, want nil error", err)
	}
	task = <-p.ResultChan
	if task.Error == nil {
		t.Error("Got nil error, want net error")
	}
	p.Quit()
	if p.poolIsRunning() {
		t.Errorf("Got %v error, want false", p.poolIsRunning())
	}
}

func TestWithServer(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(testHandler))
	defer ts.Close()

	p := New(numWorkers)
	_ = p.Add(ts.URL, nil)
	task, ok := <-p.ResultChan
	if !ok {
		t.Error("Channel is closed'")
	}
	if string(task.Body) != "Test page" {
		t.Errorf("Got %v error, want 'Test page'", string(task.Body))
	}
	p.EndWaitingTasks()
	err := p.Add(ts.URL, nil)
	if err != errNotWait {
		t.Errorf("Got %v error, want %v", err, errNotWait)
	}
	if p.GetCompletedTasks() == 0 {
		t.Errorf("Got %v error, want %v", 0, 1)
	}
	if !p.isCompleteJobs() {
		t.Errorf("Got %v error, want %v", false, true)
	}
}

func TestWithTimeout(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(testHandlerWithTimeout))
	defer ts.Close()

	p := New(1)
	p.SetTimeout(100)
	err := p.Add(ts.URL, nil)
	if err != nil {
		t.Errorf("Got %v error, want %v", err, nil)
	}
	task, ok := <-p.ResultChan
	if !ok {
		t.Error("Channel is closed'")
	}
	if string(task.Body) != "Test page with timeout" {
		t.Errorf("Got %v error, want 'Test page with timeout'", string(task.Body))
	}
	p.timeout = time.Duration(1) * time.Millisecond
	err = p.Add(ts.URL, nil)
	if err != nil {
		t.Errorf("Got %v error, want %v", err, nil)
	}
	task, ok = <-p.ResultChan
	if !ok {
		t.Error("Channel is closed'")
	}
	if task.Error == nil {
		t.Errorf("Got no error, want %v", task.Error)
	}
	_ = p.Add(ts.URL, nil)
	p.Quit()
	if p.GetCompletedTasks() != 2 {
		t.Errorf("Got %v error, want %v", p.GetCompletedTasks(), 2)
	}
	task, ok = <-p.ResultChan
	if ok {
		t.Errorf("Got %v error, want %v", ok, false)
	}
	if task != nil {
		t.Errorf("Got %v error, want %v", task, nil)
	}
	if p.poolIsRunning() {
		t.Errorf("Got %v error, want %v", !p.poolIsRunning(), false)
	}
	err = p.Add(ts.URL, nil)
	if err != errNotRun {
		t.Errorf("Got %v error, want %v", err, errNotRun)
	}
}

func TestQuitTimeout(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(testHandlerWithTimeout))
	defer ts.Close()

	p := New(1)
	p.SetTimeout(30)
	p.SetQuitTimeout(2)
	_ = p.Add(ts.URL, nil)
	_ = p.Add(ts.URL, nil)
	for range p.ResultChan {
	}
	if p.GetCompletedTasks() != 2 {
		t.Errorf("Got %v error, want %v", p.GetCompletedTasks(), 1)
	}
}

func TestWaitingTasks(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(testHandler))
	defer ts.Close()

	p := New(1)
	_ = p.Add(ts.URL, nil)
	_ = p.Add(ts.URL, nil)
	p.EndWaitingTasks()
	for range p.ResultChan {
	}
	if p.GetCompletedTasks() != 2 {
		t.Errorf("Got %v error, want %v", p.GetCompletedTasks(), 1)
	}
}

func BenchmarkAccumulate(b *testing.B) {
	ts := httptest.NewServer(http.HandlerFunc(testHandler))
	defer ts.Close()
	b.ResetTimer()

	p := New(numWorkers)
	n := b.N
	for i := 0; i < n; i++ {
		err := p.Add(ts.URL, nil)
		if err != nil {
			b.Errorf("Got %v error, want %v", err, nil)
		}
	}
	for i := 0; i < n; i++ {
		task := <-p.ResultChan
		err := task.Error
		if err != nil {
			b.Error("Error", err)
		}
	}
}

func BenchmarkParallel(b *testing.B) {
	ts := httptest.NewServer(http.HandlerFunc(testHandler))
	defer ts.Close()
	b.ResetTimer()

	p := New(numWorkers)
	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			err := p.Add(ts.URL, nil)
			if err != nil {
				b.Errorf("Got %v error, want %v", err, nil)
			}
		}
	})
	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			task := <-p.ResultChan
			_ = task.Error
			// if err != nil {
			// 	b.Error("Error", err)
			// }
		}
	})
}
<|endoftext|>