<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package tchannel

import (
	"fmt"
)

const (
	// Message id for protocol level errors
	invalidMessageID uint32 = 0xFFFFFFFF
)

// A SystemErrCode indicates how a caller should handle a system error returned from a peer
type SystemErrCode byte

const (
	// ErrCodeInvalid is an invalid error code, and should not be used
	ErrCodeInvalid SystemErrCode = 0x00

	// ErrCodeTimeout indicates the peer timed out.  Callers can retry the request
	// on another peer if the request is safe to retry.
	ErrCodeTimeout SystemErrCode = 0x01

	// ErrCodeCancelled indicates that the request was cancelled on the peer.  Callers
	// can retry the request on the same or another peer if the request is safe to retry
	ErrCodeCancelled SystemErrCode = 0x02

	// ErrCodeBusy indicates that the request was not dispatched because the peer
	// was too busy to handle it.  Callers can retry the request on another peer, and should
	// reweight their connections to direct less traffic to this peer until it recovers.
	ErrCodeBusy SystemErrCode = 0x03

	// ErrCodeDeclined indicates that the request not dispatched because the peer
	// declined to handle it, typically because the peer is not yet ready to handle it.
	// Callers can retry the request on another peer, but should not reweight their connections
	// and should continue to send traffic to this peer.
	ErrCodeDeclined SystemErrCode = 0x04

	// ErrCodeUnexpected indicates that the request failed for an unexpected reason, typically
	// a crash or other unexpected handling.  The request may have been processed before the failure;
	// callers should retry the request on this or another peer only if the request is safe to retry
	ErrCodeUnexpected SystemErrCode = 0x05

	// ErrCodeBadRequest indicates that the request was malformed, and could not be processed.
	// Callers should not bother to retry the request, as there is no chance it will be handled.
	ErrCodeBadRequest SystemErrCode = 0x06

	// ErrCodeNetwork indicates a network level error, such as a connection reset.
	// Callers can retry the request if the request is safe to retry
	ErrCodeNetwork SystemErrCode = 0x07

	// ErrCodeProtocol indincates a fatal protocol error communicating with the peer.  The connection
	// will be terminated.
	ErrCodeProtocol SystemErrCode = 0xFF
)

var (
	// ErrServerBusy is a SystemError indicating the server is busy
	ErrServerBusy = NewSystemError(ErrCodeBusy, "server busy")

	// ErrRequestCancelled is a SystemError indicating the request has been cancelled on the peer
	ErrRequestCancelled = NewSystemError(ErrCodeCancelled, "request cancelled")

	// ErrTimeout is a SytemError indicating the request has timed out
	ErrTimeout = NewSystemError(ErrCodeTimeout, "timeout")

	// ErrTimeoutRequired is a SystemError indicating that timeouts must be specified.
	ErrTimeoutRequired = NewSystemError(ErrCodeBadRequest, "timeout required")

	// ErrChannelClosed is a SystemError indicating that the channel has been closed.
	ErrChannelClosed = NewSystemError(ErrCodeDeclined, "closed channel")

	// ErrOperationTooLarge is a SystemError indicating that the operation is too large.
	ErrOperationTooLarge = NewSystemError(ErrCodeProtocol, "operation too large")
)

// A SystemError is a system-level error, containing an error code and message
// TODO(mmihic): Probably we want to hide this interface, and let application code
// just deal with standard raw errors.
type SystemError struct {
	code    SystemErrCode
	msg     string
	wrapped error
}

// NewSystemError defines a new SystemError with a code and message
func NewSystemError(code SystemErrCode, msg string, args ...interface{}) error {
	return SystemError{code: code, msg: fmt.Sprintf(msg, args...)}
}

// NewWrappedSystemError defines a new SystemError wrapping an existing error
func NewWrappedSystemError(code SystemErrCode, wrapped error) error {
	return SystemError{code: code, msg: fmt.Sprintf("sys err %x: %s", code, wrapped.Error()), wrapped: wrapped}
}

// Error returns the SystemError message, conforming to the error interface
func (se SystemError) Error() string {
	return se.msg
}

// Wrapped returns the wrapped error
func (se SystemError) Wrapped() error { return se.wrapped }

// Code returns the SystemError code, for sending to a peer
func (se SystemError) Code() SystemErrCode {
	return se.code
}

// GetSystemErrorCode returns the code to report for the given error.  If the error is a SystemError, we can
// get the code directly.  Otherwise treat it as an unexpected error
func GetSystemErrorCode(err error) SystemErrCode {
	if se, ok := err.(SystemError); ok {
		return se.Code()
	}

	return ErrCodeUnexpected
}
<commit_msg>Add method to check if an error is a SystemError<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package tchannel

import (
	"fmt"
)

const (
	// Message id for protocol level errors
	invalidMessageID uint32 = 0xFFFFFFFF
)

// A SystemErrCode indicates how a caller should handle a system error returned from a peer
type SystemErrCode byte

const (
	// ErrCodeInvalid is an invalid error code, and should not be used
	ErrCodeInvalid SystemErrCode = 0x00

	// ErrCodeTimeout indicates the peer timed out.  Callers can retry the request
	// on another peer if the request is safe to retry.
	ErrCodeTimeout SystemErrCode = 0x01

	// ErrCodeCancelled indicates that the request was cancelled on the peer.  Callers
	// can retry the request on the same or another peer if the request is safe to retry
	ErrCodeCancelled SystemErrCode = 0x02

	// ErrCodeBusy indicates that the request was not dispatched because the peer
	// was too busy to handle it.  Callers can retry the request on another peer, and should
	// reweight their connections to direct less traffic to this peer until it recovers.
	ErrCodeBusy SystemErrCode = 0x03

	// ErrCodeDeclined indicates that the request not dispatched because the peer
	// declined to handle it, typically because the peer is not yet ready to handle it.
	// Callers can retry the request on another peer, but should not reweight their connections
	// and should continue to send traffic to this peer.
	ErrCodeDeclined SystemErrCode = 0x04

	// ErrCodeUnexpected indicates that the request failed for an unexpected reason, typically
	// a crash or other unexpected handling.  The request may have been processed before the failure;
	// callers should retry the request on this or another peer only if the request is safe to retry
	ErrCodeUnexpected SystemErrCode = 0x05

	// ErrCodeBadRequest indicates that the request was malformed, and could not be processed.
	// Callers should not bother to retry the request, as there is no chance it will be handled.
	ErrCodeBadRequest SystemErrCode = 0x06

	// ErrCodeNetwork indicates a network level error, such as a connection reset.
	// Callers can retry the request if the request is safe to retry
	ErrCodeNetwork SystemErrCode = 0x07

	// ErrCodeProtocol indincates a fatal protocol error communicating with the peer.  The connection
	// will be terminated.
	ErrCodeProtocol SystemErrCode = 0xFF
)

var (
	// ErrServerBusy is a SystemError indicating the server is busy
	ErrServerBusy = NewSystemError(ErrCodeBusy, "server busy")

	// ErrRequestCancelled is a SystemError indicating the request has been cancelled on the peer
	ErrRequestCancelled = NewSystemError(ErrCodeCancelled, "request cancelled")

	// ErrTimeout is a SytemError indicating the request has timed out
	ErrTimeout = NewSystemError(ErrCodeTimeout, "timeout")

	// ErrTimeoutRequired is a SystemError indicating that timeouts must be specified.
	ErrTimeoutRequired = NewSystemError(ErrCodeBadRequest, "timeout required")

	// ErrChannelClosed is a SystemError indicating that the channel has been closed.
	ErrChannelClosed = NewSystemError(ErrCodeDeclined, "closed channel")

	// ErrOperationTooLarge is a SystemError indicating that the operation is too large.
	ErrOperationTooLarge = NewSystemError(ErrCodeProtocol, "operation too large")
)

// A SystemError is a system-level error, containing an error code and message
// TODO(mmihic): Probably we want to hide this interface, and let application code
// just deal with standard raw errors.
type SystemError struct {
	code    SystemErrCode
	msg     string
	wrapped error
}

// NewSystemError defines a new SystemError with a code and message
func NewSystemError(code SystemErrCode, msg string, args ...interface{}) error {
	return SystemError{code: code, msg: fmt.Sprintf(msg, args...)}
}

// NewWrappedSystemError defines a new SystemError wrapping an existing error
func NewWrappedSystemError(code SystemErrCode, wrapped error) error {
	return SystemError{code: code, msg: fmt.Sprintf("sys err %x: %s", code, wrapped.Error()), wrapped: wrapped}
}

// Error returns the SystemError message, conforming to the error interface
func (se SystemError) Error() string {
	return se.msg
}

// Wrapped returns the wrapped error
func (se SystemError) Wrapped() error { return se.wrapped }

// Code returns the SystemError code, for sending to a peer
func (se SystemError) Code() SystemErrCode {
	return se.code
}

// IsSystemError returns whether the error is a system error.
func IsSystemError(err error) bool {
	_, ok := err.(SystemError)
	return ok
}

// GetSystemErrorCode returns the code to report for the given error.  If the error is a SystemError, we can
// get the code directly.  Otherwise treat it as an unexpected error
func GetSystemErrorCode(err error) SystemErrCode {
	if se, ok := err.(SystemError); ok {
		return se.Code()
	}

	return ErrCodeUnexpected
}
<|endoftext|>


<commit_before>package telebot

import (
	"fmt"
	"regexp"
	"strings"
)

type APIError struct {
	Code        int
	Description string
	Message     string
}

// ʔ returns description of error.
// A tiny shortcut to make code clearier.
func (err *APIError) ʔ() string {
	return err.Description
}

// Error implements error interface.
func (err *APIError) Error() string {
	msg := err.Message
	if msg == "" {
		split := strings.Split(err.Description, ": ")
		if len(split) == 2 {
			msg = split[1]
		} else {
			msg = err.Description
		}
	}
	return fmt.Sprintf("telegram: %s (%d)", msg, err.Code)
}

// NewAPIError returns new APIError instance with given description.
// First element of msgs is Description. The second is optional Message.
func NewAPIError(code int, msgs ...string) *APIError {
	err := &APIError{Code: code}
	if len(msgs) >= 1 {
		err.Description = msgs[0]
	}
	if len(msgs) >= 2 {
		err.Message = msgs[1]
	}
	return err
}

var errorRx = regexp.MustCompile(`{.+"error_code":(\d+),"description":"(.+)"}`)

var (
	// General errors
	ErrUnauthorized      = NewAPIError(401, "Unauthorized")
	ErrBlockedByUser     = NewAPIError(401, "Forbidden: bot was blocked by the user")
	ErrUserIsDeactivated = NewAPIError(401, "Forbidden: user is deactivated")
	ErrNotFound          = NewAPIError(404, "Not Found")
	ErrInternal          = NewAPIError(500, "Internal Server Error ")

	// Bad request errors
	ErrTooLarge             = NewAPIError(400, "Request Entity Too Large")
	ErrMessageTooLong       = NewAPIError(400, "Bad Request: message is too long")
	ErrToForwardNotFound    = NewAPIError(400, "Bad Request: message to forward not found")
	ErrToReplyNotFound      = NewAPIError(400, "Bad Request: reply message not found")
	ErrToDeleteNotFound     = NewAPIError(400, "Bad Request: message to delete not found")
	ErrEmptyMessage         = NewAPIError(400, "Bad Request: message must be non-empty")
	ErrEmptyText            = NewAPIError(400, "Bad Request: text is empty")
	ErrEmptyChatID          = NewAPIError(400, "Bad Request: chat_id is empty")
	ErrChatNotFound         = NewAPIError(400, "Bad Request: chat not found")
	ErrMessageNotModified   = NewAPIError(400, "Bad Request: message is not modified")
	ErrButtonDataInvalid    = NewAPIError(400, "Bad Request: BUTTON_DATA_INVALID")
	ErrWrongTypeOfContent   = NewAPIError(400, "Bad Request: wrong type of the web page content")
	ErrBadURLContent        = NewAPIError(400, "Bad Request: failed to get HTTP URL content")
	ErrWrongFileID          = NewAPIError(400, "Bad Request: wrong file identifier/HTTP URL specified")
	ErrWrongFileIDSymbol    = NewAPIError(400, "Bad Request: wrong remote file id specified: can't unserialize it. Wrong last symbol")
	ErrWrongFileIDLength    = NewAPIError(400, "Bad Request: wrong remote file id specified: Wrong string length")
	ErrWrongFileIDCharacter = NewAPIError(400, "Bad Request: wrong remote file id specified: Wrong character in the string")
	ErrWrongFileIDPadding   = NewAPIError(400, "Bad Request: wrong remote file id specified: Wrong padding in the string")
	ErrFailedImageProcess   = NewAPIError(400, "Bad Request: IMAGE_PROCESS_FAILED", "Image process failed")
	ErrInvaliadStickerset   = NewAPIError(400, "Bad Request: STICKERSET_INVALID", "Stickerset is invalid")
	ErrBadPollOptions       = NewAPIError(400, "Bad Request: expected Array of String as options")

	// No rights errors
	ErrNoRightsToRestrict     = NewAPIError(400, "Bad Request: not enough rights to restrict/unrestrict chat member")
	ErrNoRightsToSend         = NewAPIError(400, "Bad Request: have no rights to send a message")
	ErrNoRightsToSendPhoto    = NewAPIError(400, "Bad Request: not enough rights to send photos to the chat")
	ErrNoRightsToSendStickers = NewAPIError(400, "Bad Request: not enough rights to send stickers to the chat")
	ErrNoRightsToSendGifs     = NewAPIError(400, "Bad Request: CHAT_SEND_GIFS_FORBIDDEN", "sending GIFS is not allowed in this chat")
	ErrNoRightsToDelete       = NewAPIError(400, "Bad Request: message can't be deleted")
	ErrKickingChatOwner       = NewAPIError(400, "Bad Request: can't remove chat owner")

	// Super/groups errors
	ErrBotKickedFromGroup      = NewAPIError(403, "Forbidden: bot was kicked from the group chat")
	ErrBotKickedFromSuperGroup = NewAPIError(403, "Forbidden: bot was kicked from the supergroup chat")
)

