<commit_before>// Configr provides an abstraction above configuration sources, allowing you to
// use a single interface to get all your configuration values
package configr

import (
	"errors"
	"fmt"
	"reflect"
	"sort"
	"strings"

	"github.com/spf13/cast"
)

type Manager interface {
	RegisterKey(string, string, interface{}, ...Validator)
	RequireKey(string, string, ...Validator)

	AddSource(Source)

	GenerateBlank(Encoder) ([]byte, error)
}

// Validator is a validation function which would be coupled with a configuration
// key, anytime the config key is found in a Source it's value is validated.
type Validator func(interface{}) error

type Config interface {
	Parse() error
	Parsed() bool
	MustParse()

	Get(string) (interface{}, error)

	String(string) (string, error)
	Bool(string) (bool, error)
	Int(string) (int, error)
	Float64(string) (float64, error)
}

// Source is a source of configuration keys and values, calling unmarshal should
// return a map[string]interface{} of all key/value pairs (nesting is supported)
// with multiple types.
type Source interface {
	Unmarshal() (map[string]interface{}, error)
}

// Encoder would be used to encode registered and required values (along with
// their defaults or descriptions) into bytes.
type Encoder interface {
	Marshal(interface{}) ([]byte, error)
}

type Configr struct {
	valueValidators    map[string][]Validator
	registeredKeys     map[string]string
	requiredKeys       map[string]struct{}
	defaultValues      map[string]interface{}
	cache              map[string]interface{}
	sources            []Source
	parsed             bool
	keyDelimeter       string
	descriptionWrapper string
}

func New() *Configr {
	return &Configr{
		valueValidators:    make(map[string][]Validator),
		registeredKeys:     make(map[string]string),
		requiredKeys:       make(map[string]struct{}),
		defaultValues:      make(map[string]interface{}),
		cache:              make(map[string]interface{}),
		keyDelimeter:       ".",
		descriptionWrapper: "***",
	}
}

func GetConfigr() *Configr {
	return globalConfigr
}

func SetConfigr(c *Configr) {
	globalConfigr = c
}

var globalConfigr *Configr = New()
var ErrKeyNotFound = errors.New("configr: Key not found")
var ErrParseHasntBeenCalled = errors.New("configr: Trying to get values before calling Parse()")
var ErrNoRegisteredValues = errors.New("configr: No registered values to generate")

type ErrRequiredKeysMissing []string

func (e ErrRequiredKeysMissing) Error() string {
	sort.Strings(e)
	return fmt.Sprintf("configr: Missing required configuration values: %v", []string(e))
}

// RegisterKey registers a configuration key (name) along with a description
// of what the configuration key is for, a default value and optional validators
//
// name supports nested notation in the form of '.' delimitered keys (unless changed)
// e.g.
//     "user.age.month"
func RegisterKey(name, description string, defaultVal interface{}, validators ...Validator) {
	globalConfigr.RegisterKey(name, description, defaultVal, validators...)
}
func (c *Configr) RegisterKey(name, description string, defaultVal interface{}, validators ...Validator) {
	name = strings.ToLower(name)
	c.registeredKeys[name] = description

	if defaultVal != nil {
		c.defaultValues[name] = defaultVal
	}

	if len(validators) > 0 {
		c.valueValidators[name] = validators
	}
}

// RequireValue wraps the RegisterValue() call but upon parsing sources, if the
// configuration key (name) is not found, Parse() will return a
// ErrRequiredValuesMissing error
func RequireKey(name, description string, validators ...Validator) {
	globalConfigr.RequireKey(name, description, validators...)
}
func (c *Configr) RequireKey(name, description string, validators ...Validator) {
	name = strings.ToLower(name)
	c.requiredKeys[name] = struct{}{}
	c.RegisterKey(name, description, nil, validators...)
}

// AddSource registers Sources with the Configr instance to Unmarshal()
// when Parse() is called. Sources are parsed in a FILO order, meaning
// the first source added is considered the highest priority, and any
// keys from lower priority sources that are present in a higher will be
// overwritten
func AddSource(p Source) {
	globalConfigr.AddSource(p)
}
func (c *Configr) AddSource(p Source) {
	c.sources = append(c.sources, p)
}

// Parse calls Unmarshal on all registered sources, and caches the subsequent
// key/value's. Additional calls to Parse can be made to add additional config
// from sources.
//
// Sources are called in a FILO order, meaning the first source added is
// considered the highest priority, any keys set from lower priority sources
// found in higher priority will be overwritten.
func Parse() error {
	return globalConfigr.Parse()
}
func (c *Configr) Parse() error {
	if err := c.populateValues(); err != nil {
		return err
	}

	if err := c.checkRequiredKeys(); err != nil {
		return err
	}

	c.parsed = true
	return nil
}

func (c *Configr) checkRequiredKeys() error {
	missingKeys := []string{}

	for requiredKey := range c.requiredKeys {
		if _, err := c.get(requiredKey); err != nil {
			missingKeys = append(missingKeys, requiredKey)
		}
	}

	if len(missingKeys) > 0 {
		return ErrRequiredKeysMissing(missingKeys)
	}

	return nil
}

func (c *Configr) populateValues() error {
	for i := len(c.sources) - 1; i >= 0; i-- {
		source := c.sources[i]

		sourceValues, err := source.Unmarshal()
		if err != nil {
			return err
		}
		for key, value := range sourceValues {
			if err := c.set(key, value); err != nil {
				return err
			}
		}
	}

	return nil
}

// MustParse wraps Parse() and will panic if there are any resulting errors
func MustParse() {
	globalConfigr.MustParse()
}
func (c *Configr) MustParse() {
	if err := c.Parse(); err != nil {
		panic(err)
	}
}

func (c *Configr) set(key string, value interface{}) error {
	key = strings.ToLower(key)
	if err := c.runValidators(key, value); err != nil {
		return err
	}

	c.cache = c.mergeMap(key, value, c.cache)

	return nil
}

func (c *Configr) mergeMap(key string, value interface{}, targetMap map[string]interface{}) map[string]interface{} {
	if reflect.TypeOf(value).Kind() == reflect.Map {
		targetMap = c.traverseSubMap(key, cast.ToStringMap(value), targetMap)
	} else {
		path := strings.SplitN(key, c.keyDelimeter, 2)
		if len(path) == 2 {
			targetMap = c.traverseKeyPath(path[0], path[1], value, targetMap)
		} else {
			targetMap[key] = value
		}
	}

	return targetMap
}

func (c *Configr) traverseKeyPath(currentKey, keyRemainder string, value interface{}, targetMap map[string]interface{}) map[string]interface{} {
	if _, found := targetMap[currentKey]; !found {
		targetMap[currentKey] = make(map[string]interface{})
	}

	targetMap[currentKey] = c.mergeMap(keyRemainder, value, targetMap[currentKey].(map[string]interface{}))

	return targetMap
}

func (c *Configr) traverseSubMap(key string, value map[string]interface{}, targetMap map[string]interface{}) map[string]interface{} {
	for subKey, subValue := range value {
		if _, found := targetMap[key]; !found {
			targetMap[key] = make(map[string]interface{})
		}
		targetMap[key] = c.mergeMap(subKey, subValue, targetMap[key].(map[string]interface{}))
	}

	return targetMap
}

func (c *Configr) runValidators(key string, value interface{}) error {
	keysAndValues, err := c.findKeysAndValuesToValidate(key, value)
	if err != nil {
		return err
	}

	for validatorKey, valueToValidate := range keysAndValues {
		if validators, found := c.valueValidators[validatorKey]; found {
			for _, validate := range validators {
				if err := validate(valueToValidate); err != nil {
					return err
				}
			}
		}
	}

	return nil
}

func (c *Configr) findKeysAndValuesToValidate(key string, value interface{}) (map[string]interface{}, error) {
	keysAndValues := make(map[string]interface{})
	if reflect.TypeOf(value).Kind() == reflect.Map {
		for validatorKey := range c.valueValidators {
			if !strings.HasPrefix(validatorKey, key) {
				continue
			}
			valueToValidate := searchMap(cast.ToStringMap(value), strings.Split(validatorKey, c.keyDelimeter)[1:])
			keysAndValues[validatorKey] = valueToValidate
		}
	} else {
		keysAndValues[key] = value
	}

	return keysAndValues, nil
}

// Get can only be called after a Parse() has been done. Keys support the
// nested notation format:
//    "user.age.month"
//
// If a key is not found but has been registered with a default, the default
// will be returned
func Get(key string) (interface{}, error) {
	return globalConfigr.Get(key)
}
func (c *Configr) Get(key string) (interface{}, error) {
	if !c.Parsed() {
		return nil, ErrParseHasntBeenCalled
	}

	return c.get(key)
}

func (c *Configr) get(key string) (interface{}, error) {
	key = strings.ToLower(key)
	if value, found := c.cache[key]; found {
		return value, nil
	}

	path := strings.Split(key, c.keyDelimeter)
	parent, found := c.cache[path[0]]
	if found {
		if reflect.TypeOf(parent).Kind() == reflect.Map {
			if val := searchMap(cast.ToStringMap(parent), path[1:]); val != nil {
				return val, nil
			}
		}
	}

	if defaultValue, found := c.defaultValues[key]; found {
		return defaultValue, nil
	}

	return nil, ErrKeyNotFound
}

// From github.com/spf13/viper
func searchMap(source map[string]interface{}, path []string) interface{} {
	if len(path) == 0 {
		return source
	}

	if next, ok := source[path[0]]; ok {
		switch next.(type) {
		case map[string]interface{}:
			// Type assertion is safe here since it is only reached
			// if the type of `next` is the same as the type being asserted
			return searchMap(next.(map[string]interface{}), path[1:])
		default:
			return next
		}
	} else {
		return nil
	}
}

// String wraps Get() and will attempt to cast the resulting value to a string
// or error
func String(key string) (string, error) {
	return globalConfigr.String(key)
}
func (c *Configr) String(key string) (string, error) {
	val, err := c.Get(key)
	if err != nil {
		return "", err
	}
	return cast.ToStringE(val)
}

// Bool wraps Get() and will attempt to cast the resulting value to a bool
// or error
func Bool(key string) (bool, error) {
	return globalConfigr.Bool(key)
}
func (c *Configr) Bool(key string) (bool, error) {
	val, err := c.Get(key)
	if err != nil {
		return false, err
	}
	return cast.ToBoolE(val)
}

// Int wraps Get() and will attempt to cast the resulting value to a int
// or error
func Int(key string) (int, error) {
	return globalConfigr.Int(key)
}
func (c *Configr) Int(key string) (int, error) {
	val, err := c.Get(key)
	if err != nil {
		return 0, err
	}
	return cast.ToIntE(val)
}

// Float64 wraps Get() and will attempt to cast the resulting value to a float64
// or error
func Float64(key string) (float64, error) {
	return globalConfigr.Float64(key)
}
func (c *Configr) Float64(key string) (float64, error) {
	val, err := c.Get(key)
	if err != nil {
		return 0, err
	}
	return cast.ToFloat64E(val)
}

// Parsed lets the caller know if a Parse() call has been made or not
func Parsed() bool {
	return globalConfigr.Parsed()
}
func (c *Configr) Parsed() bool {
	return c.parsed
}

// GenerateBlank generates a 'blank' configuration using the passed Encoder,
// it will honour nested keys, use default values where possible and when not
// fall back to placing the description as the value.
func GenerateBlank(e Encoder) ([]byte, error) {
	return globalConfigr.GenerateBlank(e)
}
func (c *Configr) GenerateBlank(e Encoder) ([]byte, error) {
	if len(c.registeredKeys) == 0 {
		return []byte{}, ErrNoRegisteredValues
	}

	blankMap := make(map[string]interface{})
	for key, description := range c.registeredKeys {
		if defaultValue, found := c.defaultValues[key]; found {
			blankMap = c.mergeMap(key, defaultValue, blankMap)
		} else {
			blankMap = c.mergeMap(key, c.wrapDescription(description), blankMap)
		}
	}

	return e.Marshal(blankMap)
}

func (c *Configr) wrapDescription(description string) string {
	return strings.Join([]string{c.descriptionWrapper, description, c.descriptionWrapper}, " ")
}
<commit_msg>Add setters for key path delimeter and description wrapper<commit_after>// Configr provides an abstraction above configuration sources, allowing you to
// use a single interface to get all your configuration values
package configr

import (
	"errors"
	"fmt"
	"reflect"
	"sort"
	"strings"

	"github.com/spf13/cast"
)

type Manager interface {
	RegisterKey(string, string, interface{}, ...Validator)
	RequireKey(string, string, ...Validator)

	AddSource(Source)

	GenerateBlank(Encoder) ([]byte, error)
}

// Validator is a validation function which would be coupled with a configuration
// key, anytime the config key is found in a Source it's value is validated.
type Validator func(interface{}) error

type Config interface {
	Parse() error
	Parsed() bool
	MustParse()

	Get(string) (interface{}, error)

	String(string) (string, error)
	Bool(string) (bool, error)
	Int(string) (int, error)
	Float64(string) (float64, error)
}

// Source is a source of configuration keys and values, calling unmarshal should
// return a map[string]interface{} of all key/value pairs (nesting is supported)
// with multiple types.
type Source interface {
	Unmarshal() (map[string]interface{}, error)
}

// Encoder would be used to encode registered and required values (along with
// their defaults or descriptions) into bytes.
type Encoder interface {
	Marshal(interface{}) ([]byte, error)
}

type Configr struct {
	valueValidators    map[string][]Validator
	registeredKeys     map[string]string
	requiredKeys       map[string]struct{}
	defaultValues      map[string]interface{}
	cache              map[string]interface{}
	sources            []Source
	parsed             bool
	keyDelimeter       string
	descriptionWrapper string
}