// ErrByDescription returns APIError instance by given description.
func ErrByDescription(s string) error {
	switch s {
	case ErrUnauthorized.ʔ():
		return ErrUnauthorized
	case ErrNotFound.ʔ():
		return ErrNotFound
	case ErrUserIsDeactivated.ʔ():
		return ErrUserIsDeactivated
	case ErrToForwardNotFound.ʔ():
		return ErrToForwardNotFound
	case ErrToReplyNotFound.ʔ():
		return ErrToReplyNotFound
	case ErrMessageTooLong.ʔ():
		return ErrMessageTooLong
	case ErrBlockedByUser.ʔ():
		return ErrBlockedByUser
	case ErrToDeleteNotFound.ʔ():
		return ErrToDeleteNotFound
	case ErrEmptyMessage.ʔ():
		return ErrEmptyMessage
	case ErrEmptyText.ʔ():
		return ErrEmptyText
	case ErrEmptyChatID.ʔ():
		return ErrEmptyChatID
	case ErrChatNotFound.ʔ():
		return ErrChatNotFound
	case ErrMessageNotModified.ʔ():
		return ErrMessageNotModified
	case ErrButtonDataInvalid.ʔ():
		return ErrButtonDataInvalid
	case ErrBadPollOptions.ʔ():
		return ErrBadPollOptions
	case ErrNoRightsToRestrict.ʔ():
		return ErrNoRightsToRestrict
	case ErrNoRightsToSend.ʔ():
		return ErrNoRightsToSend
	case ErrNoRightsToSendPhoto.ʔ():
		return ErrNoRightsToSendPhoto
	case ErrNoRightsToSendStickers.ʔ():
		return ErrNoRightsToSendStickers
	case ErrNoRightsToSendGifs.ʔ():
		return ErrNoRightsToSendGifs
	case ErrNoRightsToDelete.ʔ():
		return ErrNoRightsToDelete
	case ErrKickingChatOwner.ʔ():
		return ErrKickingChatOwner
	case ErrBotKickedFromGroup.ʔ():
		return ErrKickingChatOwner
	case ErrBotKickedFromSuperGroup.ʔ():
		return ErrBotKickedFromSuperGroup
	case ErrWrongTypeOfContent.ʔ():
		return ErrWrongTypeOfContent
	case ErrBadURLContent.ʔ():
		return ErrBadURLContent
	case ErrWrongFileIDSymbol.ʔ():
		return ErrWrongFileIDSymbol
	case ErrWrongFileIDLength.ʔ():
		return ErrWrongFileIDLength
	case ErrWrongFileIDCharacter.ʔ():
		return ErrWrongFileIDCharacter
	case ErrWrongFileID.ʔ():
		return ErrWrongFileID
	case ErrTooLarge.ʔ():
		return ErrTooLarge
	case ErrWrongFileIDPadding.ʔ():
		return ErrWrongFileIDPadding
	case ErrFailedImageProcess.ʔ():
		return ErrFailedImageProcess
	case ErrInvaliadStickerset.ʔ():
		return ErrInvaliadStickerset
	default:
		return nil
	}
}
<commit_msg>errors: remove extra space<commit_after>package telebot

import (
	"fmt"
	"regexp"
	"strings"
)

type APIError struct {
	Code        int
	Description string
	Message     string
}

// ʔ returns description of error.
// A tiny shortcut to make code clearier.
func (err *APIError) ʔ() string {
	return err.Description
}

// Error implements error interface.
func (err *APIError) Error() string {
	msg := err.Message
	if msg == "" {
		split := strings.Split(err.Description, ": ")
		if len(split) == 2 {
			msg = split[1]
		} else {
			msg = err.Description
		}
	}
	return fmt.Sprintf("telegram: %s (%d)", msg, err.Code)
}

// NewAPIError returns new APIError instance with given description.
// First element of msgs is Description. The second is optional Message.
func NewAPIError(code int, msgs ...string) *APIError {
	err := &APIError{Code: code}
	if len(msgs) >= 1 {
		err.Description = msgs[0]
	}
	if len(msgs) >= 2 {
		err.Message = msgs[1]
	}
	return err
}

var errorRx = regexp.MustCompile(`{.+"error_code":(\d+),"description":"(.+)"}`)

var (
	// General errors
	ErrUnauthorized      = NewAPIError(401, "Unauthorized")
	ErrBlockedByUser     = NewAPIError(401, "Forbidden: bot was blocked by the user")
	ErrUserIsDeactivated = NewAPIError(401, "Forbidden: user is deactivated")
	ErrNotFound          = NewAPIError(404, "Not Found")
	ErrInternal          = NewAPIError(500, "Internal Server Error")

	// Bad request errors
	ErrTooLarge             = NewAPIError(400, "Request Entity Too Large")
	ErrMessageTooLong       = NewAPIError(400, "Bad Request: message is too long")
	ErrToForwardNotFound    = NewAPIError(400, "Bad Request: message to forward not found")
	ErrToReplyNotFound      = NewAPIError(400, "Bad Request: reply message not found")
	ErrToDeleteNotFound     = NewAPIError(400, "Bad Request: message to delete not found")
	ErrEmptyMessage         = NewAPIError(400, "Bad Request: message must be non-empty")
	ErrEmptyText            = NewAPIError(400, "Bad Request: text is empty")
	ErrEmptyChatID          = NewAPIError(400, "Bad Request: chat_id is empty")
	ErrChatNotFound         = NewAPIError(400, "Bad Request: chat not found")
	ErrMessageNotModified   = NewAPIError(400, "Bad Request: message is not modified")
	ErrButtonDataInvalid    = NewAPIError(400, "Bad Request: BUTTON_DATA_INVALID")
	ErrWrongTypeOfContent   = NewAPIError(400, "Bad Request: wrong type of the web page content")
	ErrBadURLContent        = NewAPIError(400, "Bad Request: failed to get HTTP URL content")
	ErrWrongFileID          = NewAPIError(400, "Bad Request: wrong file identifier/HTTP URL specified")
	ErrWrongFileIDSymbol    = NewAPIError(400, "Bad Request: wrong remote file id specified: can't unserialize it. Wrong last symbol")
	ErrWrongFileIDLength    = NewAPIError(400, "Bad Request: wrong remote file id specified: Wrong string length")
	ErrWrongFileIDCharacter = NewAPIError(400, "Bad Request: wrong remote file id specified: Wrong character in the string")
	ErrWrongFileIDPadding   = NewAPIError(400, "Bad Request: wrong remote file id specified: Wrong padding in the string")
	ErrFailedImageProcess   = NewAPIError(400, "Bad Request: IMAGE_PROCESS_FAILED", "Image process failed")
	ErrInvaliadStickerset   = NewAPIError(400, "Bad Request: STICKERSET_INVALID", "Stickerset is invalid")
	ErrBadPollOptions       = NewAPIError(400, "Bad Request: expected Array of String as options")

	// No rights errors
	ErrNoRightsToRestrict     = NewAPIError(400, "Bad Request: not enough rights to restrict/unrestrict chat member")
	ErrNoRightsToSend         = NewAPIError(400, "Bad Request: have no rights to send a message")
	ErrNoRightsToSendPhoto    = NewAPIError(400, "Bad Request: not enough rights to send photos to the chat")
	ErrNoRightsToSendStickers = NewAPIError(400, "Bad Request: not enough rights to send stickers to the chat")
	ErrNoRightsToSendGifs     = NewAPIError(400, "Bad Request: CHAT_SEND_GIFS_FORBIDDEN", "sending GIFS is not allowed in this chat")
	ErrNoRightsToDelete       = NewAPIError(400, "Bad Request: message can't be deleted")
	ErrKickingChatOwner       = NewAPIError(400, "Bad Request: can't remove chat owner")

	// Super/groups errors
	ErrBotKickedFromGroup      = NewAPIError(403, "Forbidden: bot was kicked from the group chat")
	ErrBotKickedFromSuperGroup = NewAPIError(403, "Forbidden: bot was kicked from the supergroup chat")
)

// ErrByDescription returns APIError instance by given description.
func ErrByDescription(s string) error {
	switch s {
	case ErrUnauthorized.ʔ():
		return ErrUnauthorized
	case ErrNotFound.ʔ():
		return ErrNotFound
	case ErrUserIsDeactivated.ʔ():
		return ErrUserIsDeactivated
	case ErrToForwardNotFound.ʔ():
		return ErrToForwardNotFound
	case ErrToReplyNotFound.ʔ():
		return ErrToReplyNotFound
	case ErrMessageTooLong.ʔ():
		return ErrMessageTooLong
	case ErrBlockedByUser.ʔ():
		return ErrBlockedByUser
	case ErrToDeleteNotFound.ʔ():
		return ErrToDeleteNotFound
	case ErrEmptyMessage.ʔ():
		return ErrEmptyMessage
	case ErrEmptyText.ʔ():
		return ErrEmptyText
	case ErrEmptyChatID.ʔ():
		return ErrEmptyChatID
	case ErrChatNotFound.ʔ():
		return ErrChatNotFound
	case ErrMessageNotModified.ʔ():
		return ErrMessageNotModified
	case ErrButtonDataInvalid.ʔ():
		return ErrButtonDataInvalid
	case ErrBadPollOptions.ʔ():
		return ErrBadPollOptions
	case ErrNoRightsToRestrict.ʔ():
		return ErrNoRightsToRestrict
	case ErrNoRightsToSend.ʔ():
		return ErrNoRightsToSend
	case ErrNoRightsToSendPhoto.ʔ():
		return ErrNoRightsToSendPhoto
	case ErrNoRightsToSendStickers.ʔ():
		return ErrNoRightsToSendStickers
	case ErrNoRightsToSendGifs.ʔ():
		return ErrNoRightsToSendGifs
	case ErrNoRightsToDelete.ʔ():
		return ErrNoRightsToDelete
	case ErrKickingChatOwner.ʔ():
		return ErrKickingChatOwner
	case ErrBotKickedFromGroup.ʔ():
		return ErrKickingChatOwner
	case ErrBotKickedFromSuperGroup.ʔ():
		return ErrBotKickedFromSuperGroup
	case ErrWrongTypeOfContent.ʔ():
		return ErrWrongTypeOfContent
	case ErrBadURLContent.ʔ():
		return ErrBadURLContent
	case ErrWrongFileIDSymbol.ʔ():
		return ErrWrongFileIDSymbol
	case ErrWrongFileIDLength.ʔ():
		return ErrWrongFileIDLength
	case ErrWrongFileIDCharacter.ʔ():
		return ErrWrongFileIDCharacter
	case ErrWrongFileID.ʔ():
		return ErrWrongFileID
	case ErrTooLarge.ʔ():
		return ErrTooLarge
	case ErrWrongFileIDPadding.ʔ():
		return ErrWrongFileIDPadding
	case ErrFailedImageProcess.ʔ():
		return ErrFailedImageProcess
	case ErrInvaliadStickerset.ʔ():
		return ErrInvaliadStickerset
	default:
		return nil
	}
}
<|endoftext|>


<commit_before>package solr

import (
	"fmt"
)

var ErrNotFound = NewNotFoundError("Not found")

type SolrError struct {
	errorMessage string
}

func (err SolrError) Error() string {
	return err.errorMessage
}

func NewSolrError(status int, message string) error {
	return SolrError{errorMessage: fmt.Sprintf("recieved error response from solr status: %d message: %s", status, message)}
}

func NewSolrRFError(rf, minRF int) error {
	return SolrMinRFError{SolrError{errorMessage: fmt.Sprintf("recieved error response from solr: rf (%d) is < min_rf (%d)", rf, minRF)}, minRF}
}

type SolrMinRFError struct {
	SolrError
	MinRF int
}

type SolrInternalError struct {
	SolrError
}

func NewSolrInternalError(status int, message string) error {
	return SolrInternalError{SolrError{errorMessage: fmt.Sprintf("recieved error response from solr status: %d message: %s", status, message)}}
}

type SolrLeaderError struct {
	SolrError
}

func NewSolrLeaderError(docID string) error {
	return SolrLeaderError{SolrError{errorMessage: fmt.Sprintf("Cannot find leader for doc %s", docID)}}
}

type SolrBatchError struct {
	error
}

func NewSolrBatchError(err error) error {
	return SolrBatchError{error: err}
}

type SolrParseError struct {
	SolrError
}

func NewSolrParseError(status int, message string) error {
	return SolrInternalError{SolrError{errorMessage: fmt.Sprintf("recieved error response from solr status: %d message: %s", status, message)}}
}

type SolrMapParseError struct {
	bucket string
	m      map[string]interface{}
	userId int
}

func (err SolrMapParseError) Error() string {
	return fmt.Sprintf("SolrMapParseErr: map does not contain email_register, bucket: %s, userId: %d map: %v", err.bucket, err.userId, err.m)

}
func NewSolrMapParseError(bucket string, userId int, m map[string]interface{}) error {
	return SolrMapParseError{bucket, m, userId}
}

type NotFoundError struct {
	errorMessage string
}

func (err NotFoundError) Error() string {
	return err.errorMessage
}

func NewNotFoundError(error string) error {
	return NotFoundError{errorMessage: error}
}
<commit_msg>minrf<commit_after>package solr

import (
	"fmt"
)

var ErrNotFound = NewNotFoundError("Not found")

type SolrError struct {
	errorMessage string
}

func (err SolrError) Error() string {
	return err.errorMessage
}

func NewSolrError(status int, message string) error {
	return SolrError{errorMessage: fmt.Sprintf("recieved error response from solr status: %d message: %s", status, message)}
}

func NewSolrRFError(rf, minRF int) error {
	return SolrMinRFError{SolrError{errorMessage: fmt.Sprintf("recieved error response from solr: rf (%d) is < min_rf (%d)", rf, minRF)}, rf}
}

type SolrMinRFError struct {
	SolrError
	MinRF int
}

type SolrInternalError struct {
	SolrError
}

func NewSolrInternalError(status int, message string) error {
	return SolrInternalError{SolrError{errorMessage: fmt.Sprintf("recieved error response from solr status: %d message: %s", status, message)}}
}

type SolrLeaderError struct {
	SolrError
}

func NewSolrLeaderError(docID string) error {
	return SolrLeaderError{SolrError{errorMessage: fmt.Sprintf("Cannot find leader for doc %s", docID)}}
}

type SolrBatchError struct {
	error
}

func NewSolrBatchError(err error) error {
	return SolrBatchError{error: err}
}

type SolrParseError struct {
	SolrError
}

func NewSolrParseError(status int, message string) error {
	return SolrInternalError{SolrError{errorMessage: fmt.Sprintf("recieved error response from solr status: %d message: %s", status, message)}}
}

type SolrMapParseError struct {
	bucket string
	m      map[string]interface{}
	userId int
}

func (err SolrMapParseError) Error() string {
	return fmt.Sprintf("SolrMapParseErr: map does not contain email_register, bucket: %s, userId: %d map: %v", err.bucket, err.userId, err.m)

}
func NewSolrMapParseError(bucket string, userId int, m map[string]interface{}) error {
	return SolrMapParseError{bucket, m, userId}
}

type NotFoundError struct {
	errorMessage string
}

func (err NotFoundError) Error() string {
	return err.errorMessage
}

func NewNotFoundError(error string) error {
	return NotFoundError{errorMessage: error}
}
<|endoftext|>


<commit_before>// Package video implements constants and functions related to
// the VIC-II video interface chip, such as colors.

package gfx

import (
	"encoding/hex"
	"fmt"
	"image/color"
	"log"
	"strings"
)

type Palette struct {
	Name   string
	Colors []color.Color
}

// Color index names
const (
	Black = iota
	White
	Red
	Cyan
	Purple
	Green
	Blue
	Yellow
	Orange
	Brown
	LightRed
	DarkGrey
	MediumGrey
	LightGreen
	LightBlue
	LightGrey
)

var PaletteMap = map[string]*Palette{}
var Colodore, Pepto, Levy, Vice, ViceOld, ViceNew *Palette

func init() {
	Colodore = MakePalette("colodore",
		"000000:ffffff:813338:75cec8:8e3c97:56ac4d:2e2c9b:edf171",
		"8e5029:553800:c46c71:4a4a4a:7b7b7b:a9ff9f:706deb:b2b2b2")
	Pepto = MakePalette("pepto",
		"000000:ffffff:68372b:70a4b2:6f3d86:588d43:352879:b8c76f",
		"6f4f25:433900:9a6759:444444:6c6c6c:9ad284:6c5eb5:959595")
	Levy = MakePalette("levy",
		"040204:fcfefc:cc3634:84f2dc:cc5ac4:5cce34:4436cc:f4ee5c",
		"d47e34:945e34:fc9a94:5c5a5c:8c8e8c:9cfe9c:74a2ec:c4c2c4")
	Vice = MakePalette("vice",
		"000000:fdfefc:be1a24:30e6c6:b41ae2:1fd21e:211bae:dff60a",
		"b84104:6a3304:fe4a57:424540:70746f:59fe59:5f53fe:a4a7a2")
	ViceOld = MakePalette("vice_old",
		"000000:d5d5d5:72352c:659fa6:733a91:568d35:2e237d:aeb75e",
		"774f1e:4b3c00:9c635a:474747:6b6b6b:8fc271:675db6:8f8f8f")
	ViceNew = MakePalette("vice_new",
		"000000:ffffff:b85438:8decff:ba56e4:79d949:553ee5:fbff79",
		"bd7c1b:7e6400:f29580:6f716e:a2a4a1:cdff9d:a18aff:d3d5d2")
}

func (p *Palette) Color(index int) color.Color {
	return p.Colors[index]
}

func PaletteByName(name string) *Palette {
	palette, ok := PaletteMap[name]
	if !ok {
		log.Printf("Invalid palette name %q, defaulting to %q.\n", name, "colodore")
		return Colodore
	}
	return palette
}

func PaletteBestMatch(colors []color.Color) *Palette {
	var bestMatch *Palette
	var bestScore = 0
	for _, pal := range PaletteMap {
		score := 0
		for _, ccol := range colors {
			for _, pcol := range pal.Colors {
				if ccol == pcol {
					score++
				}
			}
		}
		if pal.Name == "FORCE" {
			score = 9999
		}
		if score > bestScore {
			bestScore = score
			bestMatch = pal
		}
	}
	fmt.Printf("Palette %q won with a score of %d.\n", bestMatch.Name, bestScore)
	return bestMatch
}

func MakePalette(name string, values ...string) *Palette {
	valueStr := strings.Join(values, ":")
	colors := make([]color.Color, 16)
	for i, value := range strings.Split(valueStr, ":") {
		colors[i] = hexColor(value)
	}
	palette := &Palette{Name: name, Colors: colors}
	_, exists := PaletteMap[name]
	if !exists {
		PaletteMap[name] = palette
	}
	return palette
}

func hexColor(value string) color.Color {
	rgb, err := hex.DecodeString(value)
	if err != nil {
		panic(err)
	}
	return color.RGBA{rgb[0], rgb[1], rgb[2], 255}
}
<commit_msg>Added my VICE 3.4 palette.<commit_after>// Package video implements constants and functions related to
// the VIC-II video interface chip, such as colors.

package gfx

import (
	"encoding/hex"
	"fmt"
	"image/color"
	"log"
	"strings"
)

type Palette struct {
	Name   string
	Colors []color.Color
}

// Color index names
const (
	Black = iota
	White
	Red
	Cyan
	Purple
	Green
	Blue
	Yellow
	Orange
	Brown
	LightRed
	DarkGrey
	MediumGrey
	LightGreen
	LightBlue
	LightGrey
)

var PaletteMap = map[string]*Palette{}
var Colodore, Pepto, Levy, Vice, ViceOld, ViceNew, ViceLars *Palette

func init() {
	Colodore = MakePalette("colodore",
		"000000:ffffff:813338:75cec8:8e3c97:56ac4d:2e2c9b:edf171",
		"8e5029:553800:c46c71:4a4a4a:7b7b7b:a9ff9f:706deb:b2b2b2")
	Pepto = MakePalette("pepto",
		"000000:ffffff:68372b:70a4b2:6f3d86:588d43:352879:b8c76f",
		"6f4f25:433900:9a6759:444444:6c6c6c:9ad284:6c5eb5:959595")
	Levy = MakePalette("levy",
		"040204:fcfefc:cc3634:84f2dc:cc5ac4:5cce34:4436cc:f4ee5c",
		"d47e34:945e34:fc9a94:5c5a5c:8c8e8c:9cfe9c:74a2ec:c4c2c4")
	Vice = MakePalette("vice",
		"000000:fdfefc:be1a24:30e6c6:b41ae2:1fd21e:211bae:dff60a",
		"b84104:6a3304:fe4a57:424540:70746f:59fe59:5f53fe:a4a7a2")
	ViceOld = MakePalette("vice_old",
		"000000:d5d5d5:72352c:659fa6:733a91:568d35:2e237d:aeb75e",
		"774f1e:4b3c00:9c635a:474747:6b6b6b:8fc271:675db6:8f8f8f")
	ViceNew = MakePalette("vice_new",
		"000000:ffffff:b85438:8decff:ba56e4:79d949:553ee5:fbff79",
		"bd7c1b:7e6400:f29580:6f716e:a2a4a1:cdff9d:a18aff:d3d5d2")
	ViceLars = MakePalette("lars_3.4",
		"000000:ffffff:a75035:8ad9ec:b450bb:69c860:4f37e0:eafb5c",
		"ac7607:746000:da8c75:6a6a6a:999999:b3ffab:9480ff:c5c5c5")
}

func (p *Palette) Color(index int) color.Color {
	return p.Colors[index]
}

func PaletteByName(name string) *Palette {
	palette, ok := PaletteMap[name]
	if !ok {
		log.Printf("Invalid palette name %q, defaulting to %q.\n", name, "colodore")
		return Colodore
	}
	return palette
}

func PaletteBestMatch(colors []color.Color) *Palette {
	var bestMatch *Palette
	var bestScore = 0
	for _, pal := range PaletteMap {
		score := 0
		for _, ccol := range colors {
			for _, pcol := range pal.Colors {
				if ccol == pcol {
					score++
				}
			}
		}
		if pal.Name == "FORCE" {
			score = 9999
		}
		if score > bestScore {
			bestScore = score
			bestMatch = pal
		}
	}
	fmt.Printf("Palette %q won with a score of %d.\n", bestMatch.Name, bestScore)
	return bestMatch
}

func MakePalette(name string, values ...string) *Palette {
	valueStr := strings.Join(values, ":")
	colors := make([]color.Color, 16)
	for i, value := range strings.Split(valueStr, ":") {
		colors[i] = hexColor(value)
	}
	palette := &Palette{Name: name, Colors: colors}
	_, exists := PaletteMap[name]
	if !exists {
		PaletteMap[name] = palette
	}
	return palette
}