func New() *Configr {
	return &Configr{
		valueValidators:    make(map[string][]Validator),
		registeredKeys:     make(map[string]string),
		requiredKeys:       make(map[string]struct{}),
		defaultValues:      make(map[string]interface{}),
		cache:              make(map[string]interface{}),
		keyDelimeter:       ".",
		descriptionWrapper: "***",
	}
}

func GetConfigr() *Configr {
	return globalConfigr
}

func SetConfigr(c *Configr) {
	globalConfigr = c
}

var globalConfigr *Configr = New()
var ErrKeyNotFound = errors.New("configr: Key not found")
var ErrParseHasntBeenCalled = errors.New("configr: Trying to get values before calling Parse()")
var ErrNoRegisteredValues = errors.New("configr: No registered values to generate")

type ErrRequiredKeysMissing []string

func (e ErrRequiredKeysMissing) Error() string {
	sort.Strings(e)
	return fmt.Sprintf("configr: Missing required configuration values: %v", []string(e))
}

// RegisterKey registers a configuration key (name) along with a description
// of what the configuration key is for, a default value and optional validators
//
// name supports nested notation in the form of '.' delimitered keys (unless changed)
// e.g.
//     "user.age.month"
func RegisterKey(name, description string, defaultVal interface{}, validators ...Validator) {
	globalConfigr.RegisterKey(name, description, defaultVal, validators...)
}
func (c *Configr) RegisterKey(name, description string, defaultVal interface{}, validators ...Validator) {
	name = strings.ToLower(name)
	c.registeredKeys[name] = description

	if defaultVal != nil {
		c.defaultValues[name] = defaultVal
	}

	if len(validators) > 0 {
		c.valueValidators[name] = validators
	}
}

// RequireValue wraps the RegisterValue() call but upon parsing sources, if the
// configuration key (name) is not found, Parse() will return a
// ErrRequiredValuesMissing error
func RequireKey(name, description string, validators ...Validator) {
	globalConfigr.RequireKey(name, description, validators...)
}
func (c *Configr) RequireKey(name, description string, validators ...Validator) {
	name = strings.ToLower(name)
	c.requiredKeys[name] = struct{}{}
	c.RegisterKey(name, description, nil, validators...)
}

// AddSource registers Sources with the Configr instance to Unmarshal()
// when Parse() is called. Sources are parsed in a FILO order, meaning
// the first source added is considered the highest priority, and any
// keys from lower priority sources that are present in a higher will be
// overwritten
func AddSource(p Source) {
	globalConfigr.AddSource(p)
}
func (c *Configr) AddSource(p Source) {
	c.sources = append(c.sources, p)
}

// Parse calls Unmarshal on all registered sources, and caches the subsequent
// key/value's. Additional calls to Parse can be made to add additional config
// from sources.
//
// Sources are called in a FILO order, meaning the first source added is
// considered the highest priority, any keys set from lower priority sources
// found in higher priority will be overwritten.
func Parse() error {
	return globalConfigr.Parse()
}
func (c *Configr) Parse() error {
	if err := c.populateValues(); err != nil {
		return err
	}

	if err := c.checkRequiredKeys(); err != nil {
		return err
	}

	c.parsed = true
	return nil
}

func (c *Configr) checkRequiredKeys() error {
	missingKeys := []string{}

	for requiredKey := range c.requiredKeys {
		if _, err := c.get(requiredKey); err != nil {
			missingKeys = append(missingKeys, requiredKey)
		}
	}

	if len(missingKeys) > 0 {
		return ErrRequiredKeysMissing(missingKeys)
	}

	return nil
}

func (c *Configr) populateValues() error {
	for i := len(c.sources) - 1; i >= 0; i-- {
		source := c.sources[i]

		sourceValues, err := source.Unmarshal()
		if err != nil {
			return err
		}
		for key, value := range sourceValues {
			if err := c.set(key, value); err != nil {
				return err
			}
		}
	}

	return nil
}

// MustParse wraps Parse() and will panic if there are any resulting errors
func MustParse() {
	globalConfigr.MustParse()
}
func (c *Configr) MustParse() {
	if err := c.Parse(); err != nil {
		panic(err)
	}
}

func (c *Configr) set(key string, value interface{}) error {
	key = strings.ToLower(key)
	if err := c.runValidators(key, value); err != nil {
		return err
	}

	c.cache = c.mergeMap(key, value, c.cache)

	return nil
}

func (c *Configr) mergeMap(key string, value interface{}, targetMap map[string]interface{}) map[string]interface{} {
	if reflect.TypeOf(value).Kind() == reflect.Map {
		targetMap = c.traverseSubMap(key, cast.ToStringMap(value), targetMap)
	} else {
		path := strings.SplitN(key, c.keyDelimeter, 2)
		if len(path) == 2 {
			targetMap = c.traverseKeyPath(path[0], path[1], value, targetMap)
		} else {
			targetMap[key] = value
		}
	}

	return targetMap
}

func (c *Configr) traverseKeyPath(currentKey, keyRemainder string, value interface{}, targetMap map[string]interface{}) map[string]interface{} {
	if _, found := targetMap[currentKey]; !found {
		targetMap[currentKey] = make(map[string]interface{})
	}

	targetMap[currentKey] = c.mergeMap(keyRemainder, value, targetMap[currentKey].(map[string]interface{}))

	return targetMap
}

func (c *Configr) traverseSubMap(key string, value map[string]interface{}, targetMap map[string]interface{}) map[string]interface{} {
	for subKey, subValue := range value {
		if _, found := targetMap[key]; !found {
			targetMap[key] = make(map[string]interface{})
		}
		targetMap[key] = c.mergeMap(subKey, subValue, targetMap[key].(map[string]interface{}))
	}

	return targetMap
}

func (c *Configr) runValidators(key string, value interface{}) error {
	keysAndValues, err := c.findKeysAndValuesToValidate(key, value)
	if err != nil {
		return err
	}

	for validatorKey, valueToValidate := range keysAndValues {
		if validators, found := c.valueValidators[validatorKey]; found {
			for _, validate := range validators {
				if err := validate(valueToValidate); err != nil {
					return err
				}
			}
		}
	}

	return nil
}

func (c *Configr) findKeysAndValuesToValidate(key string, value interface{}) (map[string]interface{}, error) {
	keysAndValues := make(map[string]interface{})
	if reflect.TypeOf(value).Kind() == reflect.Map {
		for validatorKey := range c.valueValidators {
			if !strings.HasPrefix(validatorKey, key) {
				continue
			}
			valueToValidate := searchMap(cast.ToStringMap(value), strings.Split(validatorKey, c.keyDelimeter)[1:])
			keysAndValues[validatorKey] = valueToValidate
		}
	} else {
		keysAndValues[key] = value
	}

	return keysAndValues, nil
}

// Get can only be called after a Parse() has been done. Keys support the
// nested notation format:
//    "user.age.month"
//
// If a key is not found but has been registered with a default, the default
// will be returned
func Get(key string) (interface{}, error) {
	return globalConfigr.Get(key)
}
func (c *Configr) Get(key string) (interface{}, error) {
	if !c.Parsed() {
		return nil, ErrParseHasntBeenCalled
	}

	return c.get(key)
}

func (c *Configr) get(key string) (interface{}, error) {
	key = strings.ToLower(key)
	if value, found := c.cache[key]; found {
		return value, nil
	}

	path := strings.Split(key, c.keyDelimeter)
	parent, found := c.cache[path[0]]
	if found {
		if reflect.TypeOf(parent).Kind() == reflect.Map {
			if val := searchMap(cast.ToStringMap(parent), path[1:]); val != nil {
				return val, nil
			}
		}
	}

	if defaultValue, found := c.defaultValues[key]; found {
		return defaultValue, nil
	}

	return nil, ErrKeyNotFound
}

// From github.com/spf13/viper
func searchMap(source map[string]interface{}, path []string) interface{} {
	if len(path) == 0 {
		return source
	}

	if next, ok := source[path[0]]; ok {
		switch next.(type) {
		case map[string]interface{}:
			// Type assertion is safe here since it is only reached
			// if the type of `next` is the same as the type being asserted
			return searchMap(next.(map[string]interface{}), path[1:])
		default:
			return next
		}
	} else {
		return nil
	}
}

// String wraps Get() and will attempt to cast the resulting value to a string
// or error
func String(key string) (string, error) {
	return globalConfigr.String(key)
}
func (c *Configr) String(key string) (string, error) {
	val, err := c.Get(key)
	if err != nil {
		return "", err
	}
	return cast.ToStringE(val)
}

// Bool wraps Get() and will attempt to cast the resulting value to a bool
// or error
func Bool(key string) (bool, error) {
	return globalConfigr.Bool(key)
}
func (c *Configr) Bool(key string) (bool, error) {
	val, err := c.Get(key)
	if err != nil {
		return false, err
	}
	return cast.ToBoolE(val)
}

// Int wraps Get() and will attempt to cast the resulting value to a int
// or error
func Int(key string) (int, error) {
	return globalConfigr.Int(key)
}
func (c *Configr) Int(key string) (int, error) {
	val, err := c.Get(key)
	if err != nil {
		return 0, err
	}
	return cast.ToIntE(val)
}

// Float64 wraps Get() and will attempt to cast the resulting value to a float64
// or error
func Float64(key string) (float64, error) {
	return globalConfigr.Float64(key)
}
func (c *Configr) Float64(key string) (float64, error) {
	val, err := c.Get(key)
	if err != nil {
		return 0, err
	}
	return cast.ToFloat64E(val)
}

// Parsed lets the caller know if a Parse() call has been made or not
func Parsed() bool {
	return globalConfigr.Parsed()
}
func (c *Configr) Parsed() bool {
	return c.parsed
}

// GenerateBlank generates a 'blank' configuration using the passed Encoder,
// it will honour nested keys, use default values where possible and when not
// fall back to placing the description as the value.
func GenerateBlank(e Encoder) ([]byte, error) {
	return globalConfigr.GenerateBlank(e)
}
func (c *Configr) GenerateBlank(e Encoder) ([]byte, error) {
	if len(c.registeredKeys) == 0 {
		return []byte{}, ErrNoRegisteredValues
	}

	blankMap := make(map[string]interface{})
	for key, description := range c.registeredKeys {
		if defaultValue, found := c.defaultValues[key]; found {
			blankMap = c.mergeMap(key, defaultValue, blankMap)
		} else {
			blankMap = c.mergeMap(key, c.wrapDescription(description), blankMap)
		}
	}

	return e.Marshal(blankMap)
}

func (c *Configr) wrapDescription(description string) string {
	return strings.Join([]string{c.descriptionWrapper, description, c.descriptionWrapper}, " ")
}

func (c *Configr) SetKeyPathDelimeter(delimeter string) {
	c.keyDelimeter = delimeter
}
func (c *Configr) SetDescriptionWrapper(wrapper string) {
	c.descriptionWrapper = wrapper
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/acm"
	"github.com/hashicorp/errwrap"
	"github.com/hashicorp/terraform/helper/schema"
)

func dataSourceAwsAcmCertificate() *schema.Resource {
	return &schema.Resource{
		Read: dataSourceAwsAcmCertificateRead,
		Schema: map[string]*schema.Schema{
			"domain": {
				Type:     schema.TypeString,
				Required: true,
			},
			"arn": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"statuses": {
				Type:     schema.TypeList,
				Optional: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
			},
		},
	}
}

func dataSourceAwsAcmCertificateRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).acmconn
	params := &acm.ListCertificatesInput{}

	target := d.Get("domain")

	statuses, ok := d.GetOk("statuses")
	if ok {
		statusStrings := statuses.([]string)
		statusList := make([]*string, len(statusStrings))
		for i, status := range statusStrings {
			statusList[i] = aws.String(strings.ToUpper(status))
		}
		params.CertificateStatuses = statusList
	} else {
		params.CertificateStatuses = []*string{aws.String("ISSUED")}
	}

	var arns []string
	err := conn.ListCertificatesPages(params, func(page *acm.ListCertificatesOutput, lastPage bool) bool {
		for _, cert := range page.CertificateSummaryList {
			if *cert.DomainName == target {
				arns = append(arns, *cert.CertificateArn)
			}
		}

		return true
	})
	if err != nil {
		return errwrap.Wrapf("Error describing certificates: {{err}}", err)
	}

	if len(arns) == 0 {
		return fmt.Errorf("No certificate with statuses [%s] for domain %q found in this region.",
			strings.Join(statuses.([]string), ", "), target)
	}
	if len(arns) > 1 {
		return fmt.Errorf("Multiple certificates with statuses [%s] for domain %s found in this region.",
			strings.Join(statuses.([]string), ","), target)
	}

	d.SetId(time.Now().UTC().String())
	d.Set("arn", arns[0])

	return nil
}
<commit_msg>provider/aws: Fix panic when passing statuses to aws_acm_certificate (#9990)<commit_after>package aws

import (
	"fmt"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/acm"
	"github.com/hashicorp/errwrap"
	"github.com/hashicorp/terraform/helper/schema"
)

func dataSourceAwsAcmCertificate() *schema.Resource {
	return &schema.Resource{
		Read: dataSourceAwsAcmCertificateRead,
		Schema: map[string]*schema.Schema{
			"domain": {
				Type:     schema.TypeString,
				Required: true,
			},
			"arn": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"statuses": {
				Type:     schema.TypeList,
				Optional: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
			},
		},
	}
}

func dataSourceAwsAcmCertificateRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).acmconn
	params := &acm.ListCertificatesInput{}

	target := d.Get("domain")

	statuses, ok := d.GetOk("statuses")
	if ok {
		statusStrings := statuses.([]interface{})
		statusList := make([]*string, len(statusStrings))
		for i, status := range statusStrings {
			statusList[i] = aws.String(strings.ToUpper(status.(string)))
		}
		params.CertificateStatuses = statusList
	} else {
		params.CertificateStatuses = []*string{aws.String("ISSUED")}
	}

	var arns []string
	err := conn.ListCertificatesPages(params, func(page *acm.ListCertificatesOutput, lastPage bool) bool {
		for _, cert := range page.CertificateSummaryList {
			if *cert.DomainName == target {
				arns = append(arns, *cert.CertificateArn)
			}
		}

		return true
	})
	if err != nil {
		return errwrap.Wrapf("Error describing certificates: {{err}}", err)
	}

	if len(arns) == 0 {
		return fmt.Errorf("No certificate with statuses [%s] for domain %q found in this region.",
			strings.Join(statuses.([]string), ", "), target)
	}
	if len(arns) > 1 {
		return fmt.Errorf("Multiple certificates with statuses [%s] for domain %s found in this region.",
			strings.Join(statuses.([]string), ","), target)
	}

	d.SetId(time.Now().UTC().String())
	d.Set("arn", arns[0])

	return nil
}
<|endoftext|>


<commit_before>package retry

type AlwaysRetryStrategy struct{}

func (s *AlwaysRetryStrategy) Next() bool {
	return true
}

func (s *AlwaysRetryStrategy) HasNext() bool {
	return true
}

type CountStrategy struct {
	Tries int
	count int
}

// Type validation
var _ Strategy = &CountStrategy{}

func (s *CountStrategy) Next() bool {
	if s.count < s.Tries {
		s.count++
		return true
	}
	return false
}

func (s *CountStrategy) HasNext() bool {
	return s.count < s.Tries
}
<commit_msg>CountStrategy is not resettable<commit_after>package retry

// Retry forever.  No waiting.
type AlwaysRetryStrategy struct{}

func (s *AlwaysRetryStrategy) Next() bool {
	return true
}

func (s *AlwaysRetryStrategy) HasNext() bool {
	return true
}

// Try up to a fixed number of times
type CountStrategy struct {
	Tries int
	count int
}

func (s *CountStrategy) Next() bool {
	if s.count < s.Tries {
		s.count++
		return true
	}
	return false
}

func (s *CountStrategy) HasNext() bool {
	return s.count < s.Tries
}

func (s *CountStrategy) Reset() {
	s.count = 0
}
<|endoftext|>


<commit_before>package sirius

import (
	"golang.org/x/net/context"
)

type Service struct {
	loader  ExtensionLoader
	clients []Client
}

func NewService(l ExtensionLoader) *Service {
	return &Service{
		loader: l,
	}
}

func (s *Service) Start(ctx context.Context, users []User) {
	for _, user := range users {
		cl := NewClient(&user, s.loader)

		go cl.Start(ctx)
	}

	select {
	case <-ctx.Done():
		break
	}
}
<commit_msg>Fix bug where user references would leak between clients<commit_after>package sirius

import (
	"golang.org/x/net/context"
)

type Service struct {
	loader  ExtensionLoader
	clients []Client
}

func NewService(l ExtensionLoader) *Service {
	return &Service{
		loader: l,
	}
}

func (s *Service) Start(ctx context.Context, users []User) {
	for _, u := range users {
		u := u
		cl := NewClient(&u, s.loader)
		s.clients = append(s.clients, *cl)

		go cl.Start(ctx)
	}

	select {
	case <-ctx.Done():
		break
	}
}
<|endoftext|>


<commit_before>package scheduler

import (
	"testing"

	"github.com/hashicorp/nomad/nomad/mock"
	"github.com/hashicorp/nomad/nomad/structs"
)

func TestFeasibleRankIterator(t *testing.T) {
	_, ctx := testContext(t)
	var nodes []*structs.Node
	for i := 0; i < 10; i++ {
		nodes = append(nodes, mock.Node())
	}
	static := NewStaticIterator(ctx, nodes)

	feasible := NewFeasibleRankIterator(ctx, static)

	out := collectRanked(feasible)
	if len(out) != len(nodes) {
		t.Fatalf("bad: %v", out)
	}
}

func TestBinPackIterator(t *testing.T) {
	_, ctx := testContext(t)
	nodes := []*RankedNode{
		&RankedNode{
			Node: mock.Node(),
		},
		&RankedNode{
			Node: mock.Node(),
		},
		&RankedNode{
			Node: mock.Node(),
		},
	}
	static := NewStaticRankIterator(ctx, nodes)

	alloc := mock.Alloc()
	resources := alloc.Resources
	binp := NewBinPackIterator(ctx, static, resources, false, 0)

	out := collectRanked(binp)
	if len(out) != 3 {
		t.Fatalf("Bad: %v", out)
	}
}

func collectRanked(iter RankIterator) (out []*RankedNode) {
	for {
		next := iter.Next()
		if next == nil {
			break
		}
		out = append(out, next)
	}
	return
}
<commit_msg>scheduler: testing basic bin pack<commit_after>package scheduler

import (
	"testing"

	"github.com/hashicorp/nomad/nomad/mock"
	"github.com/hashicorp/nomad/nomad/structs"
)

func TestFeasibleRankIterator(t *testing.T) {
	_, ctx := testContext(t)
	var nodes []*structs.Node
	for i := 0; i < 10; i++ {
		nodes = append(nodes, mock.Node())
	}
	static := NewStaticIterator(ctx, nodes)

	feasible := NewFeasibleRankIterator(ctx, static)

	out := collectRanked(feasible)
	if len(out) != len(nodes) {
		t.Fatalf("bad: %v", out)
	}
}

func TestBinPackIterator_Simple_NoExistingAlloc(t *testing.T) {
	_, ctx := testContext(t)
	nodes := []*RankedNode{
		&RankedNode{
			Node: &structs.Node{
				// Perfect fit
				Resources: &structs.Resources{
					CPU:      2048,
					MemoryMB: 2048,
				},
				Reserved: &structs.Resources{
					CPU:      1024,
					MemoryMB: 1024,
				},
			},
		},
		&RankedNode{
			Node: &structs.Node{
				// Overloaded
				Resources: &structs.Resources{
					CPU:      1024,
					MemoryMB: 1024,
				},
				Reserved: &structs.Resources{
					CPU:      512,
					MemoryMB: 512,
				},
			},
		},
		&RankedNode{
			Node: &structs.Node{
				// 50% fit
				Resources: &structs.Resources{
					CPU:      4096,
					MemoryMB: 4096,
				},
				Reserved: &structs.Resources{
					CPU:      1024,
					MemoryMB: 1024,
				},
			},
		},
	}
	static := NewStaticRankIterator(ctx, nodes)

	resources := &structs.Resources{
		CPU:      1024,
		MemoryMB: 1024,
	}
	binp := NewBinPackIterator(ctx, static, resources, false, 0)

	out := collectRanked(binp)
	if len(out) != 2 {
		t.Fatalf("Bad: %v", out)
	}
	if out[0] != nodes[0] || out[1] != nodes[2] {
		t.Fatalf("Bad: %v", out)
	}

	if out[0].Score != 18 {
		t.Fatalf("Bad: %v", out[0])
	}
	if out[1].Score < 10 || out[1].Score > 16 {
		t.Fatalf("Bad: %v", out[1])
	}
}

func collectRanked(iter RankIterator) (out []*RankedNode) {
	for {
		next := iter.Next()
		if next == nil {
			break
		}
		out = append(out, next)
	}
	return
}
<|endoftext|>


<commit_before>package main

const(
INDEX_PAGE_CONTENT = `

	<title>RequestHub</title>

RequestHub

<form method="POST">
	<input type="text" name="hub_name" />
	<input type="submit" value="Create Hub"/>
</form>

My Hubs:

`

HUB_PAGE_CONTENT = `

	<title>RequestHub - {{.Id}}</title>

RequestHub

{{.Id}}

Clear

`
)
<commit_msg>Fix issue when request body isn't JSON<commit_after>package main

const(
INDEX_PAGE_CONTENT = `

	<title>RequestHub</title>

RequestHub

<form method="POST">
	<input type="text" name="hub_name" />
	<input type="submit" value="Create Hub"/>
</form>

My Hubs:

`

HUB_PAGE_CONTENT = `

	<title>RequestHub - {{.Id}}</title>

RequestHub

{{.Id}}

Clear

`
)
<|endoftext|>


<commit_before>package logo

import (
	"strings"
)

/*
	List of Console Text Colors
*/
const (
	ConsoleColorDefaultText      = "\x1b[39m"
	ConsoleColorBlackText        = "\x1b[30m"
	ConsoleColorRedText          = "\x1b[31m"
	ConsoleColorGreenText        = "\x1b[32m"
	ConsoleColorYellowText       = "\x1b[33m"
	ConsoleColorBlueText         = "\x1b[34m"
	ConsoleColorMagentaText      = "\x1b[35m"
	ConsoleColorCyanText         = "\x1b[36m"
	ConsoleColorLightGrayText    = "\x1b[37m"
	ConsoleColorDarkGrayText     = "\x1b[90m"
	ConsoleColorLightRedText     = "\x1b[91m"
	ConsoleColorLightGreenText   = "\x1b[92m"
	ConsoleColorLightYellowText  = "\x1b[93m"
	ConsoleColorLightBlueText    = "\x1b[94m"
	ConsoleColorLightMagentaText = "\x1b[95m"
	ConsoleColorLightCyanText    = "\x1b[96m"
	ConsoleColorWhiteText        = "\x1b[97m"
)

/*
	List of Console Background Colors
*/
const (
	ConsoleColorDefaultBackground      = "\x1b[49m"
	ConsoleColorBlackBackground        = "\x1b[40m"
	ConsoleColorRedBackground          = "\x1b[41m"
	ConsoleColorGreenBackground        = "\x1b[42m"
	ConsoleColorYellowBackground       = "\x1b[43m"
	ConsoleColorBlueBackground         = "\x1b[44m"
	ConsoleColorMagentaBackground      = "\x1b[45m"
	ConsoleColorCyanBackground         = "\x1b[46m"
	ConsoleColorLightGrayBackground    = "\x1b[47m"
	ConsoleColorDarkGrayBackground     = "\x1b[100m"
	ConsoleColorLightRedBackground     = "\x1b[101m"
	ConsoleColorLightGreenBackground   = "\x1b[102m"
	ConsoleColorLightYellowBackground  = "\x1b[103m"
	ConsoleColorLightBlueBackground    = "\x1b[104m"
	ConsoleColorLightMagentaBackground = "\x1b[105m"
	ConsoleColorLightCyanBackground    = "\x1b[106m"
	ConsoleColorWhiteBackground        = "\x1b[107m"
)

/*
	List of Console Text Effects
*/
const (
	ConsoleColorBold       = "\x1b[1m"
	ConsoleColorDim        = "\x1b[2m"
	ConsoleColorUnderlined = "\x1b[4m"
	ConsoleColorBlink      = "\x1b[5m"
	ConsoleColorReverse    = "\x1b[7m"
	ConsoleColorHidden     = "\x1b[8m"
)

/*
	A Color Aspect describes text and background colors and effects
*/
type ConsoleColorAspect struct {
	TextColor       string
	BackgroundColor string
	TextEffect      []string
}

/*
	A Color Theme is a list of Color Aspect (one for each logging level)
*/
type ConsoleColorTheme struct {
	Silly    ConsoleColorAspect
	Debug    ConsoleColorAspect
	Verbose  ConsoleColorAspect
	Info     ConsoleColorAspect
	Warn     ConsoleColorAspect
	Error    ConsoleColorAspect
	Critical ConsoleColorAspect
}

/*
	List of available theme for console logging (At the moment there is only one, but more are coming)
*/
var (
	darkConsoleColorTheme = ConsoleColorTheme{
		ConsoleColorAspect{ConsoleColorDarkGrayText, ConsoleColorDefaultBackground, []string{}},            // Silly
		ConsoleColorAspect{ConsoleColorDefaultText, ConsoleColorDefaultBackground, []string{}},             // Debug
		ConsoleColorAspect{ConsoleColorLightGreenText, ConsoleColorDefaultBackground, []string{}},          // Verbose
		ConsoleColorAspect{ConsoleColorLightBlueText, ConsoleColorDefaultBackground, []string{}},           // Info
		ConsoleColorAspect{ConsoleColorLightYellowText, ConsoleColorDefaultBackground, []string{}},         // Warn
		ConsoleColorAspect{ConsoleColorLightRedText, ConsoleColorDefaultBackground, []string{}},            // Error
		ConsoleColorAspect{ConsoleColorDefaultText, ConsoleColorRedBackground, []string{ConsoleColorBold}}, // Critical
	}
	lightConsoleColorTheme = ConsoleColorTheme{
		ConsoleColorAspect{ConsoleColorDarkGrayText, ConsoleColorDefaultBackground, []string{}},            // Silly
		ConsoleColorAspect{ConsoleColorDefaultText, ConsoleColorDefaultBackground, []string{}},             // Debug
		ConsoleColorAspect{ConsoleColorGreenText, ConsoleColorDefaultBackground, []string{}},               // Verbose
		ConsoleColorAspect{ConsoleColorBlueText, ConsoleColorDefaultBackground, []string{}},                // Info
		ConsoleColorAspect{ConsoleColorYellowText, ConsoleColorDefaultBackground, []string{}},              // Warn
		ConsoleColorAspect{ConsoleColorRedText, ConsoleColorDefaultBackground, []string{}},                 // Error
		ConsoleColorAspect{ConsoleColorDefaultText, ConsoleColorRedBackground, []string{ConsoleColorBold}}, // Critical
	}
)