func hexColor(value string) color.Color {
	rgb, err := hex.DecodeString(value)
	if err != nil {
		panic(err)
	}
	return color.RGBA{rgb[0], rgb[1], rgb[2], 255}
}
<|endoftext|>


<commit_before>package analyze

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"regexp"

	"github.com/deckarep/golang-set"
	"github.com/jzelinskie/geddit"
)

func AnalyzeComments(s *geddit.OAuthSession, comments []*geddit.Comment) error {
	r, err := regexp.Compile(`github\.com\/\w+\/\w+`)
	if err != nil {
		return err
	}
	for _, comment := range comments {
		if comment.Author == "github-stats-bot" {
			continue
		}
		if r.MatchString(comment.Body) {
			linkSet := mapset.NewSet()
			for _, link := range r.FindAllString(comment.Body, -1) {
				linkSet.Add(link)
			}
			var links []string
			for _, link := range linkSet.ToSlice() {
				links = append(links, link.(string))
			}
			if err = postReply(s, comment, links); err != nil {
				return err
			}
		}
	}
	return nil
}

func postReply(s *geddit.OAuthSession, comment *geddit.Comment, links []string) error {
	footer := "***\n^(This is Earth radio, and now here's human music ♫)\n\n^[Source](https://github.com/anaskhan96/github-stats-bot) ^| ^[PMme](https://np.reddit.com/message/compose?to=github-stats-bot)"
	var reply string
	for _, link := range links {
		var data map[string]interface{}
		if err := getStats(link, &data); err != nil {
			return err
		}
		if data["message"] == "Not Found" {
			return errors.New("Wrong GitHub API endpoint")
		}
		description := data["description"]
		stargazers := data["stargazers_count"]
		forks := data["forks_count"]
		issuesURL := "https://" + link + "/issues"
		pullsURL := "https://" + link + "/pulls"
		reply += fmt.Sprintf("\n[%s](https://%s)\n\n> *Description*: %v\n\n> *Stars*: %v\n\n> *Forks*: %v\n\n> [Issues](%s) | [Pull Requests](%s)\n\n",
			link[11:], link, description, stargazers, forks, issuesURL, pullsURL)
	}
	reply += footer
	if _, err := s.Reply(comment, reply); err != nil {
		return err
	}
	return nil
}

func getStats(link string, data *map[string]interface{}) error {
	res, err := http.Get("https://api.github.com/repos/" + link[11:])
	if err != nil {
		return err
	}
	defer res.Body.Close()
	if err = json.NewDecoder(res.Body).Decode(&data); err != nil {
		return err
	}
	return nil
}
<commit_msg>correcting regex<commit_after>package analyze

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"regexp"

	"github.com/deckarep/golang-set"
	"github.com/jzelinskie/geddit"
)

func AnalyzeComments(s *geddit.OAuthSession, comments []*geddit.Comment) error {
	r, err := regexp.Compile(`github\.com\/[\w\-]+\/[\w\-]+`)
	if err != nil {
		return err
	}
	for _, comment := range comments {
		if comment.Author == "github-stats-bot" {
			continue
		}
		if r.MatchString(comment.Body) {
			linkSet := mapset.NewSet()
			for _, link := range r.FindAllString(comment.Body, -1) {
				linkSet.Add(link)
			}
			var links []string
			for _, link := range linkSet.ToSlice() {
				links = append(links, link.(string))
			}
			if err = postReply(s, comment, links); err != nil {
				return err
			}
		}
	}
	return nil
}

func postReply(s *geddit.OAuthSession, comment *geddit.Comment, links []string) error {
	footer := "***\n^(This is Earth radio, and now here's human music ♫)\n\n^[Source](https://github.com/anaskhan96/github-stats-bot) ^| ^[PMme](https://np.reddit.com/message/compose?to=github-stats-bot)"
	var reply string
	for _, link := range links {
		var data map[string]interface{}
		if err := getStats(link, &data); err != nil {
			return err
		}
		if data["message"] == "Not Found" {
			return errors.New("Wrong GitHub API endpoint")
		}
		description := data["description"]
		stargazers := data["stargazers_count"]
		forks := data["forks_count"]
		issuesURL := "https://" + link + "/issues"
		pullsURL := "https://" + link + "/pulls"
		reply += fmt.Sprintf("\n[%s](https://%s)\n\n> *Description*: %v\n\n> *Stars*: %v\n\n> *Forks*: %v\n\n> [Issues](%s) | [Pull Requests](%s)\n\n",
			link[11:], link, description, stargazers, forks, issuesURL, pullsURL)
	}
	reply += footer
	if _, err := s.Reply(comment, reply); err != nil {
		return err
	}
	return nil
}

func getStats(link string, data *map[string]interface{}) error {
	res, err := http.Get("https://api.github.com/repos/" + link[11:])
	if err != nil {
		return err
	}
	defer res.Body.Close()
	if err = json.NewDecoder(res.Body).Decode(&data); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package pretty

import (
	"fmt"
	"github.com/MakeNowJust/heredoc"
	"strings"
)

func Bash(s string) string {
	return fmt.Sprintf("`%s`", s)
}

func LongDesc(s string) string {
	s = heredoc.Doc(s)
	s = strings.TrimSpace(s)
	return s
}
<commit_msg>Add function godocs<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package pretty

import (
	"fmt"
	"github.com/MakeNowJust/heredoc"
	"strings"
)

// Bash markdown-quotes a bash command for insertion into help text.
func Bash(s string) string {
	return fmt.Sprintf("`%s`", s)
}

// LongDesc is used for formatting help text for a commands Long Description.
// It de-dents it and trims it.
func LongDesc(s string) string {
	s = heredoc.Doc(s)
	s = strings.TrimSpace(s)
	return s
}
<|endoftext|>


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

import (
	"context"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"testing"

	"gvisor.dev/gvisor/pkg/cleanup"
	"gvisor.dev/gvisor/pkg/test/dockerutil"
	"gvisor.dev/gvisor/test/benchmarks/harness"
	"gvisor.dev/gvisor/test/benchmarks/tools"
)

// BenchmarkFio runs fio on the runtime under test. There are 4 basic test
// cases each run on a tmpfs mount and a bind mount. Fio requires root so that
// caches can be dropped.
func BenchmarkFio(b *testing.B) {
	testCases := []tools.Fio{
		{
			Test:      "write",
			BlockSize: 4,
			IODepth:   4,
		},
		{
			Test:      "write",
			BlockSize: 1024,
			IODepth:   4,
		},
		{
			Test:      "read",
			BlockSize: 4,
			IODepth:   4,
		},
		{
			Test:      "read",
			BlockSize: 1024,
			IODepth:   4,
		},
		{
			Test:      "randwrite",
			BlockSize: 4,
			IODepth:   4,
		},
		{
			Test:      "randread",
			BlockSize: 4,
			IODepth:   4,
		},
	}

	machine, err := harness.GetMachine()
	if err != nil {
		b.Fatalf("failed to get machine with: %v", err)
	}
	defer machine.CleanUp()

	for _, fsType := range []harness.FileSystemType{harness.BindFS, harness.TmpFS, harness.RootFS} {
		for _, tc := range testCases {
			operation := tools.Parameter{
				Name:  "operation",
				Value: tc.Test,
			}
			blockSize := tools.Parameter{
				Name:  "blockSize",
				Value: fmt.Sprintf("%dK", tc.BlockSize),
			}
			filesystem := tools.Parameter{
				Name:  "filesystem",
				Value: string(fsType),
			}
			name, err := tools.ParametersToName(operation, blockSize, filesystem)
			if err != nil {
				b.Fatalf("Failed to parser paramters: %v", err)
			}
			b.Run(name, func(b *testing.B) {
				b.StopTimer()
				tc.Size = b.N

				ctx := context.Background()
				container := machine.GetContainer(ctx, b)
				cu := cleanup.Make(func() {
					container.CleanUp(ctx)
				})
				defer cu.Clean()

				mnts, outdir, err := harness.MakeMount(machine, fsType, &cu)
				if err != nil {
					b.Fatalf("failed to make mount: %v", err)
				}

				// Start the container with the mount.
				if err := container.Spawn(
					ctx, dockerutil.RunOpts{
						Image:  "benchmarks/fio",
						Mounts: mnts,
					},
					// Sleep on the order of b.N.
					"sleep", fmt.Sprintf("%d", 1000*b.N),
				); err != nil {
					b.Fatalf("failed to start fio container with: %v", err)
				}

				if out, err := container.Exec(ctx, dockerutil.ExecOpts{},
					"mkdir", "-p", outdir); err != nil {
					b.Fatalf("failed to copy directory: %v (%s)", err, out)
				}

				// Directory and filename inside container where fio will read/write.
				outfile := filepath.Join(outdir, "test.txt")

				// For reads, we need a file to read so make one inside the container.
				if strings.Contains(tc.Test, "read") {
					fallocateCmd := fmt.Sprintf("fallocate -l %dM %s", tc.Size, outfile)
					if out, err := container.Exec(ctx, dockerutil.ExecOpts{},
						strings.Split(fallocateCmd, " ")...); err != nil {
						b.Fatalf("failed to create readable file on mount: %v, %s", err, out)
					}
				}

				// Drop caches just before running.
				if err := harness.DropCaches(machine); err != nil {
					b.Skipf("failed to drop caches with %v. You probably need root.", err)
				}

				cmd := tc.MakeCmd(outfile)
				if err := harness.DropCaches(machine); err != nil {
					b.Fatalf("failed to drop caches: %v", err)
				}

				// Run fio.
				b.StartTimer()
				data, err := container.Exec(ctx, dockerutil.ExecOpts{}, cmd...)
				if err != nil {
					b.Fatalf("failed to run cmd %v: %v", cmd, err)
				}
				b.StopTimer()
				tc.Report(b, data)
			})
		}
	}
}

// TestMain is the main method for package fs.
func TestMain(m *testing.M) {
	harness.Init()
	os.Exit(m.Run())
}
<commit_msg>benchmarks: add more blocksize arguments for fio benchmark<commit_after>// Copyright 2020 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fio_test

import (
	"context"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"testing"

	"gvisor.dev/gvisor/pkg/cleanup"
	"gvisor.dev/gvisor/pkg/test/dockerutil"
	"gvisor.dev/gvisor/test/benchmarks/harness"
	"gvisor.dev/gvisor/test/benchmarks/tools"
)

// BenchmarkFio runs fio on the runtime under test. There are 4 basic test
// cases each run on a tmpfs mount and a bind mount. Fio requires root so that
// caches can be dropped.
func BenchmarkFio(b *testing.B) {
	testCases := []tools.Fio{
		{
			Test:      "write",
			BlockSize: 4,
			IODepth:   4,
		},
		{
			Test:      "write",
			BlockSize: 64,
			IODepth:   4,
		},
		{
			Test:      "write",
			BlockSize: 1024,
			IODepth:   4,
		},
		{
			Test:      "read",
			BlockSize: 4,
			IODepth:   4,
		},
		{
			Test:      "read",
			BlockSize: 64,
			IODepth:   4,
		},
		{
			Test:      "read",
			BlockSize: 1024,
			IODepth:   4,
		},
		{
			Test:      "randwrite",
			BlockSize: 4,
			IODepth:   4,
		},
		{
			Test:      "randread",
			BlockSize: 4,
			IODepth:   4,
		},
	}

	machine, err := harness.GetMachine()
	if err != nil {
		b.Fatalf("failed to get machine with: %v", err)
	}
	defer machine.CleanUp()

	for _, fsType := range []harness.FileSystemType{harness.BindFS, harness.TmpFS, harness.RootFS} {
		for _, tc := range testCases {
			operation := tools.Parameter{
				Name:  "operation",
				Value: tc.Test,
			}
			blockSize := tools.Parameter{
				Name:  "blockSize",
				Value: fmt.Sprintf("%dK", tc.BlockSize),
			}
			filesystem := tools.Parameter{
				Name:  "filesystem",
				Value: string(fsType),
			}
			name, err := tools.ParametersToName(operation, blockSize, filesystem)
			if err != nil {
				b.Fatalf("Failed to parser paramters: %v", err)
			}
			b.Run(name, func(b *testing.B) {
				b.StopTimer()
				tc.Size = b.N

				ctx := context.Background()
				container := machine.GetContainer(ctx, b)
				cu := cleanup.Make(func() {
					container.CleanUp(ctx)
				})
				defer cu.Clean()

				mnts, outdir, err := harness.MakeMount(machine, fsType, &cu)
				if err != nil {
					b.Fatalf("failed to make mount: %v", err)
				}

				// Start the container with the mount.
				if err := container.Spawn(
					ctx, dockerutil.RunOpts{
						Image:  "benchmarks/fio",
						Mounts: mnts,
					},
					// Sleep on the order of b.N.
					"sleep", fmt.Sprintf("%d", 1000*b.N),
				); err != nil {
					b.Fatalf("failed to start fio container with: %v", err)
				}

				if out, err := container.Exec(ctx, dockerutil.ExecOpts{},
					"mkdir", "-p", outdir); err != nil {
					b.Fatalf("failed to copy directory: %v (%s)", err, out)
				}

				// Directory and filename inside container where fio will read/write.
				outfile := filepath.Join(outdir, "test.txt")

				// For reads, we need a file to read so make one inside the container.
				if strings.Contains(tc.Test, "read") {
					fallocateCmd := fmt.Sprintf("fallocate -l %dM %s", tc.Size, outfile)
					if out, err := container.Exec(ctx, dockerutil.ExecOpts{},
						strings.Split(fallocateCmd, " ")...); err != nil {
						b.Fatalf("failed to create readable file on mount: %v, %s", err, out)
					}
				}

				// Drop caches just before running.
				if err := harness.DropCaches(machine); err != nil {
					b.Skipf("failed to drop caches with %v. You probably need root.", err)
				}

				cmd := tc.MakeCmd(outfile)
				if err := harness.DropCaches(machine); err != nil {
					b.Fatalf("failed to drop caches: %v", err)
				}

				// Run fio.
				b.StartTimer()
				data, err := container.Exec(ctx, dockerutil.ExecOpts{}, cmd...)
				if err != nil {
					b.Fatalf("failed to run cmd %v: %v", cmd, err)
				}
				b.StopTimer()
				tc.Report(b, data)
			})
		}
	}
}

// TestMain is the main method for package fs.
func TestMain(m *testing.M) {
	harness.Init()
	os.Exit(m.Run())
}
<|endoftext|>


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

package sql_test

import (
	"database/sql"
	"fmt"
	"net"
	"net/url"
	"os"
	"reflect"
	"testing"

	"github.com/lib/pq"

	"github.com/cockroachdb/cockroach/security"
	"github.com/cockroachdb/cockroach/security/securitytest"
	"github.com/cockroachdb/cockroach/server"
	"github.com/cockroachdb/cockroach/sql/pgwire"
	"github.com/cockroachdb/cockroach/testutils"
	"github.com/cockroachdb/cockroach/testutils/sqlutils"
	"github.com/cockroachdb/cockroach/util"
	"github.com/cockroachdb/cockroach/util/leaktest"
)

func trivialQuery(pgUrl url.URL) error {
	db, err := sql.Open("postgres", pgUrl.String())
	if err != nil {
		return err
	}
	defer db.Close()
	{
		_, err := db.Exec("SELECT 1")
		return err
	}
}

func tempRestrictedAsset(t util.Tester, path, tempdir, prefix string) (string, func()) {
	contents, err := securitytest.Asset(path)
	if err != nil {
		t.Fatal(err)
	}

	return util.CreateTempRestrictedFile(t, contents, tempdir, prefix)
}

func TestPGWire(t *testing.T) {
	defer leaktest.AfterTest(t)

	certUser := server.TestUser
	certPath := security.ClientCertPath(security.EmbeddedCertsDir, certUser)
	keyPath := security.ClientKeyPath(security.EmbeddedCertsDir, certUser)

	// Copy these assets to disk from embedded strings, so this test can
	// run from a standalone binary.
	tempCertPath, tempCertCleanup := securitytest.TempRestrictedCopy(t, certPath, os.TempDir(), "TestPGWire_cert")
	defer tempCertCleanup()
	tempKeyPath, tempKeyCleanup := securitytest.TempRestrictedCopy(t, keyPath, os.TempDir(), "TestPGWire_key")
	defer tempKeyCleanup()

	for _, insecure := range [...]bool{true, false} {
		ctx := server.NewTestContext()
		ctx.Insecure = insecure
		s := setupTestServerWithContext(t, ctx)

		host, port, err := net.SplitHostPort(s.PGAddr())
		if err != nil {
			t.Fatal(err)
		}

		basePgUrl := url.URL{
			Scheme: "postgres",
			Host:   net.JoinHostPort(host, port),
		}
		if err := trivialQuery(basePgUrl); err != nil {
			if insecure {
				if err != pq.ErrSSLNotSupported {
					t.Error(err)
				}
			} else {
				if !testutils.IsError(err, "no client certificates in request") {
					t.Error(err)
				}
			}
		}

		{
			disablePgUrl := basePgUrl
			disablePgUrl.RawQuery = "sslmode=disable"
			err := trivialQuery(disablePgUrl)
			if insecure {
				if err != nil {
					t.Error(err)
				}
			} else {
				if !testutils.IsError(err, pgwire.ErrSSLRequired) {
					t.Error(err)
				}
			}
		}

		{
			requirePgUrlNoCert := basePgUrl
			requirePgUrlNoCert.RawQuery = "sslmode=require"
			err := trivialQuery(requirePgUrlNoCert)
			if insecure {
				if err != pq.ErrSSLNotSupported {
					t.Error(err)
				}
			} else {
				if !testutils.IsError(err, "no client certificates in request") {
					t.Error(err)
				}
			}
		}

		{
			for _, optUser := range []string{certUser, security.RootUser} {
				requirePgUrlWithCert := basePgUrl
				requirePgUrlWithCert.User = url.User(optUser)
				requirePgUrlWithCert.RawQuery = fmt.Sprintf("sslmode=require&sslcert=%s&sslkey=%s",
					url.QueryEscape(tempCertPath),
					url.QueryEscape(tempKeyPath),
				)
				err := trivialQuery(requirePgUrlWithCert)
				if insecure {
					if err != pq.ErrSSLNotSupported {
						t.Error(err)
					}
				} else {
					if optUser == certUser {
						if err != nil {
							t.Error(err)
						}
					} else {
						if !testutils.IsError(err, `requested user is \w+, but certificate is for \w+`) {
							t.Error(err)
						}
					}
				}
			}
		}

		cleanupTestServer(s)
	}
}

type preparedTest struct {
	params []interface{}
	error  string
	result []interface{}
}

func (p preparedTest) Params(v ...interface{}) preparedTest {
	p.params = v
	return p
}

func (p preparedTest) Error(err string) preparedTest {
	p.error = err
	return p
}

func (p preparedTest) Results(v ...interface{}) preparedTest {
	p.result = v
	return p
}

func TestPGPrepared(t *testing.T) {
	defer leaktest.AfterTest(t)
	var base preparedTest
	queryTests := map[string][]preparedTest{
		"SELECT $1 > 0": {
			base.Params(1).Results(true),
			base.Params("1").Results(true),
			base.Params(1.1).Error(`pq: param $1: strconv.ParseInt: parsing "1.1": invalid syntax`).Results(true),
			base.Params("1.0").Error(`pq: param $1: strconv.ParseInt: parsing "1.0": invalid syntax`),
			base.Params(true).Error(`pq: param $1: strconv.ParseInt: parsing "true": invalid syntax`),
		},
		"SELECT TRUE AND $1": {
			base.Params(true).Results(true),
			base.Params(false).Results(false),
			base.Params(1).Results(true),
			base.Params("").Error(`pq: param $1: strconv.ParseBool: parsing "": invalid syntax`),
			// Make sure we can run another after a failure.
			base.Params(true).Results(true),
		},
		"SELECT $1::bool": {
			base.Params(true).Results(true),
			base.Params("true").Results(true),
			base.Params("false").Results(false),
			base.Params("1").Results(true),
			base.Params(2).Error(`pq: strconv.ParseBool: parsing "2": invalid syntax`),
			base.Params(3.1).Error(`pq: strconv.ParseBool: parsing "3.1": invalid syntax`),
			base.Params("").Error(`pq: strconv.ParseBool: parsing "": invalid syntax`),
		},
		"SELECT $1::int > $2::float": {
			base.Params("2", 1).Results(true),
			base.Params(1, "2").Results(false),
			base.Params("2", "1.0").Results(true),
			base.Params("2.0", "1").Error(`pq: strconv.ParseInt: parsing "2.0": invalid syntax`),
			base.Params(2.1, 1).Error(`pq: strconv.ParseInt: parsing "2.1": invalid syntax`),
		},
		"SELECT GREATEST($1, 0, $2), $2": {
			base.Params(1, -1).Results(1, -1),
			base.Params(-1, 10).Results(10, 10),
			base.Params("-2", "-1").Results(0, -1),
			base.Params(1, 2.1).Error(`pq: param $2: strconv.ParseInt: parsing "2.1": invalid syntax`),
		},
		"SELECT $1::int, $1::float": {
			base.Params("1").Results(1, 1.0),
		},
		"SELECT 3 + $1, $1 + $2": {
			base.Params("1", "2").Results(4, 3),
			base.Params(3, "4").Results(6, 7),
			base.Params(0, "a").Error(`pq: param $2: strconv.ParseInt: parsing "a": invalid syntax`),
		},
		// TODO(mjibson): test date/time types
	}

	s := server.StartTestServer(t)
	defer s.Stop()

	pgUrl, cleanupFn := sqlutils.PGUrl(t, s, security.RootUser, os.TempDir(), "TestPGPrepared")
	defer cleanupFn()

	db, err := sql.Open("postgres", pgUrl.String())
	if err != nil {
		t.Fatal(err)
	}
	defer db.Close()

	for query, tests := range queryTests {
		stmt, err := db.Prepare(query)
		if err != nil {
			t.Errorf("prepare error: %s: %s", query, err)
			continue
		}

		for _, test := range tests {
			rows, err := stmt.Query(test.params...)
			if err != nil {
				if test.error == "" {
					t.Errorf("%s: %#v: unexpected error: %s", query, test.params, err)
				}
				if test.error != err.Error() {
					t.Errorf("%s: %#v: expected error: %s, got %s", query, test.params, test.error, err)
				}
				continue
			}
			if test.error != "" && err == nil {
				t.Errorf("expected error: %s: %#v", query, test.params)
			}
			dst := make([]interface{}, len(test.result))
			for i, d := range test.result {
				dst[i] = reflect.New(reflect.TypeOf(d)).Interface()
			}
			if !rows.Next() {
				t.Errorf("expected row: %s: %#v", query, test.params)
			}
			if err := rows.Scan(dst...); err != nil {
				t.Error(err)
			}
			rows.Close()
			for i, d := range dst {
				v := reflect.Indirect(reflect.ValueOf(d)).Interface()
				dst[i] = v
			}
			if !reflect.DeepEqual(dst, test.result) {
				t.Errorf("%s: %#v: expected %v, got %v", query, test.params, test.result, dst)
			}
		}
		if err := stmt.Close(); err != nil {
			t.Error(err)
		}
	}

	testFailures := map[string]string{
		"SELECT $1 = $1":           "pq: unsupported comparison operator: <valarg> = <valarg>",
		"SELECT $1 > 0 AND NOT $1": "pq: incompatible NOT argument type: int",
		"SELECT $1":                "pq: unsupported result type: valarg",
		"SELECT $1 + $1":           "pq: unsupported binary operator: <valarg> + <valarg>",
		"SELECT now() + $1":        "pq: unsupported binary operator: <timestamp> + <valarg>",
	}

	for query, reason := range testFailures {
		stmt, err := db.Prepare(query)
		if err == nil {
			t.Errorf("expected error: %s", query)
			stmt.Close()
			continue
		}
		if err.Error() != reason {
			t.Errorf("unexpected error: %s: %s", query, err)
		}
	}
}
<commit_msg>sql/pgwire: test `(*sql.DB).Query` as well<commit_after>// Copyright 2015 The Cockroach Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.
//
// Author: Tamir Duberstein (tamird@gmail.com)

package sql_test

import (
	"database/sql"
	"fmt"
	"net"
	"net/url"
	"os"
	"reflect"
	"testing"

	"github.com/lib/pq"

	"github.com/cockroachdb/cockroach/security"
	"github.com/cockroachdb/cockroach/security/securitytest"
	"github.com/cockroachdb/cockroach/server"
	"github.com/cockroachdb/cockroach/sql/pgwire"
	"github.com/cockroachdb/cockroach/testutils"
	"github.com/cockroachdb/cockroach/testutils/sqlutils"
	"github.com/cockroachdb/cockroach/util"
	"github.com/cockroachdb/cockroach/util/leaktest"
)

func trivialQuery(pgUrl url.URL) error {
	db, err := sql.Open("postgres", pgUrl.String())
	if err != nil {
		return err
	}
	defer db.Close()
	{
		_, err := db.Exec("SELECT 1")
		return err
	}
}

func tempRestrictedAsset(t util.Tester, path, tempdir, prefix string) (string, func()) {
	contents, err := securitytest.Asset(path)
	if err != nil {
		t.Fatal(err)
	}

	return util.CreateTempRestrictedFile(t, contents, tempdir, prefix)
}

func TestPGWire(t *testing.T) {
	defer leaktest.AfterTest(t)

	certUser := server.TestUser
	certPath := security.ClientCertPath(security.EmbeddedCertsDir, certUser)
	keyPath := security.ClientKeyPath(security.EmbeddedCertsDir, certUser)

	// Copy these assets to disk from embedded strings, so this test can
	// run from a standalone binary.
	tempCertPath, tempCertCleanup := securitytest.TempRestrictedCopy(t, certPath, os.TempDir(), "TestPGWire_cert")
	defer tempCertCleanup()
	tempKeyPath, tempKeyCleanup := securitytest.TempRestrictedCopy(t, keyPath, os.TempDir(), "TestPGWire_key")
	defer tempKeyCleanup()

	for _, insecure := range [...]bool{true, false} {
		ctx := server.NewTestContext()
		ctx.Insecure = insecure
		s := setupTestServerWithContext(t, ctx)

		host, port, err := net.SplitHostPort(s.PGAddr())
		if err != nil {
			t.Fatal(err)
		}

		basePgUrl := url.URL{
			Scheme: "postgres",
			Host:   net.JoinHostPort(host, port),
		}
		if err := trivialQuery(basePgUrl); err != nil {
			if insecure {
				if err != pq.ErrSSLNotSupported {
					t.Error(err)
				}
			} else {
				if !testutils.IsError(err, "no client certificates in request") {
					t.Error(err)
				}
			}
		}

		{
			disablePgUrl := basePgUrl
			disablePgUrl.RawQuery = "sslmode=disable"
			err := trivialQuery(disablePgUrl)
			if insecure {
				if err != nil {
					t.Error(err)
				}
			} else {
				if !testutils.IsError(err, pgwire.ErrSSLRequired) {
					t.Error(err)
				}
			}
		}

		{
			requirePgUrlNoCert := basePgUrl
			requirePgUrlNoCert.RawQuery = "sslmode=require"
			err := trivialQuery(requirePgUrlNoCert)
			if insecure {
				if err != pq.ErrSSLNotSupported {
					t.Error(err)
				}
			} else {
				if !testutils.IsError(err, "no client certificates in request") {
					t.Error(err)
				}
			}
		}

		{
			for _, optUser := range []string{certUser, security.RootUser} {
				requirePgUrlWithCert := basePgUrl
				requirePgUrlWithCert.User = url.User(optUser)
				requirePgUrlWithCert.RawQuery = fmt.Sprintf("sslmode=require&sslcert=%s&sslkey=%s",
					url.QueryEscape(tempCertPath),
					url.QueryEscape(tempKeyPath),
				)
				err := trivialQuery(requirePgUrlWithCert)
				if insecure {
					if err != pq.ErrSSLNotSupported {
						t.Error(err)
					}
				} else {
					if optUser == certUser {
						if err != nil {
							t.Error(err)
						}
					} else {
						if !testutils.IsError(err, `requested user is \w+, but certificate is for \w+`) {
							t.Error(err)
						}
					}
				}
			}
		}

		cleanupTestServer(s)
	}
}

type preparedTest struct {
	params []interface{}
	error  string
	result []interface{}
}

func (p preparedTest) Params(v ...interface{}) preparedTest {
	p.params = v
	return p
}

func (p preparedTest) Error(err string) preparedTest {
	p.error = err
	return p
}

func (p preparedTest) Results(v ...interface{}) preparedTest {
	p.result = v
	return p
}

func TestPGPrepared(t *testing.T) {
	defer leaktest.AfterTest(t)
	var base preparedTest
	queryTests := map[string][]preparedTest{
		"SELECT $1 > 0": {
			base.Params(1).Results(true),
			base.Params("1").Results(true),
			base.Params(1.1).Error(`pq: param $1: strconv.ParseInt: parsing "1.1": invalid syntax`).Results(true),
			base.Params("1.0").Error(`pq: param $1: strconv.ParseInt: parsing "1.0": invalid syntax`),
			base.Params(true).Error(`pq: param $1: strconv.ParseInt: parsing "true": invalid syntax`),
		},
		"SELECT TRUE AND $1": {
			base.Params(true).Results(true),
			base.Params(false).Results(false),
			base.Params(1).Results(true),
			base.Params("").Error(`pq: param $1: strconv.ParseBool: parsing "": invalid syntax`),
			// Make sure we can run another after a failure.
			base.Params(true).Results(true),
		},
		"SELECT $1::bool": {
			base.Params(true).Results(true),
			base.Params("true").Results(true),
			base.Params("false").Results(false),
			base.Params("1").Results(true),
			base.Params(2).Error(`pq: strconv.ParseBool: parsing "2": invalid syntax`),
			base.Params(3.1).Error(`pq: strconv.ParseBool: parsing "3.1": invalid syntax`),
			base.Params("").Error(`pq: strconv.ParseBool: parsing "": invalid syntax`),
		},
		"SELECT $1::int > $2::float": {
			base.Params("2", 1).Results(true),
			base.Params(1, "2").Results(false),
			base.Params("2", "1.0").Results(true),
			base.Params("2.0", "1").Error(`pq: strconv.ParseInt: parsing "2.0": invalid syntax`),
			base.Params(2.1, 1).Error(`pq: strconv.ParseInt: parsing "2.1": invalid syntax`),
		},
		"SELECT GREATEST($1, 0, $2), $2": {
			base.Params(1, -1).Results(1, -1),
			base.Params(-1, 10).Results(10, 10),
			base.Params("-2", "-1").Results(0, -1),
			base.Params(1, 2.1).Error(`pq: param $2: strconv.ParseInt: parsing "2.1": invalid syntax`),
		},
		"SELECT $1::int, $1::float": {
			base.Params("1").Results(1, 1.0),
		},
		"SELECT 3 + $1, $1 + $2": {
			base.Params("1", "2").Results(4, 3),
			base.Params(3, "4").Results(6, 7),
			base.Params(0, "a").Error(`pq: param $2: strconv.ParseInt: parsing "a": invalid syntax`),
		},
		// TODO(mjibson): test date/time types
	}

	s := server.StartTestServer(t)
	defer s.Stop()

	pgUrl, cleanupFn := sqlutils.PGUrl(t, s, security.RootUser, os.TempDir(), "TestPGPrepared")
	defer cleanupFn()

	db, err := sql.Open("postgres", pgUrl.String())
	if err != nil {
		t.Fatal(err)
	}
	defer db.Close()

	for query, tests := range queryTests {
		stmt, err := db.Prepare(query)
		if err != nil {
			t.Errorf("prepare error: %s: %s", query, err)
			continue
		}

		type result struct {
			rows *sql.Rows
			err  error
		}

		for _, test := range tests {
			var results []result
			{
				rows, err := db.Query(query, test.params...)
				results = append(results, result{rows: rows, err: err})
			}
			{
				rows, err := stmt.Query(test.params...)
				results = append(results, result{rows: rows, err: err})
			}
			for _, res := range results {
				rows, err := res.rows, res.err
				if err != nil {
					if test.error == "" {
						t.Errorf("%s: %#v: unexpected error: %s", query, test.params, err)
					}
					if test.error != err.Error() {
						t.Errorf("%s: %#v: expected error: %s, got %s", query, test.params, test.error, err)
					}
					continue
				}
				if test.error != "" && err == nil {
					t.Errorf("expected error: %s: %#v", query, test.params)
				}
				dst := make([]interface{}, len(test.result))
				for i, d := range test.result {
					dst[i] = reflect.New(reflect.TypeOf(d)).Interface()
				}
				if !rows.Next() {
					t.Errorf("expected row: %s: %#v", query, test.params)
				}
				if err := rows.Scan(dst...); err != nil {
					t.Error(err)
				}
				rows.Close()
				for i, d := range dst {
					v := reflect.Indirect(reflect.ValueOf(d)).Interface()
					dst[i] = v
				}
				if !reflect.DeepEqual(dst, test.result) {
					t.Errorf("%s: %#v: expected %v, got %v", query, test.params, test.result, dst)
				}
			}
		}
		if err := stmt.Close(); err != nil {
			t.Error(err)
		}
	}

	testFailures := map[string]string{
		"SELECT $1 = $1":           "pq: unsupported comparison operator: <valarg> = <valarg>",
		"SELECT $1 > 0 AND NOT $1": "pq: incompatible NOT argument type: int",
		"SELECT $1":                "pq: unsupported result type: valarg",
		"SELECT $1 + $1":           "pq: unsupported binary operator: <valarg> + <valarg>",
		"SELECT now() + $1":        "pq: unsupported binary operator: <timestamp> + <valarg>",
	}

	for query, reason := range testFailures {
		stmt, err := db.Prepare(query)
		if err == nil {
			t.Errorf("expected error: %s", query)
			stmt.Close()
			continue
		}
		if err.Error() != reason {
			t.Errorf("unexpected error: %s: %s", query, err)
		}
	}
}
<|endoftext|>


<commit_before>// Code generated by protoc-gen-go.
// source: upside_down.proto
// DO NOT EDIT!

/*
Package upside_down is a generated protocol buffer package.

It is generated from these files:
	upside_down.proto

It has these top-level messages:
	BackIndexTermEntry
	BackIndexStoreEntry
	BackIndexRowValue
*/
package upside_down

import proto "github.com/golang/protobuf/proto"
import math "math"

// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = math.Inf

type BackIndexTermEntry struct {
	Term             *string `protobuf:"bytes,1,req,name=term" json:"term,omitempty"`
	Field            *uint32 `protobuf:"varint,2,req,name=field" json:"field,omitempty"`
	XXX_unrecognized []byte  `json:"-"`
}

func (m *BackIndexTermEntry) Reset()         { *m = BackIndexTermEntry{} }
func (m *BackIndexTermEntry) String() string { return proto.CompactTextString(m) }
func (*BackIndexTermEntry) ProtoMessage()    {}

func (m *BackIndexTermEntry) GetTerm() string {
	if m != nil && m.Term != nil {
		return *m.Term
	}
	return ""
}

func (m *BackIndexTermEntry) GetField() uint32 {
	if m != nil && m.Field != nil {
		return *m.Field
	}
	return 0
}

type BackIndexStoreEntry struct {
	Field            *uint32  `protobuf:"varint,1,req,name=field" json:"field,omitempty"`
	ArrayPositions   []uint64 `protobuf:"varint,2,rep,name=arrayPositions" json:"arrayPositions,omitempty"`
	XXX_unrecognized []byte   `json:"-"`
}

func (m *BackIndexStoreEntry) Reset()         { *m = BackIndexStoreEntry{} }
func (m *BackIndexStoreEntry) String() string { return proto.CompactTextString(m) }
func (*BackIndexStoreEntry) ProtoMessage()    {}

func (m *BackIndexStoreEntry) GetField() uint32 {
	if m != nil && m.Field != nil {
		return *m.Field
	}
	return 0
}

func (m *BackIndexStoreEntry) GetArrayPositions() []uint64 {
	if m != nil {
		return m.ArrayPositions
	}
	return nil
}

type BackIndexRowValue struct {
	TermEntries      []*BackIndexTermEntry  `protobuf:"bytes,1,rep,name=termEntries" json:"termEntries,omitempty"`
	StoredEntries    []*BackIndexStoreEntry `protobuf:"bytes,2,rep,name=storedEntries" json:"storedEntries,omitempty"`
	XXX_unrecognized []byte                 `json:"-"`
}

func (m *BackIndexRowValue) Reset()         { *m = BackIndexRowValue{} }
func (m *BackIndexRowValue) String() string { return proto.CompactTextString(m) }
func (*BackIndexRowValue) ProtoMessage()    {}

func (m *BackIndexRowValue) GetTermEntries() []*BackIndexTermEntry {
	if m != nil {
		return m.TermEntries
	}
	return nil
}

func (m *BackIndexRowValue) GetStoredEntries() []*BackIndexStoreEntry {
	if m != nil {
		return m.StoredEntries
	}
	return nil
}

func init() {
}
<commit_msg>faster protobufs with gogo<commit_after>// Code generated by protoc-gen-gogo.
// source: upside_down.proto
// DO NOT EDIT!

/*
Package upside_down is a generated protocol buffer package.

It is generated from these files:
	upside_down.proto

It has these top-level messages:
	BackIndexTermEntry
	BackIndexStoreEntry
	BackIndexRowValue
*/
package upside_down

import proto "github.com/golang/protobuf/proto"
import math "math"

import io "io"
import fmt "fmt"
import github_com_golang_protobuf_proto "github.com/golang/protobuf/proto"

// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = math.Inf

type BackIndexTermEntry struct {
	Term             *string `protobuf:"bytes,1,req,name=term" json:"term,omitempty"`
	Field            *uint32 `protobuf:"varint,2,req,name=field" json:"field,omitempty"`
	XXX_unrecognized []byte  `json:"-"`
}

func (m *BackIndexTermEntry) Reset()         { *m = BackIndexTermEntry{} }
func (m *BackIndexTermEntry) String() string { return proto.CompactTextString(m) }
func (*BackIndexTermEntry) ProtoMessage()    {}

func (m *BackIndexTermEntry) GetTerm() string {
	if m != nil && m.Term != nil {
		return *m.Term
	}
	return ""
}

func (m *BackIndexTermEntry) GetField() uint32 {
	if m != nil && m.Field != nil {
		return *m.Field
	}
	return 0
}

type BackIndexStoreEntry struct {
	Field            *uint32  `protobuf:"varint,1,req,name=field" json:"field,omitempty"`
	ArrayPositions   []uint64 `protobuf:"varint,2,rep,name=arrayPositions" json:"arrayPositions,omitempty"`
	XXX_unrecognized []byte   `json:"-"`
}

func (m *BackIndexStoreEntry) Reset()         { *m = BackIndexStoreEntry{} }
func (m *BackIndexStoreEntry) String() string { return proto.CompactTextString(m) }
func (*BackIndexStoreEntry) ProtoMessage()    {}

func (m *BackIndexStoreEntry) GetField() uint32 {
	if m != nil && m.Field != nil {
		return *m.Field
	}
	return 0
}

func (m *BackIndexStoreEntry) GetArrayPositions() []uint64 {
	if m != nil {
		return m.ArrayPositions
	}
	return nil
}

type BackIndexRowValue struct {
	TermEntries      []*BackIndexTermEntry  `protobuf:"bytes,1,rep,name=termEntries" json:"termEntries,omitempty"`
	StoredEntries    []*BackIndexStoreEntry `protobuf:"bytes,2,rep,name=storedEntries" json:"storedEntries,omitempty"`
	XXX_unrecognized []byte                 `json:"-"`
}

func (m *BackIndexRowValue) Reset()         { *m = BackIndexRowValue{} }
func (m *BackIndexRowValue) String() string { return proto.CompactTextString(m) }
func (*BackIndexRowValue) ProtoMessage()    {}

func (m *BackIndexRowValue) GetTermEntries() []*BackIndexTermEntry {
	if m != nil {
		return m.TermEntries
	}
	return nil
}

func (m *BackIndexRowValue) GetStoredEntries() []*BackIndexStoreEntry {
	if m != nil {
		return m.StoredEntries
	}
	return nil
}

func (m *BackIndexTermEntry) Unmarshal(data []byte) error {
	var hasFields [1]uint64
	l := len(data)
	iNdEx := 0
	for iNdEx < l {
		var wire uint64
		for shift := uint(0); ; shift += 7 {
			if iNdEx >= l {
				return io.ErrUnexpectedEOF
			}
			b := data[iNdEx]
			iNdEx++
			wire |= (uint64(b) & 0x7F) << shift
			if b < 0x80 {
				break
			}
		}
		fieldNum := int32(wire >> 3)
		wireType := int(wire & 0x7)
		switch fieldNum {
		case 1:
			if wireType != 2 {
				return fmt.Errorf("proto: wrong wireType = %d for field Term", wireType)
			}
			var stringLen uint64
			for shift := uint(0); ; shift += 7 {
				if iNdEx >= l {
					return io.ErrUnexpectedEOF
				}
				b := data[iNdEx]
				iNdEx++
				stringLen |= (uint64(b) & 0x7F) << shift
				if b < 0x80 {
					break
				}
			}
			postIndex := iNdEx + int(stringLen)
			if postIndex > l {
				return io.ErrUnexpectedEOF
			}
			s := string(data[iNdEx:postIndex])
			m.Term = &s
			iNdEx = postIndex
			hasFields[0] |= uint64(0x00000001)
		case 2:
			if wireType != 0 {
				return fmt.Errorf("proto: wrong wireType = %d for field Field", wireType)
			}
			var v uint32
			for shift := uint(0); ; shift += 7 {
				if iNdEx >= l {
					return io.ErrUnexpectedEOF
				}
				b := data[iNdEx]
				iNdEx++
				v |= (uint32(b) & 0x7F) << shift
				if b < 0x80 {
					break
				}
			}
			m.Field = &v
			hasFields[0] |= uint64(0x00000002)
		default:
			var sizeOfWire int
			for {
				sizeOfWire++
				wire >>= 7
				if wire == 0 {
					break
				}
			}
			iNdEx -= sizeOfWire
			skippy, err := skipUpsideDown(data[iNdEx:])
			if err != nil {
				return err
			}
			if skippy < 0 {
				return ErrInvalidLengthUpsideDown
			}
			if (iNdEx + skippy) > l {
				return io.ErrUnexpectedEOF
			}
			m.XXX_unrecognized = append(m.XXX_unrecognized, data[iNdEx:iNdEx+skippy]...)
			iNdEx += skippy
		}
	}
	if hasFields[0]&uint64(0x00000001) == 0 {
		return new(github_com_golang_protobuf_proto.RequiredNotSetError)
	}
	if hasFields[0]&uint64(0x00000002) == 0 {
		return new(github_com_golang_protobuf_proto.RequiredNotSetError)
	}

	return nil
}
func (m *BackIndexStoreEntry) Unmarshal(data []byte) error {
	var hasFields [1]uint64
	l := len(data)
	iNdEx := 0
	for iNdEx < l {
		var wire uint64
		for shift := uint(0); ; shift += 7 {
			if iNdEx >= l {
				return io.ErrUnexpectedEOF
			}
			b := data[iNdEx]
			iNdEx++
			wire |= (uint64(b) & 0x7F) << shift
			if b < 0x80 {
				break
			}
		}
		fieldNum := int32(wire >> 3)
		wireType := int(wire & 0x7)
		switch fieldNum {
		case 1:
			if wireType != 0 {
				return fmt.Errorf("proto: wrong wireType = %d for field Field", wireType)
			}
			var v uint32
			for shift := uint(0); ; shift += 7 {
				if iNdEx >= l {
					return io.ErrUnexpectedEOF
				}
				b := data[iNdEx]
				iNdEx++
				v |= (uint32(b) & 0x7F) << shift
				if b < 0x80 {
					break
				}
			}
			m.Field = &v
			hasFields[0] |= uint64(0x00000001)
		case 2:
			if wireType != 0 {
				return fmt.Errorf("proto: wrong wireType = %d for field ArrayPositions", wireType)
			}
			var v uint64
			for shift := uint(0); ; shift += 7 {
				if iNdEx >= l {
					return io.ErrUnexpectedEOF
				}
				b := data[iNdEx]
				iNdEx++
				v |= (uint64(b) & 0x7F) << shift
				if b < 0x80 {
					break
				}
			}
			m.ArrayPositions = append(m.ArrayPositions, v)
		default:
			var sizeOfWire int
			for {
				sizeOfWire++
				wire >>= 7
				if wire == 0 {
					break
				}
			}
			iNdEx -= sizeOfWire
			skippy, err := skipUpsideDown(data[iNdEx:])
			if err != nil {
				return err
			}
			if skippy < 0 {
				return ErrInvalidLengthUpsideDown
			}
			if (iNdEx + skippy) > l {
				return io.ErrUnexpectedEOF
			}
			m.XXX_unrecognized = append(m.XXX_unrecognized, data[iNdEx:iNdEx+skippy]...)
			iNdEx += skippy
		}
	}
	if hasFields[0]&uint64(0x00000001) == 0 {
		return new(github_com_golang_protobuf_proto.RequiredNotSetError)
	}

	return nil
}
func (m *BackIndexRowValue) Unmarshal(data []byte) error {
	l := len(data)
	iNdEx := 0
	for iNdEx < l {
		var wire uint64
		for shift := uint(0); ; shift += 7 {
			if iNdEx >= l {
				return io.ErrUnexpectedEOF
			}
			b := data[iNdEx]
			iNdEx++
			wire |= (uint64(b) & 0x7F) << shift
			if b < 0x80 {
				break
			}
		}
		fieldNum := int32(wire >> 3)
		wireType := int(wire & 0x7)
		switch fieldNum {
		case 1:
			if wireType != 2 {
				return fmt.Errorf("proto: wrong wireType = %d for field TermEntries", wireType)
			}
			var msglen int
			for shift := uint(0); ; shift += 7 {
				if iNdEx >= l {
					return io.ErrUnexpectedEOF
				}
				b := data[iNdEx]
				iNdEx++
				msglen |= (int(b) & 0x7F) << shift
				if b < 0x80 {
					break
				}
			}
			postIndex := iNdEx + msglen
			if msglen < 0 {
				return ErrInvalidLengthUpsideDown
			}
			if postIndex > l {
				return io.ErrUnexpectedEOF
			}
			m.TermEntries = append(m.TermEntries, &BackIndexTermEntry{})
			if err := m.TermEntries[len(m.TermEntries)-1].Unmarshal(data[iNdEx:postIndex]); err != nil {
				return err
			}
			iNdEx = postIndex
		case 2:
			if wireType != 2 {
				return fmt.Errorf("proto: wrong wireType = %d for field StoredEntries", wireType)
			}
			var msglen int
			for shift := uint(0); ; shift += 7 {
				if iNdEx >= l {
					return io.ErrUnexpectedEOF
				}
				b := data[iNdEx]
				iNdEx++
				msglen |= (int(b) & 0x7F) << shift
				if b < 0x80 {
					break
				}
			}
			postIndex := iNdEx + msglen
			if msglen < 0 {
				return ErrInvalidLengthUpsideDown
			}
			if postIndex > l {
				return io.ErrUnexpectedEOF
			}
			m.StoredEntries = append(m.StoredEntries, &BackIndexStoreEntry{})
			if err := m.StoredEntries[len(m.StoredEntries)-1].Unmarshal(data[iNdEx:postIndex]); err != nil {
				return err
			}
			iNdEx = postIndex
		default:
			var sizeOfWire int
			for {
				sizeOfWire++
				wire >>= 7
				if wire == 0 {
					break
				}
			}
			iNdEx -= sizeOfWire
			skippy, err := skipUpsideDown(data[iNdEx:])
			if err != nil {
				return err
			}
			if skippy < 0 {
				return ErrInvalidLengthUpsideDown
			}
			if (iNdEx + skippy) > l {
				return io.ErrUnexpectedEOF
			}
			m.XXX_unrecognized = append(m.XXX_unrecognized, data[iNdEx:iNdEx+skippy]...)
			iNdEx += skippy
		}
	}

	return nil
}
func skipUpsideDown(data []byte) (n int, err error) {
	l := len(data)
	iNdEx := 0
	for iNdEx < l {
		var wire uint64
		for shift := uint(0); ; shift += 7 {
			if iNdEx >= l {
				return 0, io.ErrUnexpectedEOF
			}
			b := data[iNdEx]
			iNdEx++
			wire |= (uint64(b) & 0x7F) << shift
			if b < 0x80 {
				break
			}
		}
		wireType := int(wire & 0x7)
		switch wireType {
		case 0:
			for {
				if iNdEx >= l {
					return 0, io.ErrUnexpectedEOF
				}
				iNdEx++
				if data[iNdEx-1] < 0x80 {
					break
				}
			}
			return iNdEx, nil
		case 1:
			iNdEx += 8
			return iNdEx, nil
		case 2:
			var length int
			for shift := uint(0); ; shift += 7 {
				if iNdEx >= l {
					return 0, io.ErrUnexpectedEOF
				}
				b := data[iNdEx]
				iNdEx++
				length |= (int(b) & 0x7F) << shift
				if b < 0x80 {
					break
				}
			}
			iNdEx += length
			if length < 0 {
				return 0, ErrInvalidLengthUpsideDown
			}
			return iNdEx, nil
		case 3:
			for {
				var innerWire uint64
				var start int = iNdEx
				for shift := uint(0); ; shift += 7 {
					if iNdEx >= l {
						return 0, io.ErrUnexpectedEOF
					}
					b := data[iNdEx]
					iNdEx++
					innerWire |= (uint64(b) & 0x7F) << shift
					if b < 0x80 {
						break
					}
				}
				innerWireType := int(innerWire & 0x7)
				if innerWireType == 4 {
					break
				}
				next, err := skipUpsideDown(data[start:])
				if err != nil {
					return 0, err
				}
				iNdEx = start + next
			}
			return iNdEx, nil
		case 4:
			return iNdEx, nil
		case 5:
			iNdEx += 4
			return iNdEx, nil
		default:
			return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
		}
	}
	panic("unreachable")
}

var (
	ErrInvalidLengthUpsideDown = fmt.Errorf("proto: negative length found during unmarshaling")
)

func (m *BackIndexTermEntry) Size() (n int) {
	var l int
	_ = l
	if m.Term != nil {
		l = len(*m.Term)
		n += 1 + l + sovUpsideDown(uint64(l))
	}
	if m.Field != nil {
		n += 1 + sovUpsideDown(uint64(*m.Field))
	}
	if m.XXX_unrecognized != nil {
		n += len(m.XXX_unrecognized)
	}
	return n
}

func (m *BackIndexStoreEntry) Size() (n int) {
	var l int
	_ = l
	if m.Field != nil {
		n += 1 + sovUpsideDown(uint64(*m.Field))
	}
	if len(m.ArrayPositions) > 0 {
		for _, e := range m.ArrayPositions {
			n += 1 + sovUpsideDown(uint64(e))
		}
	}
	if m.XXX_unrecognized != nil {
		n += len(m.XXX_unrecognized)
	}
	return n
}

func (m *BackIndexRowValue) Size() (n int) {
	var l int
	_ = l
	if len(m.TermEntries) > 0 {
		for _, e := range m.TermEntries {
			l = e.Size()
			n += 1 + l + sovUpsideDown(uint64(l))
		}
	}
	if len(m.StoredEntries) > 0 {
		for _, e := range m.StoredEntries {
			l = e.Size()
			n += 1 + l + sovUpsideDown(uint64(l))
		}
	}
	if m.XXX_unrecognized != nil {
		n += len(m.XXX_unrecognized)
	}
	return n
}

func sovUpsideDown(x uint64) (n int) {
	for {
		n++
		x >>= 7
		if x == 0 {
			break
		}
	}
	return n
}
func sozUpsideDown(x uint64) (n int) {
	return sovUpsideDown(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *BackIndexTermEntry) Marshal() (data []byte, err error) {
	size := m.Size()
	data = make([]byte, size)
	n, err := m.MarshalTo(data)
	if err != nil {
		return nil, err
	}
	return data[:n], nil
}

func (m *BackIndexTermEntry) MarshalTo(data []byte) (n int, err error) {
	var i int
	_ = i
	var l int
	_ = l
	if m.Term == nil {
		return 0, new(github_com_golang_protobuf_proto.RequiredNotSetError)
	} else {
		data[i] = 0xa
		i++
		i = encodeVarintUpsideDown(data, i, uint64(len(*m.Term)))
		i += copy(data[i:], *m.Term)
	}
	if m.Field == nil {
		return 0, new(github_com_golang_protobuf_proto.RequiredNotSetError)
	} else {
		data[i] = 0x10
		i++
		i = encodeVarintUpsideDown(data, i, uint64(*m.Field))
	}
	if m.XXX_unrecognized != nil {
		i += copy(data[i:], m.XXX_unrecognized)
	}
	return i, nil
}

func (m *BackIndexStoreEntry) Marshal() (data []byte, err error) {
	size := m.Size()
	data = make([]byte, size)
	n, err := m.MarshalTo(data)
	if err != nil {
		return nil, err
	}
	return data[:n], nil
}

func (m *BackIndexStoreEntry) MarshalTo(data []byte) (n int, err error) {
	var i int
	_ = i
	var l int
	_ = l
	if m.Field == nil {
		return 0, new(github_com_golang_protobuf_proto.RequiredNotSetError)
	} else {
		data[i] = 0x8
		i++
		i = encodeVarintUpsideDown(data, i, uint64(*m.Field))
	}
	if len(m.ArrayPositions) > 0 {
		for _, num := range m.ArrayPositions {
			data[i] = 0x10
			i++
			i = encodeVarintUpsideDown(data, i, uint64(num))
		}
	}
	if m.XXX_unrecognized != nil {
		i += copy(data[i:], m.XXX_unrecognized)
	}
	return i, nil
}

func (m *BackIndexRowValue) Marshal() (data []byte, err error) {
	size := m.Size()
	data = make([]byte, size)
	n, err := m.MarshalTo(data)
	if err != nil {
		return nil, err
	}
	return data[:n], nil
}

func (m *BackIndexRowValue) MarshalTo(data []byte) (n int, err error) {
	var i int
	_ = i
	var l int
	_ = l
	if len(m.TermEntries) > 0 {
		for _, msg := range m.TermEntries {
			data[i] = 0xa
			i++
			i = encodeVarintUpsideDown(data, i, uint64(msg.Size()))
			n, err := msg.MarshalTo(data[i:])
			if err != nil {
				return 0, err
			}
			i += n
		}
	}
	if len(m.StoredEntries) > 0 {
		for _, msg := range m.StoredEntries {
			data[i] = 0x12
			i++
			i = encodeVarintUpsideDown(data, i, uint64(msg.Size()))
			n, err := msg.MarshalTo(data[i:])
			if err != nil {
				return 0, err
			}
			i += n
		}
	}
	if m.XXX_unrecognized != nil {
		i += copy(data[i:], m.XXX_unrecognized)
	}
	return i, nil
}

func encodeFixed64UpsideDown(data []byte, offset int, v uint64) int {
	data[offset] = uint8(v)
	data[offset+1] = uint8(v >> 8)
	data[offset+2] = uint8(v >> 16)
	data[offset+3] = uint8(v >> 24)
	data[offset+4] = uint8(v >> 32)
	data[offset+5] = uint8(v >> 40)
	data[offset+6] = uint8(v >> 48)
	data[offset+7] = uint8(v >> 56)
	return offset + 8
}
func encodeFixed32UpsideDown(data []byte, offset int, v uint32) int {
	data[offset] = uint8(v)
	data[offset+1] = uint8(v >> 8)
	data[offset+2] = uint8(v >> 16)
	data[offset+3] = uint8(v >> 24)
	return offset + 4
}
func encodeVarintUpsideDown(data []byte, offset int, v uint64) int {
	for v >= 1<<7 {
		data[offset] = uint8(v&0x7f | 0x80)
		v >>= 7
		offset++
	}
	data[offset] = uint8(v)
	return offset + 1
}
<|endoftext|>


<commit_before>package requester

import (
	"errors"
	"math/rand"
	"strconv"
	"time"

	"github.com/nats-io/go-nats-streaming"
	"github.com/tylertreat/bench"
)

// NATSStreamingRequesterFactory implements RequesterFactory by creating a
// Requester which publishes messages to NATS Streaming and waits to receive
// them.
type NATSStreamingRequesterFactory struct {
	PayloadSize int
	Subject     string
	ClientID    string
	URL         string
}

// GetRequester returns a new Requester, called for each Benchmark connection.
func (n *NATSStreamingRequesterFactory) GetRequester(num uint64) bench.Requester {
	return &natsStreamingRequester{
		url:         n.URL,
		clientID:    n.ClientID,
		payloadSize: n.PayloadSize,
		subject:     n.Subject + "-" + strconv.FormatUint(num, 10),
	}
}

// natsStreamingRequester implements Requester by publishing a message to NATS
// Streaming and waiting to receive it.
type natsStreamingRequester struct {
	url         string
	clientID    string
	payloadSize int
	subject     string
	conn        stan.Conn
	sub         stan.Subscription
	msg         []byte
	msgChan     chan []byte
}

// Setup prepares the Requester for benchmarking.
func (n *natsStreamingRequester) Setup() error {
	conn, err := stan.Connect("test-cluster", n.clientID, stan.NatsURL(n.url))
	if err != nil {
		return err
	}
	n.msgChan = make(chan []byte)
	sub, err := conn.Subscribe(n.subject, func(msg *stan.Msg) {
		n.msgChan <- msg.Data
	})
	if err != nil {
		conn.Close()
		return err
	}
	n.conn = conn
	n.sub = sub
	n.msg = make([]byte, n.payloadSize)
	for i := 0; i < n.payloadSize; i++ {
		n.msg[i] = 'A' + uint8(rand.Intn(26))
	}
	return nil
}

// Request performs a synchronous request to the system under test.
func (n *natsStreamingRequester) Request() error {
	if _, err := n.conn.PublishAsync(n.subject, n.msg, nil); err != nil {
		return err
	}
	select {
	case <-n.msgChan:
		return nil
	case <-time.After(30 * time.Second):
		return errors.New("timeout")
	}
}

// Teardown is called upon benchmark completion.
func (n *natsStreamingRequester) Teardown() error {
	if err := n.sub.Unsubscribe(); err != nil {
		return err
	}
	n.sub = nil
	n.conn.Close()
	n.conn = nil
	return nil
}
<commit_msg>Support >1 STAN connection.<commit_after>package requester

import (
	"errors"
	"fmt"
	"math/rand"
	"strconv"
	"time"

	"github.com/nats-io/go-nats-streaming"
	"github.com/tylertreat/bench"
)

// NATSStreamingRequesterFactory implements RequesterFactory by creating a
// Requester which publishes messages to NATS Streaming and waits to receive
// them.
type NATSStreamingRequesterFactory struct {
	PayloadSize int
	Subject     string
	ClientID    string
	URL         string
}

// GetRequester returns a new Requester, called for each Benchmark connection.
func (n *NATSStreamingRequesterFactory) GetRequester(num uint64) bench.Requester {
	return &natsStreamingRequester{
		url:         n.URL,
		clientID:    n.ClientID,
		payloadSize: n.PayloadSize,
		subject:     n.Subject + "-" + strconv.FormatUint(num, 10),
	}
}

// natsStreamingRequester implements Requester by publishing a message to NATS
// Streaming and waiting to receive it.
type natsStreamingRequester struct {
	url         string
	clientID    string
	payloadSize int
	subject     string
	conn        stan.Conn
	sub         stan.Subscription
	msg         []byte
	msgChan     chan []byte
}

// Setup prepares the Requester for benchmarking.
func (n *natsStreamingRequester) Setup() error {
	conn, err := stan.Connect("test-cluster", fmt.Sprintf("%s-%d", n.clientID, time.Now().UnixNano()), stan.NatsURL(n.url))
	if err != nil {
		return err
	}
	n.msgChan = make(chan []byte)
	sub, err := conn.Subscribe(n.subject, func(msg *stan.Msg) {
		n.msgChan <- msg.Data
	})
	if err != nil {
		conn.Close()
		return err
	}
	n.conn = conn
	n.sub = sub
	n.msg = make([]byte, n.payloadSize)
	for i := 0; i < n.payloadSize; i++ {
		n.msg[i] = 'A' + uint8(rand.Intn(26))
	}
	return nil
}

// Request performs a synchronous request to the system under test.
func (n *natsStreamingRequester) Request() error {
	if _, err := n.conn.PublishAsync(n.subject, n.msg, nil); err != nil {
		return err
	}
	select {
	case <-n.msgChan:
		return nil
	case <-time.After(30 * time.Second):
		return errors.New("timeout")
	}
}

// Teardown is called upon benchmark completion.
func (n *natsStreamingRequester) Teardown() error {
	if err := n.sub.Unsubscribe(); err != nil {
		return err
	}
	n.sub = nil
	n.conn.Close()
	n.conn = nil
	return nil
}
<|endoftext|>