/*
	Apply a color theme on a string with the corect logging level
*/
func ApplyConsoleColor(s string, level int, c ConsoleColorTheme) string {
	var sr string = ""        // String to return
	var ct ConsoleColorAspect // Console Color Aspect to use

	// Get the correct logging level
	switch level {
	case Silly:
		ct = c.Silly
	case Debug:
		ct = c.Debug
	case Verbose:
		ct = c.Verbose
	case Info:
		ct = c.Info
	case Warn:
		ct = c.Warn
	case Error:
		ct = c.Error
	case Critical:
		ct = c.Critical
	}

	sr += ct.TextColor                    // Add text color
	sr += ct.BackgroundColor              // Add background color
	sr += strings.Join(ct.TextEffect, "") // Add effects
	sr += s                               // Add the log
	sr += "\x1b[0m"                       // Reset all colors and effects

	return sr // Return result
}
<commit_msg>Changed green color for dark console color<commit_after>package logo

import (
	"strings"
)

/*
	List of Console Text Colors
*/
const (
	ConsoleColorDefaultText      = "\x1b[39m"
	ConsoleColorBlackText        = "\x1b[30m"
	ConsoleColorRedText          = "\x1b[31m"
	ConsoleColorGreenText        = "\x1b[32m"
	ConsoleColorYellowText       = "\x1b[33m"
	ConsoleColorBlueText         = "\x1b[34m"
	ConsoleColorMagentaText      = "\x1b[35m"
	ConsoleColorCyanText         = "\x1b[36m"
	ConsoleColorLightGrayText    = "\x1b[37m"
	ConsoleColorDarkGrayText     = "\x1b[90m"
	ConsoleColorLightRedText     = "\x1b[91m"
	ConsoleColorLightGreenText   = "\x1b[92m"
	ConsoleColorLightYellowText  = "\x1b[93m"
	ConsoleColorLightBlueText    = "\x1b[94m"
	ConsoleColorLightMagentaText = "\x1b[95m"
	ConsoleColorLightCyanText    = "\x1b[96m"
	ConsoleColorWhiteText        = "\x1b[97m"
)

/*
	List of Console Background Colors
*/
const (
	ConsoleColorDefaultBackground      = "\x1b[49m"
	ConsoleColorBlackBackground        = "\x1b[40m"
	ConsoleColorRedBackground          = "\x1b[41m"
	ConsoleColorGreenBackground        = "\x1b[42m"
	ConsoleColorYellowBackground       = "\x1b[43m"
	ConsoleColorBlueBackground         = "\x1b[44m"
	ConsoleColorMagentaBackground      = "\x1b[45m"
	ConsoleColorCyanBackground         = "\x1b[46m"
	ConsoleColorLightGrayBackground    = "\x1b[47m"
	ConsoleColorDarkGrayBackground     = "\x1b[100m"
	ConsoleColorLightRedBackground     = "\x1b[101m"
	ConsoleColorLightGreenBackground   = "\x1b[102m"
	ConsoleColorLightYellowBackground  = "\x1b[103m"
	ConsoleColorLightBlueBackground    = "\x1b[104m"
	ConsoleColorLightMagentaBackground = "\x1b[105m"
	ConsoleColorLightCyanBackground    = "\x1b[106m"
	ConsoleColorWhiteBackground        = "\x1b[107m"
)

/*
	List of Console Text Effects
*/
const (
	ConsoleColorBold       = "\x1b[1m"
	ConsoleColorDim        = "\x1b[2m"
	ConsoleColorUnderlined = "\x1b[4m"
	ConsoleColorBlink      = "\x1b[5m"
	ConsoleColorReverse    = "\x1b[7m"
	ConsoleColorHidden     = "\x1b[8m"
)

/*
	A Color Aspect describes text and background colors and effects
*/
type ConsoleColorAspect struct {
	TextColor       string
	BackgroundColor string
	TextEffect      []string
}

/*
	A Color Theme is a list of Color Aspect (one for each logging level)
*/
type ConsoleColorTheme struct {
	Silly    ConsoleColorAspect
	Debug    ConsoleColorAspect
	Verbose  ConsoleColorAspect
	Info     ConsoleColorAspect
	Warn     ConsoleColorAspect
	Error    ConsoleColorAspect
	Critical ConsoleColorAspect
}

/*
	List of available theme for console logging (At the moment there is only one, but more are coming)
*/
var (
	darkConsoleColorTheme = ConsoleColorTheme{
		ConsoleColorAspect{ConsoleColorDarkGrayText, ConsoleColorDefaultBackground, []string{}},            // Silly
		ConsoleColorAspect{ConsoleColorDefaultText, ConsoleColorDefaultBackground, []string{}},             // Debug
		ConsoleColorAspect{ConsoleColorGreenText, ConsoleColorDefaultBackground, []string{}},               // Verbose
		ConsoleColorAspect{ConsoleColorLightBlueText, ConsoleColorDefaultBackground, []string{}},           // Info
		ConsoleColorAspect{ConsoleColorLightYellowText, ConsoleColorDefaultBackground, []string{}},         // Warn
		ConsoleColorAspect{ConsoleColorLightRedText, ConsoleColorDefaultBackground, []string{}},            // Error
		ConsoleColorAspect{ConsoleColorDefaultText, ConsoleColorRedBackground, []string{ConsoleColorBold}}, // Critical
	}
	lightConsoleColorTheme = ConsoleColorTheme{
		ConsoleColorAspect{ConsoleColorDarkGrayText, ConsoleColorDefaultBackground, []string{}},            // Silly
		ConsoleColorAspect{ConsoleColorDefaultText, ConsoleColorDefaultBackground, []string{}},             // Debug
		ConsoleColorAspect{ConsoleColorGreenText, ConsoleColorDefaultBackground, []string{}},               // Verbose
		ConsoleColorAspect{ConsoleColorBlueText, ConsoleColorDefaultBackground, []string{}},                // Info
		ConsoleColorAspect{ConsoleColorYellowText, ConsoleColorDefaultBackground, []string{}},              // Warn
		ConsoleColorAspect{ConsoleColorRedText, ConsoleColorDefaultBackground, []string{}},                 // Error
		ConsoleColorAspect{ConsoleColorDefaultText, ConsoleColorRedBackground, []string{ConsoleColorBold}}, // Critical
	}
)

/*
	Apply a color theme on a string with the corect logging level
*/
func ApplyConsoleColor(s string, level int, c ConsoleColorTheme) string {
	var sr string = ""        // String to return
	var ct ConsoleColorAspect // Console Color Aspect to use

	// Get the correct logging level
	switch level {
	case Silly:
		ct = c.Silly
	case Debug:
		ct = c.Debug
	case Verbose:
		ct = c.Verbose
	case Info:
		ct = c.Info
	case Warn:
		ct = c.Warn
	case Error:
		ct = c.Error
	case Critical:
		ct = c.Critical
	}

	sr += ct.TextColor                    // Add text color
	sr += ct.BackgroundColor              // Add background color
	sr += strings.Join(ct.TextEffect, "") // Add effects
	sr += s                               // Add the log
	sr += "\x1b[0m"                       // Reset all colors and effects

	return sr // Return result
}
<|endoftext|>


<commit_before>package sqlgen

import (
	"context"
	"testing"
	"time"

	_ "github.com/go-sql-driver/mysql"
	"github.com/samsarahq/thunder/internal/testfixtures"
	"github.com/stretchr/testify/assert"
)

func setup() (*testfixtures.TestDatabase, *DB, error) {
	testDb, err := testfixtures.NewTestDatabase()
	if err != nil {
		return nil, nil, err
	}

	if _, err = testDb.Exec(`
		CREATE TABLE users (
			id   BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
			name VARCHAR(255),
			uuid VARCHAR(255),
			mood VARCHAR(255)
		)
	`); err != nil {
		return nil, nil, err
	}
	schema := NewSchema()
	schema.MustRegisterType("users", AutoIncrement, User{})

	return testDb, NewDB(testDb.DB, schema), nil
}

type User struct {
	Id   int64 `sql:",primary"`
	Name string
	Uuid testfixtures.CustomType
	Mood *testfixtures.CustomType
}

type Complex struct {
	Id       int64 `sql:",primary"`
	Name     string
	Text     []byte            `sql:",string"`
	Blob     []byte            `sql:",binary"`
	Mappings map[string]string `sql:",json"`
}

func TestTagOverrides(t *testing.T) {
	schema := NewSchema()
	err := schema.RegisterType("complex", AutoIncrement, Complex{})
	assert.NoError(t, err)
}

func TestContextDeadlineEnforced(t *testing.T) {
	tdb, db, err := setup()
	if err != nil {
		t.Fatal(err)
	}
	defer tdb.Close()

	ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
	defer cancel()
	if _, err = db.QueryExecer(ctx).ExecContext(ctx, "DO SLEEP(1)"); err == nil || err != context.DeadlineExceeded {
		t.Errorf("Expected context.DeadlineExceeded, got: %s", err)
	}
}

func TestIntegrationBasic(t *testing.T) {
	tdb, db, err := setup()
	if err != nil {
		t.Fatal(err)
	}
	defer tdb.Close()

	mood := testfixtures.CustomType{'f', 'o', 'o', 'o', 'o', 'o', 'o'}

	if _, err := db.InsertRow(context.Background(), &User{Name: "Bob", Uuid: testfixtures.CustomType{'1', '1', '2', '3', '8', '4', '9', '1', '2', '9', '3'}, Mood: &mood}); err != nil {
		t.Error(err)
	}

	var users []*User
	if err := db.Query(context.Background(), &users, nil, nil); err != nil {
		t.Error(err)
	}

	assert.Equal(t, []*User{
		{
			Id:   1,
			Name: "Bob",
			Uuid: testfixtures.CustomType{'1', '1', '2', '3', '8', '4', '9', '1', '2', '9', '3'},
			Mood: &mood,
		},
	}, users)
}

// TestContextCancelBeforeRowsScan demonstrates we don't
// always get context.Canceled back from sql library. This
// affects our error handling and we need to be aware of it.
func TestContextCancelBeforeRowsScan(t *testing.T) {
	testDb, err := testfixtures.NewTestDatabase()
	if err != nil {
		t.Fatal(err)
	}
	defer testDb.Close()

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	rows, err := testDb.QueryContext(ctx, `select "foo"`)
	if err != nil {
		t.Fatal(err)
	}
	defer rows.Close()

	// When we cancel the context after rows.Next() returns true,
	// database/sql.(*Rows).initContextClose monitors the context
	// and closes rows asynchronously, and subsequent rows.Scan()
	// returns errors.New("sql: Rows are closed") instead of
	// context.Canceled.
	for rows.Next() {
		cancel()
		time.Sleep(1000 * time.Millisecond)

		var foo string
		err := rows.Scan(&foo)

		// err is not context.Canceled.
		if err == nil || err.Error() != "sql: Rows are closed" {
			t.Fatalf("expecting 'sql: Rows are closed' from rows.Scan(), got %v", err)
		}
	}
	if err := rows.Err(); err != context.Canceled {
		t.Fatalf("expecting context.Canceled from rows.Err(), got %v", err)
	}
}

func Benchmark(b *testing.B) {
	tdb, db, err := setup()
	if err != nil {
		b.Fatal(err)
	}
	defer tdb.Close()

	ctx := context.Background()

	mood := testfixtures.CustomType{'f', 'o', 'o', 'o', 'o', 'o', 'o'}
	user := &User{
		Id:   1,
		Name: "Bob",
		Uuid: testfixtures.CustomType{'1', '1', '2', '3', '8', '4', '9', '1', '2', '9', '3'},
		Mood: &mood,
	}

	if _, err := db.InsertRow(ctx, user); err != nil {
		b.Fatal(err)
	}

	benchmarks := []struct {
		name string
		fn   func() error
	}{
		{"Read", func() error {
			user := &User{}
			return db.QueryRow(ctx, &user, nil, nil)
		}},
		{"Create", func() error {
			_, err := db.InsertRow(ctx, user)
			return err
		}},
		{"Update", func() error { return db.UpdateRow(ctx, user) }},
		{"Delete", func() error { return db.DeleteRow(ctx, user) }},
	}

	for _, bm := range benchmarks {
		b.Run(bm.name, func(b *testing.B) {
			b.ReportAllocs()
			for i := 0; i < b.N; i++ {
				if err := bm.fn(); err != nil {
					b.Error(err)
				}
			}
		})
	}
}
<commit_msg>go: add benchmark for where clause<commit_after>package sqlgen

import (
	"context"
	"testing"
	"time"

	_ "github.com/go-sql-driver/mysql"
	"github.com/samsarahq/thunder/internal/testfixtures"
	"github.com/stretchr/testify/assert"
)

func setup() (*testfixtures.TestDatabase, *DB, error) {
	testDb, err := testfixtures.NewTestDatabase()
	if err != nil {
		return nil, nil, err
	}

	if _, err = testDb.Exec(`
		CREATE TABLE users (
			id   BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
			name VARCHAR(255),
			uuid VARCHAR(255),
			mood VARCHAR(255)
		)
	`); err != nil {
		return nil, nil, err
	}
	schema := NewSchema()
	schema.MustRegisterType("users", AutoIncrement, User{})

	return testDb, NewDB(testDb.DB, schema), nil
}

type User struct {
	Id   int64 `sql:",primary"`
	Name string
	Uuid testfixtures.CustomType
	Mood *testfixtures.CustomType
}

type Complex struct {
	Id       int64 `sql:",primary"`
	Name     string
	Text     []byte            `sql:",string"`
	Blob     []byte            `sql:",binary"`
	Mappings map[string]string `sql:",json"`
}

func TestTagOverrides(t *testing.T) {
	schema := NewSchema()
	err := schema.RegisterType("complex", AutoIncrement, Complex{})
	assert.NoError(t, err)
}

func TestContextDeadlineEnforced(t *testing.T) {
	tdb, db, err := setup()
	if err != nil {
		t.Fatal(err)
	}
	defer tdb.Close()

	ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
	defer cancel()
	if _, err = db.QueryExecer(ctx).ExecContext(ctx, "DO SLEEP(1)"); err == nil || err != context.DeadlineExceeded {
		t.Errorf("Expected context.DeadlineExceeded, got: %s", err)
	}
}

func TestIntegrationBasic(t *testing.T) {
	tdb, db, err := setup()
	if err != nil {
		t.Fatal(err)
	}
	defer tdb.Close()

	mood := testfixtures.CustomType{'f', 'o', 'o', 'o', 'o', 'o', 'o'}

	if _, err := db.InsertRow(context.Background(), &User{Name: "Bob", Uuid: testfixtures.CustomType{'1', '1', '2', '3', '8', '4', '9', '1', '2', '9', '3'}, Mood: &mood}); err != nil {
		t.Error(err)
	}

	var users []*User
	if err := db.Query(context.Background(), &users, nil, nil); err != nil {
		t.Error(err)
	}

	assert.Equal(t, []*User{
		{
			Id:   1,
			Name: "Bob",
			Uuid: testfixtures.CustomType{'1', '1', '2', '3', '8', '4', '9', '1', '2', '9', '3'},
			Mood: &mood,
		},
	}, users)
}

// TestContextCancelBeforeRowsScan demonstrates we don't
// always get context.Canceled back from sql library. This
// affects our error handling and we need to be aware of it.
func TestContextCancelBeforeRowsScan(t *testing.T) {
	testDb, err := testfixtures.NewTestDatabase()
	if err != nil {
		t.Fatal(err)
	}
	defer testDb.Close()

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	rows, err := testDb.QueryContext(ctx, `select "foo"`)
	if err != nil {
		t.Fatal(err)
	}
	defer rows.Close()

	// When we cancel the context after rows.Next() returns true,
	// database/sql.(*Rows).initContextClose monitors the context
	// and closes rows asynchronously, and subsequent rows.Scan()
	// returns errors.New("sql: Rows are closed") instead of
	// context.Canceled.
	for rows.Next() {
		cancel()
		time.Sleep(1000 * time.Millisecond)

		var foo string
		err := rows.Scan(&foo)

		// err is not context.Canceled.
		if err == nil || err.Error() != "sql: Rows are closed" {
			t.Fatalf("expecting 'sql: Rows are closed' from rows.Scan(), got %v", err)
		}
	}
	if err := rows.Err(); err != context.Canceled {
		t.Fatalf("expecting context.Canceled from rows.Err(), got %v", err)
	}
}

func Benchmark(b *testing.B) {
	tdb, db, err := setup()
	if err != nil {
		b.Fatal(err)
	}
	defer tdb.Close()

	ctx := context.Background()

	mood := testfixtures.CustomType{'f', 'o', 'o', 'o', 'o', 'o', 'o'}
	user := &User{
		Id:   1,
		Name: "Bob",
		Uuid: testfixtures.CustomType{'1', '1', '2', '3', '8', '4', '9', '1', '2', '9', '3'},
		Mood: &mood,
	}

	if _, err := db.InsertRow(ctx, user); err != nil {
		b.Fatal(err)
	}

	benchmarks := []struct {
		name string
		fn   func() error
	}{
		{"Read", func() error {
			user := &User{}
			return db.QueryRow(ctx, &user, nil, nil)
		}},
		{"Read_Where", func() error {
			user := &User{}
			return db.QueryRow(ctx, &user, Filter{"name": "Bob"}, nil)
		}},
		{"Create", func() error {
			_, err := db.InsertRow(ctx, user)
			return err
		}},
		{"Update", func() error { return db.UpdateRow(ctx, user) }},
		{"Delete", func() error { return db.DeleteRow(ctx, user) }},
	}

	for _, bm := range benchmarks {
		b.Run(bm.name, func(b *testing.B) {
			b.ReportAllocs()
			for i := 0; i < b.N; i++ {
				if err := bm.fn(); err != nil {
					b.Error(err)
				}
			}
		})
	}
}
<|endoftext|>


<commit_before>package cluster

import (
	"fmt"
	"sync/atomic"
	"time"

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

var _ = Describe("Consumer", func() {

	var newConsumer = func(group string) (*Consumer, error) {
		config := NewConfig()
		config.Consumer.Return.Errors = true
		return NewConsumer(testKafkaAddrs, group, testTopics, config)
	}

	var newConsumerOf = func(group, topic string) (*Consumer, error) {
		config := NewConfig()
		config.Consumer.Return.Errors = true
		return NewConsumer(testKafkaAddrs, group, []string{topic}, config)
	}

	var subscriptionsOf = func(c *Consumer) GomegaAsyncAssertion {
		return Eventually(func() map[string][]int32 {
			return c.Subscriptions()
		}, "10s", "100ms")
	}

	var consume = func(consumerID, group string, max int, out chan *testConsumerMessage) {
		go func() {
			defer GinkgoRecover()

			cs, err := newConsumer(group)
			Expect(err).NotTo(HaveOccurred())
			defer cs.Close()
			cs.consumerID = consumerID

			for msg := range cs.Messages() {
				out <- &testConsumerMessage{*msg, consumerID}
				cs.MarkOffset(msg, "")

				if max--; max == 0 {
					return
				}
			}
		}()
	}

	It("should init and share", func() {
		cs1, err := newConsumer(testGroup)
		Expect(err).NotTo(HaveOccurred())
		defer cs1.Close()

		subscriptionsOf(cs1).Should(Equal(map[string][]int32{
			"topic-a": {0, 1, 2, 3},
			"topic-b": {0, 1, 2, 3},
		}))

		cs2, err := newConsumer(testGroup)
		Expect(err).NotTo(HaveOccurred())
		defer cs2.Close()

		subscriptionsOf(cs1).Should(HaveLen(2))
		subscriptionsOf(cs1).Should(HaveKeyWithValue("topic-a", HaveLen(2)))
		subscriptionsOf(cs1).Should(HaveKeyWithValue("topic-b", HaveLen(2)))

		subscriptionsOf(cs2).Should(HaveLen(2))
		subscriptionsOf(cs2).Should(HaveKeyWithValue("topic-a", HaveLen(2)))
		subscriptionsOf(cs2).Should(HaveKeyWithValue("topic-b", HaveLen(2)))
	})

	It("should allow more consumers than partitions", func() {
		cs1, err := newConsumerOf(testGroup, "topic-a")
		Expect(err).NotTo(HaveOccurred())
		defer cs1.Close()
		cs2, err := newConsumerOf(testGroup, "topic-a")
		Expect(err).NotTo(HaveOccurred())
		defer cs2.Close()
		cs3, err := newConsumerOf(testGroup, "topic-a")
		Expect(err).NotTo(HaveOccurred())
		defer cs3.Close()
		cs4, err := newConsumerOf(testGroup, "topic-a")
		Expect(err).NotTo(HaveOccurred())

		// start 4 consumers, one for each partition
		subscriptionsOf(cs1).Should(HaveKeyWithValue("topic-a", HaveLen(1)))
		subscriptionsOf(cs2).Should(HaveKeyWithValue("topic-a", HaveLen(1)))
		subscriptionsOf(cs3).Should(HaveKeyWithValue("topic-a", HaveLen(1)))
		subscriptionsOf(cs4).Should(HaveKeyWithValue("topic-a", HaveLen(1)))

		// add a 5th consumer
		cs5, err := newConsumerOf(testGroup, "topic-a")
		Expect(err).NotTo(HaveOccurred())
		defer cs5.Close()

		// wait for rebalance, make sure no errors occurred
		Eventually(func() bool { return atomic.LoadInt32(&cs5.consuming) == 1 }, "10s", "100ms").Should(BeTrue())
		time.Sleep(time.Second)
		Expect(cs1.Errors()).ShouldNot(Receive())
		Expect(cs2.Errors()).ShouldNot(Receive())
		Expect(cs3.Errors()).ShouldNot(Receive())
		Expect(cs4.Errors()).ShouldNot(Receive())
		Expect(cs5.Errors()).ShouldNot(Receive())

		// close 4th, make sure the 5th takes over
		cs4.Close()
		Eventually(func() bool { return atomic.LoadInt32(&cs4.consuming) == 1 }, "10s", "100ms").Should(BeFalse())
		subscriptionsOf(cs4).Should(BeEmpty())
		subscriptionsOf(cs5).Should(HaveKeyWithValue("topic-a", HaveLen(1)))

		// there should still be no errors
		Expect(cs1.Errors()).ShouldNot(Receive())
		Expect(cs2.Errors()).ShouldNot(Receive())
		Expect(cs3.Errors()).ShouldNot(Receive())
		Expect(cs4.Errors()).ShouldNot(Receive())
		Expect(cs5.Errors()).ShouldNot(Receive())
	})

	It("should support manual mark/commit", func() {
		cs, err := newConsumerOf(testGroup, "topic-a")
		Expect(err).NotTo(HaveOccurred())
		defer cs.Close()

		subscriptionsOf(cs).Should(Equal(map[string][]int32{
			"topic-a": {0, 1, 2, 3}},
		))

		cs.MarkPartitionOffset("topic-a", 1, 3, "")
		cs.MarkPartitionOffset("topic-a", 2, 4, "")
		Expect(cs.CommitOffsets()).NotTo(HaveOccurred())

		offsets, err := cs.fetchOffsets(cs.Subscriptions())
		Expect(err).NotTo(HaveOccurred())
		Expect(offsets).To(Equal(map[string]map[int32]offsetInfo{
			"topic-a": {0: {Offset: -1}, 1: {Offset: 3}, 2: {Offset: 4}, 3: {Offset: -1}},
		}))
	})

	It("should consume/commit/resume", func() {
		acc := make(chan *testConsumerMessage, 150000)
		consume("A", "fuzzing", 2000, acc)
		consume("B", "fuzzing", 2000, acc)
		consume("C", "fuzzing", 1000, acc)
		consume("D", "fuzzing", 100, acc)
		consume("E", "fuzzing", 200, acc)

		Expect(testSeed(5000)).NotTo(HaveOccurred())
		Eventually(func() int { return len(acc) }, "30s", "100ms").Should(BeNumerically(">=", 5000))

		consume("F", "fuzzing", 300, acc)
		consume("G", "fuzzing", 400, acc)
		consume("H", "fuzzing", 1000, acc)
		consume("I", "fuzzing", 2000, acc)
		Expect(testSeed(5000)).NotTo(HaveOccurred())
		Eventually(func() int { return len(acc) }, "30s", "100ms").Should(BeNumerically(">=", 8000))

		consume("J", "fuzzing", 1000, acc)
		Expect(testSeed(5000)).NotTo(HaveOccurred())
		Eventually(func() int { return len(acc) }, "30s", "100ms").Should(BeNumerically(">=", 9000))

		consume("K", "fuzzing", 1000, acc)
		consume("L", "fuzzing", 3000, acc)
		Expect(testSeed(5000)).NotTo(HaveOccurred())
		Eventually(func() int { return len(acc) }, "30s", "100ms").Should(BeNumerically(">=", 12000))

		consume("M", "fuzzing", 1000, acc)
		Expect(testSeed(5000)).NotTo(HaveOccurred())
		Eventually(func() int { return len(acc) }, "30s", "100ms").Should(BeNumerically(">=", 15000))

		close(acc)

		uniques := make(map[string][]string)
		for msg := range acc {
			key := fmt.Sprintf("%s/%d/%d", msg.Topic, msg.Partition, msg.Offset)
			uniques[key] = append(uniques[key], msg.ConsumerID)
		}
		Expect(uniques).To(HaveLen(15000))
	})

})
<commit_msg>Added test for rebalance-on-leave<commit_after>package cluster

import (
	"fmt"
	"sync/atomic"
	"time"

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

var _ = Describe("Consumer", func() {

	var newConsumer = func(group string) (*Consumer, error) {
		config := NewConfig()
		config.Consumer.Return.Errors = true
		return NewConsumer(testKafkaAddrs, group, testTopics, config)
	}

	var newConsumerOf = func(group, topic string) (*Consumer, error) {
		config := NewConfig()
		config.Consumer.Return.Errors = true
		return NewConsumer(testKafkaAddrs, group, []string{topic}, config)
	}

	var subscriptionsOf = func(c *Consumer) GomegaAsyncAssertion {
		return Eventually(func() map[string][]int32 {
			return c.Subscriptions()
		}, "10s", "100ms")
	}

	var consume = func(consumerID, group string, max int, out chan *testConsumerMessage) {
		go func() {
			defer GinkgoRecover()

			cs, err := newConsumer(group)
			Expect(err).NotTo(HaveOccurred())
			defer cs.Close()
			cs.consumerID = consumerID

			for msg := range cs.Messages() {
				out <- &testConsumerMessage{*msg, consumerID}
				cs.MarkOffset(msg, "")

				if max--; max == 0 {
					return
				}
			}
		}()
	}

	It("should init and share", func() {
		// start CS1
		cs1, err := newConsumer(testGroup)
		Expect(err).NotTo(HaveOccurred())

		// CS1 should consume all 8 partitions
		subscriptionsOf(cs1).Should(Equal(map[string][]int32{
			"topic-a": {0, 1, 2, 3},
			"topic-b": {0, 1, 2, 3},
		}))

		// start CS2
		cs2, err := newConsumer(testGroup)
		Expect(err).NotTo(HaveOccurred())
		defer cs2.Close()

		// CS1 and CS2 should consume 4 partitions each
		subscriptionsOf(cs1).Should(HaveLen(2))
		subscriptionsOf(cs1).Should(HaveKeyWithValue("topic-a", HaveLen(2)))
		subscriptionsOf(cs1).Should(HaveKeyWithValue("topic-b", HaveLen(2)))

		subscriptionsOf(cs2).Should(HaveLen(2))
		subscriptionsOf(cs2).Should(HaveKeyWithValue("topic-a", HaveLen(2)))
		subscriptionsOf(cs2).Should(HaveKeyWithValue("topic-b", HaveLen(2)))

		// shutdown CS1, now CS2 should consume all 8 partitions
		Expect(cs1.Close()).NotTo(HaveOccurred())
		subscriptionsOf(cs2).Should(Equal(map[string][]int32{
			"topic-a": {0, 1, 2, 3},
			"topic-b": {0, 1, 2, 3},
		}))
	})

	It("should allow more consumers than partitions", func() {
		cs1, err := newConsumerOf(testGroup, "topic-a")
		Expect(err).NotTo(HaveOccurred())
		defer cs1.Close()
		cs2, err := newConsumerOf(testGroup, "topic-a")
		Expect(err).NotTo(HaveOccurred())
		defer cs2.Close()
		cs3, err := newConsumerOf(testGroup, "topic-a")
		Expect(err).NotTo(HaveOccurred())
		defer cs3.Close()
		cs4, err := newConsumerOf(testGroup, "topic-a")
		Expect(err).NotTo(HaveOccurred())

		// start 4 consumers, one for each partition
		subscriptionsOf(cs1).Should(HaveKeyWithValue("topic-a", HaveLen(1)))
		subscriptionsOf(cs2).Should(HaveKeyWithValue("topic-a", HaveLen(1)))
		subscriptionsOf(cs3).Should(HaveKeyWithValue("topic-a", HaveLen(1)))
		subscriptionsOf(cs4).Should(HaveKeyWithValue("topic-a", HaveLen(1)))

		// add a 5th consumer
		cs5, err := newConsumerOf(testGroup, "topic-a")
		Expect(err).NotTo(HaveOccurred())
		defer cs5.Close()

		// wait for rebalance, make sure no errors occurred
		Eventually(func() bool { return atomic.LoadInt32(&cs5.consuming) == 1 }, "10s", "100ms").Should(BeTrue())
		time.Sleep(time.Second)
		Expect(cs1.Errors()).ShouldNot(Receive())
		Expect(cs2.Errors()).ShouldNot(Receive())
		Expect(cs3.Errors()).ShouldNot(Receive())
		Expect(cs4.Errors()).ShouldNot(Receive())
		Expect(cs5.Errors()).ShouldNot(Receive())

		// close 4th, make sure the 5th takes over
		cs4.Close()
		Eventually(func() bool { return atomic.LoadInt32(&cs4.consuming) == 1 }, "10s", "100ms").Should(BeFalse())
		subscriptionsOf(cs4).Should(BeEmpty())
		subscriptionsOf(cs5).Should(HaveKeyWithValue("topic-a", HaveLen(1)))

		// there should still be no errors
		Expect(cs1.Errors()).ShouldNot(Receive())
		Expect(cs2.Errors()).ShouldNot(Receive())
		Expect(cs3.Errors()).ShouldNot(Receive())
		Expect(cs4.Errors()).ShouldNot(Receive())
		Expect(cs5.Errors()).ShouldNot(Receive())
	})

	It("should support manual mark/commit", func() {
		cs, err := newConsumerOf(testGroup, "topic-a")
		Expect(err).NotTo(HaveOccurred())
		defer cs.Close()

		subscriptionsOf(cs).Should(Equal(map[string][]int32{
			"topic-a": {0, 1, 2, 3}},
		))

		cs.MarkPartitionOffset("topic-a", 1, 3, "")
		cs.MarkPartitionOffset("topic-a", 2, 4, "")
		Expect(cs.CommitOffsets()).NotTo(HaveOccurred())

		offsets, err := cs.fetchOffsets(cs.Subscriptions())
		Expect(err).NotTo(HaveOccurred())
		Expect(offsets).To(Equal(map[string]map[int32]offsetInfo{
			"topic-a": {0: {Offset: -1}, 1: {Offset: 3}, 2: {Offset: 4}, 3: {Offset: -1}},
		}))
	})

	It("should consume/commit/resume", func() {
		acc := make(chan *testConsumerMessage, 150000)
		consume("A", "fuzzing", 2000, acc)
		consume("B", "fuzzing", 2000, acc)
		consume("C", "fuzzing", 1000, acc)
		consume("D", "fuzzing", 100, acc)
		consume("E", "fuzzing", 200, acc)

		Expect(testSeed(5000)).NotTo(HaveOccurred())
		Eventually(func() int { return len(acc) }, "30s", "100ms").Should(BeNumerically(">=", 5000))

		consume("F", "fuzzing", 300, acc)
		consume("G", "fuzzing", 400, acc)
		consume("H", "fuzzing", 1000, acc)
		consume("I", "fuzzing", 2000, acc)
		Expect(testSeed(5000)).NotTo(HaveOccurred())
		Eventually(func() int { return len(acc) }, "30s", "100ms").Should(BeNumerically(">=", 8000))

		consume("J", "fuzzing", 1000, acc)
		Expect(testSeed(5000)).NotTo(HaveOccurred())
		Eventually(func() int { return len(acc) }, "30s", "100ms").Should(BeNumerically(">=", 9000))

		consume("K", "fuzzing", 1000, acc)
		consume("L", "fuzzing", 3000, acc)
		Expect(testSeed(5000)).NotTo(HaveOccurred())
		Eventually(func() int { return len(acc) }, "30s", "100ms").Should(BeNumerically(">=", 12000))

		consume("M", "fuzzing", 1000, acc)
		Expect(testSeed(5000)).NotTo(HaveOccurred())
		Eventually(func() int { return len(acc) }, "30s", "100ms").Should(BeNumerically(">=", 15000))

		close(acc)

		uniques := make(map[string][]string)
		for msg := range acc {
			key := fmt.Sprintf("%s/%d/%d", msg.Topic, msg.Partition, msg.Offset)
			uniques[key] = append(uniques[key], msg.ConsumerID)
		}
		Expect(uniques).To(HaveLen(15000))
	})

})
<|endoftext|>


<commit_before>package capn

import (
	"golang.org/x/net/context"
)

// A Client makes calls for an interface type.
type Client interface {
	// Call calls a method with an existing parameters struct.  This is
	// used when the RPC system receives a call for an exported object.
	Call(
		ctx context.Context,
		method *Method,
		params Struct) Promise

	// NewCall calls a method, allowing the client to allocate the
	// parameters struct.  This is used when application code is using
	// a client.
	NewCall(
		ctx context.Context,
		method *Method,
		paramsSize ObjectSize,
		params func(Struct)) Promise

	// Close releases any resources associated with this client.
	// No further calls to the client should be made after calling Close.
	Close() error
}

// A Promise is a generic promise for a Struct.
type Promise interface {
	Get() (Struct, error)
	GetClient(off int) Client
	GetPromise(off int) Promise
	GetPromiseDefault(off int, s *Segment, tagoff int) Promise
}

// A Method identifies a method along with an optional human-readable
// description of the method.
type Method struct {
	InterfaceID uint64
	MethodID    uint16

	// Canonical name of the interface.  May be empty.
	InterfaceName string
	// Method name as it appears in the schema.  May be empty.
	MethodName string
}

type immediatePromise Struct

// ImmediatePromise returns a Promise that accesses s.
func ImmediatePromise(s Struct) Promise {
	return immediatePromise(s)
}

func (ip immediatePromise) Get() (Struct, error) {
	return Struct(ip), nil
}

func (ip immediatePromise) GetClient(off int) Client {
	return Struct(ip).GetObject(off).ToInterface().Client()
}

func (ip immediatePromise) GetPromise(off int) Promise {
	return immediatePromise(Struct(ip).GetObject(off).ToStruct())
}

func (ip immediatePromise) GetPromiseDefault(off int, s *Segment, tagoff int) Promise {
	return immediatePromise(Struct(ip).GetObject(off).ToStructDefault(s, tagoff))
}

type errorPromise struct {
	e error
}

// ErrorPromise returns a Promise that always returns error e.
func ErrorPromise(e error) Promise {
	return errorPromise{e}
}

func (ep errorPromise) Get() (Struct, error) {
	return Struct{}, ep.e
}

func (ep errorPromise) GetClient(off int) Client {
	return ErrorClient(ep.e)
}

func (ep errorPromise) GetPromise(off int) Promise {
	return ep
}

func (ep errorPromise) GetPromiseDefault(off int, s *Segment, tagoff int) Promise {
	return ep
}

type errorClient struct {
	e error
}

// ErrorClient returns a Client that always returns error e.
func ErrorClient(e error) Client {
	return errorClient{e}
}

func (ec errorClient) NewCall(ctx context.Context, method *Method, paramsSize ObjectSize, params func(Struct)) Promise {
	return ErrorPromise(ec.e)
}

func (ec errorClient) Call(ctx context.Context, method *Method, params Struct) Promise {
	return ErrorPromise(ec.e)
}

func (ec errorClient) Close() error {
	return nil
}
<commit_msg>Add Method.String method<commit_after>package capn

import (
	"strconv"

	"golang.org/x/net/context"
)

// A Client makes calls for an interface type.
type Client interface {
	// Call calls a method with an existing parameters struct.  This is
	// used when the RPC system receives a call for an exported object.
	Call(
		ctx context.Context,
		method *Method,
		params Struct) Promise

	// NewCall calls a method, allowing the client to allocate the
	// parameters struct.  This is used when application code is using
	// a client.
	NewCall(
		ctx context.Context,
		method *Method,
		paramsSize ObjectSize,
		params func(Struct)) Promise

	// Close releases any resources associated with this client.
	// No further calls to the client should be made after calling Close.
	Close() error
}

// A Promise is a generic promise for a Struct.
type Promise interface {
	Get() (Struct, error)
	GetClient(off int) Client
	GetPromise(off int) Promise
	GetPromiseDefault(off int, s *Segment, tagoff int) Promise
}

// A Method identifies a method along with an optional human-readable
// description of the method.
type Method struct {
	InterfaceID uint64
	MethodID    uint16

	// Canonical name of the interface.  May be empty.
	InterfaceName string
	// Method name as it appears in the schema.  May be empty.
	MethodName string
}

// String returns a formatted string containing the interface name or
// the method name if present, otherwise it uses the raw IDs.
// This is suitable for use in error messages and logs.
func (m *Method) String() string {
	buf := make([]byte, 0, 128)
	if m.InterfaceName == "" {
		buf = append(buf, '@', '0', 'x')
		buf = strconv.AppendUint(buf, m.InterfaceID, 16)
	} else {
		buf = append(buf, m.InterfaceName...)
	}
	buf = append(buf, '/')
	if m.MethodName == "" {
		buf = append(buf, '@')
		buf = strconv.AppendUint(buf, uint64(m.MethodID), 10)
	} else {
		buf = append(buf, m.MethodName...)
	}
	return string(buf)
}

type immediatePromise Struct

// ImmediatePromise returns a Promise that accesses s.
func ImmediatePromise(s Struct) Promise {
	return immediatePromise(s)
}

func (ip immediatePromise) Get() (Struct, error) {
	return Struct(ip), nil
}

func (ip immediatePromise) GetClient(off int) Client {
	return Struct(ip).GetObject(off).ToInterface().Client()
}

func (ip immediatePromise) GetPromise(off int) Promise {
	return immediatePromise(Struct(ip).GetObject(off).ToStruct())
}

func (ip immediatePromise) GetPromiseDefault(off int, s *Segment, tagoff int) Promise {
	return immediatePromise(Struct(ip).GetObject(off).ToStructDefault(s, tagoff))
}

type errorPromise struct {
	e error
}

// ErrorPromise returns a Promise that always returns error e.
func ErrorPromise(e error) Promise {
	return errorPromise{e}
}

func (ep errorPromise) Get() (Struct, error) {
	return Struct{}, ep.e
}

func (ep errorPromise) GetClient(off int) Client {
	return ErrorClient(ep.e)
}

func (ep errorPromise) GetPromise(off int) Promise {
	return ep
}

func (ep errorPromise) GetPromiseDefault(off int, s *Segment, tagoff int) Promise {
	return ep
}

type errorClient struct {
	e error
}

// ErrorClient returns a Client that always returns error e.
func ErrorClient(e error) Client {
	return errorClient{e}
}

func (ec errorClient) NewCall(ctx context.Context, method *Method, paramsSize ObjectSize, params func(Struct)) Promise {
	return ErrorPromise(ec.e)
}

func (ec errorClient) Call(ctx context.Context, method *Method, params Struct) Promise {
	return ErrorPromise(ec.e)
}

func (ec errorClient) Close() error {
	return nil
}
<|endoftext|>


<commit_before>package restgo

import (
	"github.com/fasthttp-contrib/render"
	"github.com/valyala/fasthttp"
	"sync"
)

type Context struct {
	*fasthttp.RequestCtx
	*render.Render
}

func contextPool() sync.Pool {
	return sync.Pool{
		New: func() interface{} {
			return &Context{}
		},
	}
}

// Get path parameter or query parameter as int. if not exist, default value will be returned
func (this *Context) ParamInt(key string, defVal int) int {
	val, err := this.URI().QueryArgs().GetUint(key)
	if err != nil {
		return defVal
	}
	return val
}

// Get path parameter or query parameter as float64. if not exist, default value will be returned
func (this *Context) ParamFloat(key string, defVal float64) float64 {
	val, err := this.URI().QueryArgs().GetUfloat(key)
	if err != nil {
		return defVal
	}
	return val
}

// Get path parameter or query parameter as string. if not exist, default value will be returned
func (this *Context) ParamString(key string, defVal string) string {
	val := this.URI().QueryArgs().Peek(key)
	if val == nil {
		return defVal
	}
	return string(val)
}

func (this *Context) ServeJSON(status int, v interface{}) error {
	return this.JSON(this.RequestCtx, status, v)
}

func (this *Context) ServeJSONP(status int, callback string, v interface{}) error {
	return this.JSONP(this.RequestCtx, status, callback, v)
}

func (this *Context) ServeText(status int, v string) error {
	return this.Text(this.RequestCtx, status, v)
}

func (this *Context) ServeXML(status int, v interface{}) error {
	return this.XML(this.RequestCtx, status, v)
}

func (this *Context) ServeHTML(status int, name string, binding interface{}, layout ...string) error {
	return this.HTML(this.RequestCtx, status, name, binding, layout...)
}

func (this *Context) ServeData(status int, v []byte) error {
	return this.Data(this.RequestCtx, status, v)
}

func (this *Context) ServeError(status int, err error) error{
	return this.Text(this.RequestCtx, status, err.Error())
}
<commit_msg>define JSON type<commit_after>package restgo

import (
	"github.com/fasthttp-contrib/render"
	"github.com/valyala/fasthttp"
	"sync"
)

type Context struct {
	*fasthttp.RequestCtx
	*render.Render
}

type JSON map[string]interface{}

func contextPool() sync.Pool {
	return sync.Pool{
		New: func() interface{} {
			return &Context{}
		},
	}
}

// Get path parameter or query parameter as int. if not exist, default value will be returned
func (this *Context) ParamInt(key string, defVal int) int {
	val, err := this.URI().QueryArgs().GetUint(key)
	if err != nil {
		return defVal
	}
	return val
}

// Get path parameter or query parameter as float64. if not exist, default value will be returned
func (this *Context) ParamFloat(key string, defVal float64) float64 {
	val, err := this.URI().QueryArgs().GetUfloat(key)
	if err != nil {
		return defVal
	}
	return val
}

// Get path parameter or query parameter as string. if not exist, default value will be returned
func (this *Context) ParamString(key string, defVal string) string {
	val := this.URI().QueryArgs().Peek(key)
	if val == nil {
		return defVal
	}
	return string(val)
}

func (this *Context) ServeJSON(status int, v interface{}) error {
	return this.JSON(this.RequestCtx, status, v)
}

func (this *Context) ServeJSONP(status int, callback string, v interface{}) error {
	return this.JSONP(this.RequestCtx, status, callback, v)
}

func (this *Context) ServeText(status int, v string) error {
	return this.Text(this.RequestCtx, status, v)
}

func (this *Context) ServeXML(status int, v interface{}) error {
	return this.XML(this.RequestCtx, status, v)
}

func (this *Context) ServeHTML(status int, name string, binding interface{}, layout ...string) error {
	return this.HTML(this.RequestCtx, status, name, binding, layout...)
}

func (this *Context) ServeData(status int, v []byte) error {
	return this.Data(this.RequestCtx, status, v)
}

func (this *Context) ServeError(status int, err error) error{
	return this.Text(this.RequestCtx, status, err.Error())
}
<|endoftext|>


<commit_before>package echo

import (
	"encoding/json"
	"encoding/xml"
	"io"
	"mime"
	"net/http"
	"os"
	"path/filepath"
	"time"

	"github.com/webx-top/echo/engine"
	"github.com/webx-top/echo/logger"

	"bytes"

	netContext "golang.org/x/net/context"
)

type (
	// Context represents context for the current request. It holds request and
	// response objects, path parameters, data and registered handler.
	Context interface {
		netContext.Context
		Request() engine.Request
		Response() engine.Response
		Path() string
		P(int) string
		Param(string) string

		// ParamNames returns path parameter names.
		ParamNames() []string

		// Queries returns the query parameters as map. It is an alias for `engine.URL#Query()`.
		Queries() map[string][]string
		QueryValues(string) []string
		Query(string) string

		Form(string) string
		FormValues(string) []string

		// Forms returns the form parameters as map. It is an alias for `engine.Request#Form().All()`.
		Forms() map[string][]string

		Set(string, interface{})
		Get(string) interface{}
		Bind(interface{}) error
		Render(int, string, interface{}) error
		HTML(int, string) error
		String(int, string) error
		JSON(int, interface{}) error
		JSONBlob(int, []byte) error
		JSONP(int, string, interface{}) error
		XML(int, interface{}) error
		XMLBlob(int, []byte) error
		File(string) error
		Attachment(io.ReadSeeker, string) error
		NoContent(int) error
		Redirect(int, string) error
		Error(err error)
		Handle(Context) error
		Logger() logger.Logger
		Object() *context

		// ServeContent sends static content from `io.Reader` and handles caching
		// via `If-Modified-Since` request header. It automatically sets `Content-Type`
		// and `Last-Modified` response headers.
		ServeContent(io.ReadSeeker, string, time.Time) error

		SetFunc(string, interface{})
		GetFunc(string) interface{}
		ResetFuncs(map[string]interface{})
		Funcs() map[string]interface{}
		Reset(engine.Request, engine.Response)
		Fetch(string, interface{}) ([]byte, error)
		SetRenderer(Renderer)
	}

	context struct {
		netContext netContext.Context
		request    engine.Request
		response   engine.Response
		path       string
		pnames     []string
		pvalues    []string
		store      store
		handler    Handler
		echo       *Echo
		funcs      map[string]interface{}
		renderer   Renderer
	}

	store map[string]interface{}
)

const (
	indexPage = "index.html"
)

// NewContext creates a Context object.
func NewContext(req engine.Request, res engine.Response, e *Echo) Context {
	return &context{
		request:  req,
		response: res,
		echo:     e,
		pvalues:  make([]string, *e.maxParam),
		store:    make(store),
		handler:  notFoundHandler,
		funcs:    make(map[string]interface{}),
	}
}

func (c *context) NetContext() netContext.Context {
	return c.netContext
}

func (c *context) SetNetContext(ctx netContext.Context) {
	c.netContext = ctx
}

func (c *context) Deadline() (deadline time.Time, ok bool) {
	return c.netContext.Deadline()
}

func (c *context) Done() <-chan struct{} {
	return c.netContext.Done()
}

func (c *context) Err() error {
	return c.netContext.Err()
}

func (c *context) Value(key interface{}) interface{} {
	return c.netContext.Value(key)
}

func (c *context) Handle(ctx Context) error {
	return c.handler.Handle(ctx)
}

// Request returns *http.Request.
func (c *context) Request() engine.Request {
	return c.request
}

// Response returns *Response.
func (c *context) Response() engine.Response {
	return c.response
}

// Path returns the registered path for the handler.
func (c *context) Path() string {
	return c.path
}

// P returns path parameter by index.
func (c *context) P(i int) (value string) {
	l := len(c.pnames)
	if i < l {
		value = c.pvalues[i]
	}
	return
}

// Param returns path parameter by name.
func (c *context) Param(name string) (value string) {
	l := len(c.pnames)
	for i, n := range c.pnames {
		if n == name && i < l {
			value = c.pvalues[i]
			break
		}
	}
	return
}

func (c *context) ParamNames() []string {
	return c.pnames
}

// Query returns query parameter by name.
func (c *context) Query(name string) string {
	return c.request.URL().QueryValue(name)
}

func (c *context) QueryValues(name string) []string {
	return c.request.URL().QueryValues(name)
}

func (c *context) Queries() map[string][]string {
	return c.request.URL().Query()
}

// Form returns form parameter by name.
func (c *context) Form(name string) string {
	return c.request.FormValue(name)
}

func (c *context) FormValues(name string) []string {
	return c.request.Form().Gets(name)
}

func (c *context) Forms() map[string][]string {
	return c.request.Form().All()
}

// Get retrieves data from the context.
func (c *context) Get(key string) interface{} {
	return c.store[key]
}

// Set saves data in the context.
func (c *context) Set(key string, val interface{}) {
	if c.store == nil {
		c.store = make(store)
	}
	c.store[key] = val
}

// Bind binds the request body into specified type `i`. The default binder does
// it based on Content-Type header.
func (c *context) Bind(i interface{}) error {
	return c.echo.binder.Bind(i, c)
}

// Render renders a template with data and sends a text/html response with status
// code. Templates can be registered using `Echo.SetRenderer()`.
func (c *context) Render(code int, name string, data interface{}) (err error) {
	b, err := c.Fetch(name, data)
	if err != nil {
		return
	}
	c.response.Header().Set(HeaderContentType, MIMETextHTMLCharsetUTF8)
	c.response.WriteHeader(code)
	_, err = c.response.Write(b)
	return
}

// HTML sends an HTTP response with status code.
func (c *context) HTML(code int, html string) (err error) {
	c.response.Header().Set(HeaderContentType, MIMETextHTMLCharsetUTF8)
	c.response.WriteHeader(code)
	_, err = c.response.Write([]byte(html))
	return
}

// String sends a string response with status code.
func (c *context) String(code int, s string) (err error) {
	c.response.Header().Set(HeaderContentType, MIMETextPlainCharsetUTF8)
	c.response.WriteHeader(code)
	_, err = c.response.Write([]byte(s))
	return
}

// JSON sends a JSON response with status code.
func (c *context) JSON(code int, i interface{}) (err error) {
	var b []byte
	if c.echo.Debug() {
		b, err = json.MarshalIndent(i, "", "  ")
	} else {
		b, err = json.Marshal(i)
	}
	if err != nil {
		return err
	}
	return c.JSONBlob(code, b)
}

// JSONBlob sends a JSON blob response with status code.
func (c *context) JSONBlob(code int, b []byte) (err error) {
	c.response.Header().Set(HeaderContentType, MIMEApplicationJSONCharsetUTF8)
	c.response.WriteHeader(code)
	_, err = c.response.Write(b)
	return
}

// JSONP sends a JSONP response with status code. It uses `callback` to construct
// the JSONP payload.
func (c *context) JSONP(code int, callback string, i interface{}) (err error) {
	b, err := json.Marshal(i)
	if err != nil {
		return err
	}
	c.response.Header().Set(HeaderContentType, MIMEApplicationJavaScriptCharsetUTF8)
	c.response.WriteHeader(code)

	if _, err = c.response.Write([]byte(callback + "(")); err != nil {
		return
	}
	if _, err = c.response.Write(b); err != nil {
		return
	}
	_, err = c.response.Write([]byte(");"))
	return
}

// XML sends an XML response with status code.
func (c *context) XML(code int, i interface{}) (err error) {
	var b []byte
	if c.echo.Debug() {
		b, err = xml.MarshalIndent(i, "", "  ")
	} else {
		b, err = xml.Marshal(i)
	}
	if err != nil {
		return err
	}
	return c.XMLBlob(code, b)
}

// XMLBlob sends a XML blob response with status code.
func (c *context) XMLBlob(code int, b []byte) (err error) {
	c.response.Header().Set(HeaderContentType, MIMEApplicationXMLCharsetUTF8)
	c.response.WriteHeader(code)
	if _, err = c.response.Write([]byte(xml.Header)); err != nil {
		return
	}
	_, err = c.response.Write(b)
	return
}

func (c *context) File(file string) error {
	f, err := os.Open(file)
	if err != nil {
		return ErrNotFound
	}
	defer f.Close()

	fi, _ := f.Stat()
	if fi.IsDir() {
		file = filepath.Join(file, "index.html")
		f, err = os.Open(file)
		if err != nil {
			return ErrNotFound
		}
		fi, _ = f.Stat()
	}
	return c.ServeContent(f, fi.Name(), fi.ModTime())
}

func (c *context) Attachment(r io.ReadSeeker, name string) (err error) {
	c.response.Header().Set(HeaderContentType, ContentTypeByExtension(name))
	c.response.Header().Set(HeaderContentDisposition, "attachment; filename="+name)
	c.response.WriteHeader(http.StatusOK)
	_, err = io.Copy(c.response, r)
	return
}

// NoContent sends a response with no body and a status code.
func (c *context) NoContent(code int) error {
	c.response.WriteHeader(code)
	return nil
}

// Redirect redirects the request with status code.
func (c *context) Redirect(code int, url string) error {
	if code < http.StatusMultipleChoices || code > http.StatusTemporaryRedirect {
		return ErrInvalidRedirectCode
	}
	c.response.Redirect(url, code)
	return nil
}

// Error invokes the registered HTTP error handler. Generally used by middleware.
func (c *context) Error(err error) {
	c.echo.httpErrorHandler(err, c)
}

// Logger returns the `Logger` instance.
func (c *context) Logger() logger.Logger {
	return c.echo.logger
}

// Object returns the `context` object.
func (c *context) Object() *context {
	return c
}

func (c *context) ServeContent(content io.ReadSeeker, name string, modtime time.Time) error {
	rq := c.Request()
	rs := c.Response()

	if t, err := time.Parse(http.TimeFormat, rq.Header().Get(HeaderIfModifiedSince)); err == nil && modtime.Before(t.Add(1*time.Second)) {
		rs.Header().Del(HeaderContentType)
		rs.Header().Del(HeaderContentLength)
		return c.NoContent(http.StatusNotModified)
	}

	rs.Header().Set(HeaderContentType, ContentTypeByExtension(name))
	rs.Header().Set(HeaderLastModified, modtime.UTC().Format(http.TimeFormat))
	rs.WriteHeader(http.StatusOK)
	_, err := io.Copy(rs, content)
	return err
}

// ContentTypeByExtension returns the MIME type associated with the file based on
// its extension. It returns `application/octet-stream` incase MIME type is not
// found.
func ContentTypeByExtension(name string) (t string) {
	if t = mime.TypeByExtension(filepath.Ext(name)); t == "" {
		t = MIMEOctetStream
	}
	return
}

// Echo returns the `Echo` instance.
func (c *context) Echo() *Echo {
	return c.echo
}

func (c *context) Reset(req engine.Request, res engine.Response) {
	c.netContext = nil
	c.request = req
	c.response = res
	c.store = nil
	c.funcs = make(map[string]interface{})
	c.renderer = nil
	c.handler = notFoundHandler
}

func (c *context) GetFunc(key string) interface{} {
	return c.funcs[key]
}

func (c *context) SetFunc(key string, val interface{}) {
	c.funcs[key] = val
}

func (c *context) ResetFuncs(funcs map[string]interface{}) {
	c.funcs = funcs
}

func (c *context) Funcs() map[string]interface{} {
	return c.funcs
}

func (c *context) Fetch(name string, data interface{}) (b []byte, err error) {
	if c.renderer == nil {
		if c.echo.renderer == nil {
			return nil, ErrRendererNotRegistered
		}
		c.renderer = c.echo.renderer
	}
	buf := new(bytes.Buffer)
	err = c.renderer.Render(buf, name, data, c)
	if err != nil {
		return
	}
	b = buf.Bytes()
	return
}

// SetRenderer registers an HTML template renderer.
func (c *context) SetRenderer(r Renderer) {
	c.renderer = r
}
<commit_msg>context->xContext; netContext->context<commit_after>package echo

import (
	"encoding/json"
	"encoding/xml"
	"io"
	"mime"
	"net/http"
	"os"
	"path/filepath"
	"time"

	"github.com/webx-top/echo/engine"
	"github.com/webx-top/echo/logger"

	"bytes"

	"golang.org/x/net/context"
)

type (
	// Context represents context for the current request. It holds request and
	// response objects, path parameters, data and registered handler.
	Context interface {
		context.Context
		Request() engine.Request
		Response() engine.Response
		Path() string
		P(int) string
		Param(string) string

		// ParamNames returns path parameter names.
		ParamNames() []string

		// Queries returns the query parameters as map. It is an alias for `engine.URL#Query()`.
		Queries() map[string][]string
		QueryValues(string) []string
		Query(string) string

		Form(string) string
		FormValues(string) []string

		// Forms returns the form parameters as map. It is an alias for `engine.Request#Form().All()`.
		Forms() map[string][]string

		Set(string, interface{})
		Get(string) interface{}
		Bind(interface{}) error
		Render(int, string, interface{}) error
		HTML(int, string) error
		String(int, string) error
		JSON(int, interface{}) error
		JSONBlob(int, []byte) error
		JSONP(int, string, interface{}) error
		XML(int, interface{}) error
		XMLBlob(int, []byte) error
		File(string) error
		Attachment(io.ReadSeeker, string) error
		NoContent(int) error
		Redirect(int, string) error
		Error(err error)
		Handle(Context) error
		Logger() logger.Logger
		Object() *xContext

		// ServeContent sends static content from `io.Reader` and handles caching
		// via `If-Modified-Since` request header. It automatically sets `Content-Type`
		// and `Last-Modified` response headers.
		ServeContent(io.ReadSeeker, string, time.Time) error

		SetFunc(string, interface{})
		GetFunc(string) interface{}
		ResetFuncs(map[string]interface{})
		Funcs() map[string]interface{}
		Reset(engine.Request, engine.Response)
		Fetch(string, interface{}) ([]byte, error)
		SetRenderer(Renderer)
	}

	xContext struct {
		context  context.Context
		request  engine.Request
		response engine.Response
		path     string
		pnames   []string
		pvalues  []string
		store    store
		handler  Handler
		echo     *Echo
		funcs    map[string]interface{}
		renderer Renderer
	}

	store map[string]interface{}
)

const (
	indexPage = "index.html"
)

// NewContext creates a Context object.
func NewContext(req engine.Request, res engine.Response, e *Echo) Context {
	return &xContext{
		context:  context.Background(),
		request:  req,
		response: res,
		echo:     e,
		pvalues:  make([]string, *e.maxParam),
		store:    make(store),
		handler:  notFoundHandler,
		funcs:    make(map[string]interface{}),
	}
}

func (c *xContext) Context() context.Context {
	return c.context
}

func (c *xContext) SetContext(ctx context.Context) {
	c.context = ctx
}

func (c *xContext) Deadline() (deadline time.Time, ok bool) {
	return c.context.Deadline()
}

func (c *xContext) Done() <-chan struct{} {
	return c.context.Done()
}

func (c *xContext) Err() error {
	return c.context.Err()
}

func (c *xContext) Value(key interface{}) interface{} {
	return c.context.Value(key)
}

func (c *xContext) Handle(ctx Context) error {
	return c.handler.Handle(ctx)
}

// Request returns *http.Request.
func (c *xContext) Request() engine.Request {
	return c.request
}

// Response returns *Response.
func (c *xContext) Response() engine.Response {
	return c.response
}

// Path returns the registered path for the handler.
func (c *xContext) Path() string {
	return c.path
}

// P returns path parameter by index.
func (c *xContext) P(i int) (value string) {
	l := len(c.pnames)
	if i < l {
		value = c.pvalues[i]
	}
	return
}

// Param returns path parameter by name.
func (c *xContext) Param(name string) (value string) {
	l := len(c.pnames)
	for i, n := range c.pnames {
		if n == name && i < l {
			value = c.pvalues[i]
			break
		}
	}
	return
}

func (c *xContext) ParamNames() []string {
	return c.pnames
}

// Query returns query parameter by name.
func (c *xContext) Query(name string) string {
	return c.request.URL().QueryValue(name)
}

func (c *xContext) QueryValues(name string) []string {
	return c.request.URL().QueryValues(name)
}

func (c *xContext) Queries() map[string][]string {
	return c.request.URL().Query()
}

// Form returns form parameter by name.
func (c *xContext) Form(name string) string {
	return c.request.FormValue(name)
}

func (c *xContext) FormValues(name string) []string {
	return c.request.Form().Gets(name)
}

func (c *xContext) Forms() map[string][]string {
	return c.request.Form().All()
}

// Get retrieves data from the context.
func (c *xContext) Get(key string) interface{} {
	return c.store[key]
}

// Set saves data in the context.
func (c *xContext) Set(key string, val interface{}) {
	if c.store == nil {
		c.store = make(store)
	}
	c.store[key] = val
}

// Bind binds the request body into specified type `i`. The default binder does
// it based on Content-Type header.
func (c *xContext) Bind(i interface{}) error {
	return c.echo.binder.Bind(i, c)
}

// Render renders a template with data and sends a text/html response with status
// code. Templates can be registered using `Echo.SetRenderer()`.
func (c *xContext) Render(code int, name string, data interface{}) (err error) {
	b, err := c.Fetch(name, data)
	if err != nil {
		return
	}
	c.response.Header().Set(HeaderContentType, MIMETextHTMLCharsetUTF8)
	c.response.WriteHeader(code)
	_, err = c.response.Write(b)
	return
}

// HTML sends an HTTP response with status code.
func (c *xContext) HTML(code int, html string) (err error) {
	c.response.Header().Set(HeaderContentType, MIMETextHTMLCharsetUTF8)
	c.response.WriteHeader(code)
	_, err = c.response.Write([]byte(html))
	return
}

// String sends a string response with status code.
func (c *xContext) String(code int, s string) (err error) {
	c.response.Header().Set(HeaderContentType, MIMETextPlainCharsetUTF8)
	c.response.WriteHeader(code)
	_, err = c.response.Write([]byte(s))
	return
}

// JSON sends a JSON response with status code.
func (c *xContext) JSON(code int, i interface{}) (err error) {
	var b []byte
	if c.echo.Debug() {
		b, err = json.MarshalIndent(i, "", "  ")
	} else {
		b, err = json.Marshal(i)
	}
	if err != nil {
		return err
	}
	return c.JSONBlob(code, b)
}

// JSONBlob sends a JSON blob response with status code.
func (c *xContext) JSONBlob(code int, b []byte) (err error) {
	c.response.Header().Set(HeaderContentType, MIMEApplicationJSONCharsetUTF8)
	c.response.WriteHeader(code)
	_, err = c.response.Write(b)
	return
}

// JSONP sends a JSONP response with status code. It uses `callback` to construct
// the JSONP payload.
func (c *xContext) JSONP(code int, callback string, i interface{}) (err error) {
	b, err := json.Marshal(i)
	if err != nil {
		return err
	}
	c.response.Header().Set(HeaderContentType, MIMEApplicationJavaScriptCharsetUTF8)
	c.response.WriteHeader(code)

	if _, err = c.response.Write([]byte(callback + "(")); err != nil {
		return
	}
	if _, err = c.response.Write(b); err != nil {
		return
	}
	_, err = c.response.Write([]byte(");"))
	return
}

// XML sends an XML response with status code.
func (c *xContext) XML(code int, i interface{}) (err error) {
	var b []byte
	if c.echo.Debug() {
		b, err = xml.MarshalIndent(i, "", "  ")
	} else {
		b, err = xml.Marshal(i)
	}
	if err != nil {
		return err
	}
	return c.XMLBlob(code, b)
}

// XMLBlob sends a XML blob response with status code.
func (c *xContext) XMLBlob(code int, b []byte) (err error) {
	c.response.Header().Set(HeaderContentType, MIMEApplicationXMLCharsetUTF8)
	c.response.WriteHeader(code)
	if _, err = c.response.Write([]byte(xml.Header)); err != nil {
		return
	}
	_, err = c.response.Write(b)
	return
}

func (c *xContext) File(file string) error {
	f, err := os.Open(file)
	if err != nil {
		return ErrNotFound
	}
	defer f.Close()

	fi, _ := f.Stat()
	if fi.IsDir() {
		file = filepath.Join(file, "index.html")
		f, err = os.Open(file)
		if err != nil {
			return ErrNotFound
		}
		fi, _ = f.Stat()
	}
	return c.ServeContent(f, fi.Name(), fi.ModTime())
}

func (c *xContext) Attachment(r io.ReadSeeker, name string) (err error) {
	c.response.Header().Set(HeaderContentType, ContentTypeByExtension(name))
	c.response.Header().Set(HeaderContentDisposition, "attachment; filename="+name)
	c.response.WriteHeader(http.StatusOK)
	_, err = io.Copy(c.response, r)
	return
}

// NoContent sends a response with no body and a status code.
func (c *xContext) NoContent(code int) error {
	c.response.WriteHeader(code)
	return nil
}

// Redirect redirects the request with status code.
func (c *xContext) Redirect(code int, url string) error {
	if code < http.StatusMultipleChoices || code > http.StatusTemporaryRedirect {
		return ErrInvalidRedirectCode
	}
	c.response.Redirect(url, code)
	return nil
}

// Error invokes the registered HTTP error handler. Generally used by middleware.
func (c *xContext) Error(err error) {
	c.echo.httpErrorHandler(err, c)
}

// Logger returns the `Logger` instance.
func (c *xContext) Logger() logger.Logger {
	return c.echo.logger
}

// Object returns the `context` object.
func (c *xContext) Object() *xContext {
	return c
}

func (c *xContext) ServeContent(content io.ReadSeeker, name string, modtime time.Time) error {
	rq := c.Request()
	rs := c.Response()

	if t, err := time.Parse(http.TimeFormat, rq.Header().Get(HeaderIfModifiedSince)); err == nil && modtime.Before(t.Add(1*time.Second)) {
		rs.Header().Del(HeaderContentType)
		rs.Header().Del(HeaderContentLength)
		return c.NoContent(http.StatusNotModified)
	}

	rs.Header().Set(HeaderContentType, ContentTypeByExtension(name))
	rs.Header().Set(HeaderLastModified, modtime.UTC().Format(http.TimeFormat))
	rs.WriteHeader(http.StatusOK)
	_, err := io.Copy(rs, content)
	return err
}

// ContentTypeByExtension returns the MIME type associated with the file based on
// its extension. It returns `application/octet-stream` incase MIME type is not
// found.
func ContentTypeByExtension(name string) (t string) {
	if t = mime.TypeByExtension(filepath.Ext(name)); t == "" {
		t = MIMEOctetStream
	}
	return
}

// Echo returns the `Echo` instance.
func (c *xContext) Echo() *Echo {
	return c.echo
}

func (c *xContext) Reset(req engine.Request, res engine.Response) {
	c.context = context.Background()
	c.request = req
	c.response = res
	c.store = nil
	c.funcs = make(map[string]interface{})
	c.renderer = nil
	c.handler = notFoundHandler
}

func (c *xContext) GetFunc(key string) interface{} {
	return c.funcs[key]
}

func (c *xContext) SetFunc(key string, val interface{}) {
	c.funcs[key] = val
}

func (c *xContext) ResetFuncs(funcs map[string]interface{}) {
	c.funcs = funcs
}

func (c *xContext) Funcs() map[string]interface{} {
	return c.funcs
}

func (c *xContext) Fetch(name string, data interface{}) (b []byte, err error) {
	if c.renderer == nil {
		if c.echo.renderer == nil {
			return nil, ErrRendererNotRegistered
		}
		c.renderer = c.echo.renderer
	}
	buf := new(bytes.Buffer)
	err = c.renderer.Render(buf, name, data, c)
	if err != nil {
		return
	}
	b = buf.Bytes()
	return
}

// SetRenderer registers an HTML template renderer.
func (c *xContext) SetRenderer(r Renderer) {
	c.renderer = r
}
<|endoftext|>