<commit_before>package slinga

import (
	"bytes"
	"errors"
	"github.com/golang/glog"
	"strings"
	"text/template"
)

/*
	Core engine for Slinga processing and evaluation
*/

// ResolveUsage evaluates all recorded Dependencies ("<user> needs <service> with <labels>") and calculates allocations
func (usage *ServiceUsageState) ResolveUsage(users *GlobalUsers) error {
	for serviceName, dependencies := range usage.Dependencies.Dependencies {
		for _, d := range dependencies {
			user := users.Users[d.UserID]

			// take user labels
			labels := user.getLabelSet()

			// combine them with dependency labels
			labels = labels.addLabels(d.getLabelSet())

			// resolve usage via applying policy
			resKey, err := usage.resolveWithLabels(user, serviceName, labels, usage.ComponentInstanceMap, d.Trace, 0)
			if err != nil {
				return err
			}
			d.ResolvesTo = resKey
		}
	}
	return nil
}

// Evaluate "<user> needs <service>" statement
func (usage *ServiceUsageState) resolveWithLabels(user User, serviceName string, labels LabelSet, cim map[string]interface{}, trace bool, depth int) (string, error) {

	// Resolving allocations for service
	glog.Infof("Resolving allocations for service %s (user = %s, labels = %s)", serviceName, user.Name, labels)

	usage.tracing.do(trace).log(depth, "[Dependency]")
	usage.tracing.do(trace).log(depth, "User: %s (ID = %s)", user.Name, user.ID)
	usage.tracing.do(trace).log(depth+1, "Labels: %s", labels)
	usage.tracing.do(trace).log(depth, "Service: %s", serviceName)

	// Policy
	policy := usage.Policy

	// Locate the service
	service, err := policy.getService(serviceName)
	if err != nil {
		usage.tracing.do(trace).log(depth, "Error while trying to look up service %s (%v)", serviceName, err)
		return "", err
	}

	// Process service and transform labels
	labels = labels.applyTransform(service.Labels)
	usage.tracing.do(trace).log(depth+1, "New labels = %s", labels)

	// Match the context
	context, err := policy.getMatchedContext(*service, user, labels, depth, usage.tracing.do(trace))
	if err != nil {
		usage.tracing.do(trace).log(depth, "Error while matching context for service %s (%v)", serviceName, err)
		return "", err
	}
	// If no matching context is found, let's just exit
	if context == nil {
		usage.tracing.do(trace).log(depth, "No context matched for service %s", serviceName)
		return "", nil
	}

	// Process context and transform labels
	labels = labels.applyTransform(context.Labels)
	usage.tracing.do(trace).log(depth, "Context: %s", context.Name)
	usage.tracing.do(trace).log(depth+1, "New labels = %s", labels)

	// Match the allocation
	allocation, err := policy.getMatchedAllocation(*service, user, *context, labels, depth, usage.tracing.do(trace))
	if err != nil {
		usage.tracing.do(trace).log(depth, "Error while matching allocation for service %s, context %s (%v)", serviceName, context.Name, err)
		return "", err
	}
	// If no matching allocation is found, let's just exit
	if allocation == nil {
		usage.tracing.do(trace).log(depth, "No allocation matched for service %s, context %s", serviceName, context.Name)
		return "", nil
	}

	// Process allocation and transform labels
	labels = labels.applyTransform(allocation.Labels)
	usage.tracing.do(trace).log(depth, "Allocation: %s", allocation.NameResolved)
	usage.tracing.do(trace).log(depth+1, "New labels = %s", labels)

	// Now, sort all components in topological order
	componentsOrdered, err := service.getComponentsSortedTopologically()
	if err != nil {
		return "", err
	}

	// Resolve every component
	for _, component := range componentsOrdered {
		// Process component and transform labels
		componentLabels := labels.applyTransform(component.Labels)

		// Is it a code?
		var codeParams interface{}
		if component.Code != nil {
			// Evaluate code params
			glog.Infof("Processing dependency on code execution: %s (in %s)", component.Name, service.Name)
			codeParams, err = component.processCodeParams(componentLabels, user, cim, depth, usage.tracing.do(trace))
			if err != nil {
				return "", err
			}

		} else if component.Service != "" {
			glog.Infof("Processing dependency on another service: %s -> %s (in %s)", component.Name, component.Service, service.Name)
			usage.tracing.do(trace).newline()

			// Create new map with resolution keys for component
			cimComponent := make(map[string]interface{})
			cim[component.Name] = cimComponent

			_, err := usage.resolveWithLabels(user, component.Service, componentLabels, cimComponent, trace, depth+1)
			if err != nil {
				return "", err
			}
		} else {
			glog.Fatalf("Invalid component: %s (in %s)", component.Name, service.Name)
		}

		// Record usage of a given component
		componentKey := usage.recordUsage(user, service, context, allocation, component, componentLabels, codeParams)

		// Record component key in cim, if it's code
		if component.Code != nil {
			cim[component.Name] = componentKey
		}
	}

	// Record usage of a given service
	usage.recordUsage(user, service, context, allocation, nil, labels, nil)

	return context.Name + "#" + allocation.NameResolved, nil
}

// Topologically sort components and return true if there is a cycle detected
func (service *Service) dfsComponentSort(u *ServiceComponent, colors map[string]int) bool {
	colors[u.Name] = 1

	for _, vName := range u.Dependencies {
		v, exists := service.getComponentsMap()[vName]
		if !exists {
			glog.Fatalf("Invalid dependency in service %s: %s", service.Name, vName)
		}
		if vColor, ok := colors[v.Name]; !ok {
			// not visited yet -> visit and exit if a cycle was found
			if service.dfsComponentSort(v, colors) {
				return true
			}
		} else if vColor == 1 {
			return true
		}
	}

	service.componentsOrdered = append(service.componentsOrdered, u)
	colors[u.Name] = 2
	return false
}

// Sorts all components in a topological way
func (service *Service) getComponentsSortedTopologically() ([]*ServiceComponent, error) {
	if service.componentsOrdered == nil {
		// Initiate colors
		colors := make(map[string]int)

		// Dfs
		var cycle = false
		for _, c := range service.Components {
			if _, ok := colors[c.Name]; !ok {
				if service.dfsComponentSort(c, colors) {
					cycle = true
					break
				}
			}
		}

		if cycle {
			return nil, errors.New("Component cycle detected in service " + service.Name)
		}
	}

	return service.componentsOrdered, nil
}

// Helper to get a service
func (policy *Policy) getService(serviceName string) (*Service, error) {
	// Locate the service
	service := policy.Services[serviceName]
	if service == nil {
		return nil, errors.New("Service " + serviceName + " not found")
	}
	return service, nil
}

// Helper to get a matched context
func (policy *Policy) getMatchedContext(service Service, user User, labels LabelSet, depth int, tracing *ServiceUsageTracing) (*Context, error) {
	// Locate the list of contexts for service
	contexts, ok := policy.Contexts[service.Name]
	if !ok || len(contexts) <= 0 {
		tracing.log(depth+1, "No contexts found")
		return nil, errors.New("No contexts found for " + service.Name)
	}

	// See which context matches
	var contextMatched *Context
	for _, c := range contexts {
		m := c.matches(labels)
		tracing.log(depth+1, "[%t] Testing context '%s': %s", m, c.Name, c.Criteria)
		if m {
			contextMatched = c
			break
		}
	}

	if contextMatched != nil {
		glog.Infof("Matched context: '%s' (service = %s, user = %s)", contextMatched.Name, service.Name, user.Name)
	} else {
		glog.Infof("No context matched (service = %s, user = %s)", service.Name, user.Name)
	}
	return contextMatched, nil
}

// Helper to get a matched allocation
func (policy *Policy) getMatchedAllocation(service Service, user User, context Context, labels LabelSet, depth int, tracing *ServiceUsageTracing) (*Allocation, error) {
	if len(context.Allocations) <= 0 {
		tracing.log(depth+1, "No allocations found")
		return nil, errors.New("No allocations found for " + service.Name)
	}

	// See which allocation matches
	var allocationMatched *Allocation
	for _, a := range context.Allocations {
		m := a.matches(labels)
		tracing.log(depth+1, "[%t] Testing allocation '%s': %s", m, a.Name, a.Criteria)
		if m {
			allocationMatched = a
			break
		}
	}

	// Check errors and resolve allocation name (it can be dynamic, depending on user labels)
	if allocationMatched != nil {
		err := allocationMatched.resolveName(user)
		if err != nil {
			glog.Infof("Cannot resolve name for an allocation: '%s' (context = %s, service = %s, user = %s)", allocationMatched.Name, context.Name, service.Name, user.Name)
			return nil, nil
		}
		glog.Infof("Matched allocation: '%s' -> '%s' (context = %s, service = %s, user = %s)", allocationMatched.Name, allocationMatched.NameResolved, context.Name, service.Name, user.Name)
	} else {
		glog.Infof("No allocation matched (context = %s, service = %s, user = %s)", context.Name, service.Name, user.Name)
	}

	return allocationMatched, nil
}

type ProcessingError struct {
	Reason string
}

func (err ProcessingError) Error() string {
	return err.Reason
}

func (component *ServiceComponent) processCodeParams(labels LabelSet, user User, cim map[string]interface{}, depth int, tracing *ServiceUsageTracing) (interface{}, error) {
	tracing.log(depth+1, "Component: %s (code)", component.Name)

	var evalParamsInterface func(params interface{}) (interface{}, error)
	evalParamsInterface = func(params interface{}) (interface{}, error) {
		if params == nil {
			return "", nil
		} else if paramsMap, ok := params.(map[interface{}]interface{}); ok {
			resultMap := make(map[interface{}]interface{})

			for key, value := range paramsMap {
				evaluatedValue, err := evalParamsInterface(value)
				if err != nil {
					return nil, err
				}
				resultMap[key] = evaluatedValue
			}

			return resultMap, nil
		} else if paramsStr, ok := params.(string); ok {
			evaluatedValue, err := evaluateCodeParamTemplate(paramsStr, labels, user, cim)
			tracing.log(depth+2, "Parameter '%s': %s", paramsStr, evaluatedValue)
			if err != nil {
				return nil, err
			}
			return evaluatedValue, nil
		} else if paramsInt, ok := params.(int); ok {
			return paramsInt, nil
		} else if paramsBool, ok := params.(bool); ok {
			return paramsBool, nil
		}

		return nil, ProcessingError{"There should be map[string]interface{} or string"}
	}

	return evalParamsInterface(component.Code.Params)
}

func evaluateCodeParamTemplate(templateStr string, labels LabelSet, user User, cim map[string]interface{}) (string, error) {
	type Parameters struct {
		Labels     map[string]string
		User       User
		Components map[string]interface{}
	}
	param := Parameters{
		Labels:     labels.Labels,
		Components: cim,
		User:       user}

	tmpl, err := template.New("").Parse(templateStr)
	if err != nil {
		return "", errors.New("Invalid template " + templateStr)
	}

	var doc bytes.Buffer
	err = tmpl.Execute(&doc, param)

	if err != nil {
		return "", errors.New("Cannot evaluate template " + templateStr)
	}

	result := doc.String()
	if strings.Contains(result, "<no value>") {
		return "", errors.New("Cannot evaluate template " + templateStr)
	}

	// TODO: remove this ugly shit later (should not reference Helm in generic engine)
	return HelmName(doc.String()), nil
}
<commit_msg>Add component instance key to the code params evaluation context<commit_after>package slinga

import (
	"bytes"
	"errors"
	"github.com/golang/glog"
	"strings"
	"text/template"
)

/*
	Core engine for Slinga processing and evaluation
*/

// ResolveUsage evaluates all recorded Dependencies ("<user> needs <service> with <labels>") and calculates allocations
func (usage *ServiceUsageState) ResolveUsage(users *GlobalUsers) error {
	for serviceName, dependencies := range usage.Dependencies.Dependencies {
		for _, d := range dependencies {
			user := users.Users[d.UserID]

			// take user labels
			labels := user.getLabelSet()

			// combine them with dependency labels
			labels = labels.addLabels(d.getLabelSet())

			// resolve usage via applying policy
			resKey, err := usage.resolveWithLabels(user, serviceName, labels, usage.ComponentInstanceMap, d.Trace, 0)
			if err != nil {
				return err
			}
			d.ResolvesTo = resKey
		}
	}
	return nil
}

// Evaluate "<user> needs <service>" statement
func (usage *ServiceUsageState) resolveWithLabels(user User, serviceName string, labels LabelSet, cim map[string]interface{}, trace bool, depth int) (string, error) {

	// Resolving allocations for service
	glog.Infof("Resolving allocations for service %s (user = %s, labels = %s)", serviceName, user.Name, labels)

	usage.tracing.do(trace).log(depth, "[Dependency]")
	usage.tracing.do(trace).log(depth, "User: %s (ID = %s)", user.Name, user.ID)
	usage.tracing.do(trace).log(depth+1, "Labels: %s", labels)
	usage.tracing.do(trace).log(depth, "Service: %s", serviceName)

	// Policy
	policy := usage.Policy

	// Locate the service
	service, err := policy.getService(serviceName)
	if err != nil {
		usage.tracing.do(trace).log(depth, "Error while trying to look up service %s (%v)", serviceName, err)
		return "", err
	}

	// Process service and transform labels
	labels = labels.applyTransform(service.Labels)
	usage.tracing.do(trace).log(depth+1, "New labels = %s", labels)

	// Match the context
	context, err := policy.getMatchedContext(*service, user, labels, depth, usage.tracing.do(trace))
	if err != nil {
		usage.tracing.do(trace).log(depth, "Error while matching context for service %s (%v)", serviceName, err)
		return "", err
	}
	// If no matching context is found, let's just exit
	if context == nil {
		usage.tracing.do(trace).log(depth, "No context matched for service %s", serviceName)
		return "", nil
	}

	// Process context and transform labels
	labels = labels.applyTransform(context.Labels)
	usage.tracing.do(trace).log(depth, "Context: %s", context.Name)
	usage.tracing.do(trace).log(depth+1, "New labels = %s", labels)

	// Match the allocation
	allocation, err := policy.getMatchedAllocation(*service, user, *context, labels, depth, usage.tracing.do(trace))
	if err != nil {
		usage.tracing.do(trace).log(depth, "Error while matching allocation for service %s, context %s (%v)", serviceName, context.Name, err)
		return "", err
	}
	// If no matching allocation is found, let's just exit
	if allocation == nil {
		usage.tracing.do(trace).log(depth, "No allocation matched for service %s, context %s", serviceName, context.Name)
		return "", nil
	}

	// Process allocation and transform labels
	labels = labels.applyTransform(allocation.Labels)
	usage.tracing.do(trace).log(depth, "Allocation: %s", allocation.NameResolved)
	usage.tracing.do(trace).log(depth+1, "New labels = %s", labels)

	// Now, sort all components in topological order
	componentsOrdered, err := service.getComponentsSortedTopologically()
	if err != nil {
		return "", err
	}

	// Resolve every component
	for _, component := range componentsOrdered {
		// Process component and transform labels
		componentLabels := labels.applyTransform(component.Labels)

		// Is it a code?
		var codeParams interface{}
		if component.Code != nil {
			// Evaluate code params
			glog.Infof("Processing dependency on code execution: %s (in %s)", component.Name, service.Name)
			componentKey := usage.createServiceUsageKey(service, context, allocation, component)
			codeParams, err = component.processCodeParams(componentKey, componentLabels, user, cim, depth, usage.tracing.do(trace))
			if err != nil {
				return "", err
			}

		} else if component.Service != "" {
			glog.Infof("Processing dependency on another service: %s -> %s (in %s)", component.Name, component.Service, service.Name)
			usage.tracing.do(trace).newline()

			// Create new map with resolution keys for component
			cimComponent := make(map[string]interface{})
			cim[component.Name] = cimComponent

			_, err := usage.resolveWithLabels(user, component.Service, componentLabels, cimComponent, trace, depth+1)
			if err != nil {
				return "", err
			}
		} else {
			glog.Fatalf("Invalid component: %s (in %s)", component.Name, service.Name)
		}

		// Record usage of a given component
		componentKey := usage.recordUsage(user, service, context, allocation, component, componentLabels, codeParams)

		// Record component key in cim, if it's code
		if component.Code != nil {
			cim[component.Name] = componentKey
		}
	}

	// Record usage of a given service
	usage.recordUsage(user, service, context, allocation, nil, labels, nil)

	return context.Name + "#" + allocation.NameResolved, nil
}

// Topologically sort components and return true if there is a cycle detected
func (service *Service) dfsComponentSort(u *ServiceComponent, colors map[string]int) bool {
	colors[u.Name] = 1

	for _, vName := range u.Dependencies {
		v, exists := service.getComponentsMap()[vName]
		if !exists {
			glog.Fatalf("Invalid dependency in service %s: %s", service.Name, vName)
		}
		if vColor, ok := colors[v.Name]; !ok {
			// not visited yet -> visit and exit if a cycle was found
			if service.dfsComponentSort(v, colors) {
				return true
			}
		} else if vColor == 1 {
			return true
		}
	}

	service.componentsOrdered = append(service.componentsOrdered, u)
	colors[u.Name] = 2
	return false
}

// Sorts all components in a topological way
func (service *Service) getComponentsSortedTopologically() ([]*ServiceComponent, error) {
	if service.componentsOrdered == nil {
		// Initiate colors
		colors := make(map[string]int)

		// Dfs
		var cycle = false
		for _, c := range service.Components {
			if _, ok := colors[c.Name]; !ok {
				if service.dfsComponentSort(c, colors) {
					cycle = true
					break
				}
			}
		}

		if cycle {
			return nil, errors.New("Component cycle detected in service " + service.Name)
		}
	}

	return service.componentsOrdered, nil
}

// Helper to get a service
func (policy *Policy) getService(serviceName string) (*Service, error) {
	// Locate the service
	service := policy.Services[serviceName]
	if service == nil {
		return nil, errors.New("Service " + serviceName + " not found")
	}
	return service, nil
}

// Helper to get a matched context
func (policy *Policy) getMatchedContext(service Service, user User, labels LabelSet, depth int, tracing *ServiceUsageTracing) (*Context, error) {
	// Locate the list of contexts for service
	contexts, ok := policy.Contexts[service.Name]
	if !ok || len(contexts) <= 0 {
		tracing.log(depth+1, "No contexts found")
		return nil, errors.New("No contexts found for " + service.Name)
	}

	// See which context matches
	var contextMatched *Context
	for _, c := range contexts {
		m := c.matches(labels)
		tracing.log(depth+1, "[%t] Testing context '%s': %s", m, c.Name, c.Criteria)
		if m {
			contextMatched = c
			break
		}
	}

	if contextMatched != nil {
		glog.Infof("Matched context: '%s' (service = %s, user = %s)", contextMatched.Name, service.Name, user.Name)
	} else {
		glog.Infof("No context matched (service = %s, user = %s)", service.Name, user.Name)
	}
	return contextMatched, nil
}

// Helper to get a matched allocation
func (policy *Policy) getMatchedAllocation(service Service, user User, context Context, labels LabelSet, depth int, tracing *ServiceUsageTracing) (*Allocation, error) {
	if len(context.Allocations) <= 0 {
		tracing.log(depth+1, "No allocations found")
		return nil, errors.New("No allocations found for " + service.Name)
	}

	// See which allocation matches
	var allocationMatched *Allocation
	for _, a := range context.Allocations {
		m := a.matches(labels)
		tracing.log(depth+1, "[%t] Testing allocation '%s': %s", m, a.Name, a.Criteria)
		if m {
			allocationMatched = a
			break
		}
	}

	// Check errors and resolve allocation name (it can be dynamic, depending on user labels)
	if allocationMatched != nil {
		err := allocationMatched.resolveName(user)
		if err != nil {
			glog.Infof("Cannot resolve name for an allocation: '%s' (context = %s, service = %s, user = %s)", allocationMatched.Name, context.Name, service.Name, user.Name)
			return nil, nil
		}
		glog.Infof("Matched allocation: '%s' -> '%s' (context = %s, service = %s, user = %s)", allocationMatched.Name, allocationMatched.NameResolved, context.Name, service.Name, user.Name)
	} else {
		glog.Infof("No allocation matched (context = %s, service = %s, user = %s)", context.Name, service.Name, user.Name)
	}

	return allocationMatched, nil
}

type ProcessingError struct {
	Reason string
}

func (err ProcessingError) Error() string {
	return err.Reason
}

func (component *ServiceComponent) processCodeParams(componentKey string, labels LabelSet, user User, cim map[string]interface{}, depth int, tracing *ServiceUsageTracing) (interface{}, error) {
	tracing.log(depth+1, "Component: %s (code)", component.Name)

	var evalParamsInterface func(params interface{}) (interface{}, error)
	evalParamsInterface = func(params interface{}) (interface{}, error) {
		if params == nil {
			return "", nil
		} else if paramsMap, ok := params.(map[interface{}]interface{}); ok {
			resultMap := make(map[interface{}]interface{})

			for key, value := range paramsMap {
				evaluatedValue, err := evalParamsInterface(value)
				if err != nil {
					return nil, err
				}
				resultMap[key] = evaluatedValue
			}

			return resultMap, nil
		} else if paramsStr, ok := params.(string); ok {
			evaluatedValue, err := evaluateCodeParamTemplate(componentKey, paramsStr, labels, user, cim)
			tracing.log(depth+2, "Parameter '%s': %s", paramsStr, evaluatedValue)
			if err != nil {
				return nil, err
			}
			return evaluatedValue, nil
		} else if paramsInt, ok := params.(int); ok {
			return paramsInt, nil
		} else if paramsBool, ok := params.(bool); ok {
			return paramsBool, nil
		}

		return nil, ProcessingError{"There should be map[string]interface{} or string"}
	}

	return evalParamsInterface(component.Code.Params)
}

func evaluateCodeParamTemplate(componentKey string, templateStr string, labels LabelSet, user User, cim map[string]interface{}) (string, error) {
	type Parameters struct {
		ComponentInstance   string
		Labels     map[string]string
		User       User
		Components map[string]interface{}
	}
	param := Parameters{
		ComponentInstance: componentKey,
		Labels:     labels.Labels,
		Components: cim,
		User:       user}

	tmpl, err := template.New("").Parse(templateStr)
	if err != nil {
		return "", errors.New("Invalid template " + templateStr)
	}

	var doc bytes.Buffer
	err = tmpl.Execute(&doc, param)

	if err != nil {
		return "", errors.New("Cannot evaluate template " + templateStr)
	}

	result := doc.String()
	if strings.Contains(result, "<no value>") {
		return "", errors.New("Cannot evaluate template " + templateStr)
	}

	// TODO: remove this ugly shit later (should not reference Helm in generic engine)
	return HelmName(doc.String()), nil
}
<|endoftext|>


<commit_before>package sync

import (
	"github.com/pkg/errors"
)

// EnsureValid ensures that Conflict's invariants are respected.
func (c *Conflict) EnsureValid() error {
	// A nil conflict is not valid.
	if c == nil {
		return errors.New("nil conflict")
	}

	// Each side's changes must be non-empty and must all be valid.
	if len(c.AlphaChanges) == 0 {
		return errors.New("conflict has no changes to alpha")
	} else {
		for _, change := range c.AlphaChanges {
			if err := change.EnsureValid(); err != nil {
				return errors.Wrap(err, "invalid alpha change detected")
			}
		}
	}
	if len(c.BetaChanges) == 0 {
		return errors.New("conflict has no changes to beta")
	} else {
		for _, change := range c.BetaChanges {
			if err := change.EnsureValid(); err != nil {
				return errors.Wrap(err, "invalid beta change detected")
			}
		}
	}

	// There's technically a bit more validation we could do to ensure that each
	// side uses a given path only once and that all of the paths on one side
	// are subpaths of the other (or that both sides name the same path), but
	// that becomes very complicated and expensive, and it isn't really needed
	// for memory safety.

	// Success.
	return nil
}
<commit_msg>Added additional Conflict invariant check.<commit_after>package sync

import (
	"github.com/pkg/errors"
)

// EnsureValid ensures that Conflict's invariants are respected.
func (c *Conflict) EnsureValid() error {
	// A nil conflict is not valid.
	if c == nil {
		return errors.New("nil conflict")
	}

	// Each side's changes must be non-empty and must all be valid.
	if len(c.AlphaChanges) == 0 {
		return errors.New("conflict has no changes to alpha")
	} else {
		for _, change := range c.AlphaChanges {
			if err := change.EnsureValid(); err != nil {
				return errors.Wrap(err, "invalid alpha change detected")
			}
		}
	}
	if len(c.BetaChanges) == 0 {
		return errors.New("conflict has no changes to beta")
	} else {
		for _, change := range c.BetaChanges {
			if err := change.EnsureValid(); err != nil {
				return errors.Wrap(err, "invalid beta change detected")
			}
		}
	}

	// Ensure that at least one side has exactly one conflict. We know this must
	// be the case because at least one of the sides must have a change at the
	// root of the conflict.
	if len(c.AlphaChanges) != 1 && len(c.BetaChanges) != 1 {
		return errors.New("both sides of conflict have zero or multiple changes")
	}

	// There's technically a bit more validation we could do, e.g. ensuring that
	// each side uses a given path only once and that all of the paths on one of
	// the sides are subpaths of the single path on the other side (or that both
	// sides name the same path), but that becomes very complicated and
	// expensive, and it isn't really needed for memory safety purposes.

	// Success.
	return nil
}
<|endoftext|>


<commit_before>package main

import "fmt"

func main() {
	// 长度也是数组类型的一部分，因此[3]int与[10]int是不同的类型，数组也就不能改变长度。
	// 数组之间的赋值是值的赋值，即当把一个数组作为参数传入函数的时候，传入的其实是该数组的副本，而不是它的指针。
	// 如果要使用指针，那么就需要用到slice类型了。
	a := [3]int{1, 2, 3} // 声明了一个长度为3的int数组

	b := [10]int{1, 2, 3} // 声明了一个长度为10的int数组，其中前三个元素初始化为1、2、3，其它默认为0

	c := [...]int{4, 5, 6} // 可以省略长度而采用`...`的方式，Go会自动根据元素个数来计算长度

	fmt.Println(a)
	fmt.Println(b)
	fmt.Println(c)

	// 二维数组
	// 声明了一个二维数组，该数组以两个数组作为元素，其中每个数组中又有4个int类型的元素
	doubleArray := [2][4]int{[4]int{1, 2, 3, 4}, [4]int{5, 6, 7, 8}}

	// 上面的声明可以简化，直接忽略内部的类型
	easyArray := [2][4]int{{1, 2, 3, 4}, {5, 6, 7, 8}}

	fmt.Println(doubleArray)
	fmt.Println(easyArray)

	// 动态数组 Slice
	// slice并不是真正意义上的动态数组，而是一个引用类型。slice总是指向一个底层array，slice的声明也可以像array一样，只是不需要长度。
	slice := []byte {'a', 'b', 'c', 'd'} // 和声明array一样，只是少了长度
	fmt.Println(slice)
}
<commit_msg>array, 9968<commit_after>package main

import "fmt"

func main() {
	// 长度也是数组类型的一部分，因此[3]int与[10]int是不同的类型，数组也就不能改变长度。
	// 数组之间的赋值是值的赋值，即当把一个数组作为参数传入函数的时候，传入的其实是该数组的副本，而不是它的指针。
	// 如果要使用指针，那么就需要用到slice类型了。
	a := [3]int{1, 2, 3} // 声明了一个长度为3的int数组

	b := [10]int{1, 2, 3} // 声明了一个长度为10的int数组，其中前三个元素初始化为1、2、3，其它默认为0

	c := [...]int{4, 5, 6} // 可以省略长度而采用`...`的方式，Go会自动根据元素个数来计算长度

	fmt.Println(a)
	fmt.Println(b)
	fmt.Println(c)

	// 指定位置
	d := [3]int{2:1}
	fmt.Println(d)

	// 二维数组
	// 声明了一个二维数组，该数组以两个数组作为元素，其中每个数组中又有4个int类型的元素
	doubleArray := [2][4]int{[4]int{1, 2, 3, 4}, [4]int{5, 6, 7, 8}}

	// 上面的声明可以简化，直接忽略内部的类型
	easyArray := [2][4]int{{1, 2, 3, 4}, {5, 6, 7, 8}}

	fmt.Println(doubleArray)
	fmt.Println(easyArray)

	// 动态数组 Slice
	// slice并不是真正意义上的动态数组，而是一个引用类型。slice总是指向一个底层array，slice的声明也可以像array一样，只是不需要长度。
	slice := []byte {'a', 'b', 'c', 'd'} // 和声明array一样，只是少了长度
	fmt.Println(slice)
}
<|endoftext|>


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

package auth

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha1"
	"encoding/base64"
	"errors"
	"github.com/jacobsa/aws"
	"github.com/jacobsa/aws/s3/http"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
	"testing"
)

func TestSigner(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

type SignerTest struct {}

func init() { RegisterTestSuite(&SignerTest{}) }

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *SignerTest) CallsFunction() {
	// Function
	var stsArg *http.Request
	sts := func(r *http.Request)(string, error) { stsArg = r; return "", nil }

	// Signer
	signer, err := newSigner(sts, aws.AccessKey{})
	AssertEq(nil, err)

	// Call
	req := &http.Request{}
	signer.Sign(req)

	ExpectEq(req, stsArg)
}

func (t *SignerTest) FunctionReturnsError() {
	// Function
	sts := func(r *http.Request)(string, error) { return "", errors.New("taco") }

	// Signer
	signer, err := newSigner(sts, aws.AccessKey{})
	AssertEq(nil, err)

	// Call
	err = signer.Sign(&http.Request{})

	ExpectThat(err, Error(HasSubstr("Sign")))
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *SignerTest) FunctionReturnsString() {
	// Function
	sts := func(r *http.Request)(string, error) { return "taco", nil }

	// Signer
	key := aws.AccessKey{Secret: "burrito"}
	signer, err := newSigner(sts, key)
	AssertEq(nil, err)

	// Expected output
	h := hmac.New(sha1.New, []byte("burrito"))
	_, err = h.Write([]byte("taco"))
	AssertEq(nil, err)

	buf := new(bytes.Buffer)
	encoder := base64.NewEncoder(base64.StdEncoding, buf)
	_, err = encoder.Write(h.Sum(nil))
	AssertEq(nil, err)
	AssertEq(nil, encoder.Close())

	expected := buf.String()

	// Call
	req := &http.Request{
		Headers: map[string]string {
			"foo": "bar",
		},
	}

	err = signer.Sign(req)
	AssertEq(nil, err)

	ExpectEq("bar", req.Headers["foo"])
	ExpectEq(expected, req.Headers["Authorization"])
}

func (t *SignerTest) GoldenTests() {
	ExpectEq("TODO", "")
}
<commit_msg>SignerTest.GoldenTests<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package auth

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha1"
	"encoding/base64"
	"errors"
	"github.com/jacobsa/aws"
	"github.com/jacobsa/aws/s3/http"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
	"testing"
)

func TestSigner(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

type SignerTest struct {}

func init() { RegisterTestSuite(&SignerTest{}) }

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *SignerTest) CallsFunction() {
	// Function
	var stsArg *http.Request
	sts := func(r *http.Request)(string, error) { stsArg = r; return "", nil }

	// Signer
	signer, err := newSigner(sts, aws.AccessKey{})
	AssertEq(nil, err)

	// Call
	req := &http.Request{}
	signer.Sign(req)

	ExpectEq(req, stsArg)
}

func (t *SignerTest) FunctionReturnsError() {
	// Function
	sts := func(r *http.Request)(string, error) { return "", errors.New("taco") }

	// Signer
	signer, err := newSigner(sts, aws.AccessKey{})
	AssertEq(nil, err)

	// Call
	err = signer.Sign(&http.Request{})

	ExpectThat(err, Error(HasSubstr("Sign")))
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *SignerTest) FunctionReturnsString() {
	// Function
	sts := func(r *http.Request)(string, error) { return "taco", nil }

	// Signer
	key := aws.AccessKey{Id: "queso", Secret: "burrito"}
	signer, err := newSigner(sts, key)
	AssertEq(nil, err)

	// Expected output
	h := hmac.New(sha1.New, []byte("burrito"))
	_, err = h.Write([]byte("taco"))
	AssertEq(nil, err)

	buf := new(bytes.Buffer)
	encoder := base64.NewEncoder(base64.StdEncoding, buf)
	_, err = encoder.Write(h.Sum(nil))
	AssertEq(nil, err)
	AssertEq(nil, encoder.Close())

	expected := "AWS queso:" + buf.String()

	// Call
	req := &http.Request{
		Headers: map[string]string {
			"foo": "bar",
		},
	}

	err = signer.Sign(req)
	AssertEq(nil, err)

	ExpectEq("bar", req.Headers["foo"])
	ExpectEq(expected, req.Headers["Authorization"])
}

func (t *SignerTest) GoldenTests() {
	type testCase struct {
		stringToSign string
		expectedHeaderValue string
	}

	// Golden tests taken from Amazon doc examples.
	key := aws.AccessKey{
		Id: "AKIAIOSFODNN7EXAMPLE",
		Secret: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
	}

	cases := []testCase{
		testCase{
			"GET\n\n\nTue, 27 Mar 2007 19:36:42 +0000\n/johnsmith/photos/puppy.jpg",
			"AWS AKIAIOSFODNN7EXAMPLE:bWq2s1WEIj+Ydj0vQ697zp+IXMU=",
		},
		testCase{
			"PUT\n\nimage/jpeg\nTue, 27 Mar 2007 21:15:45 +0000\n/johnsmith/photos/puppy.jpg",
			"AWS AKIAIOSFODNN7EXAMPLE:MyyxeRY7whkBe+bq8fHCL/2kKUg=",
		},
		testCase{
			"GET\n\n\nTue, 27 Mar 2007 19:42:41 +0000\n/johnsmith/",
			"AWS AKIAIOSFODNN7EXAMPLE:htDYFYduRNen8P9ZfE/s9SuKy0U=",
		},
		testCase{
			"GET\n\n\nTue, 27 Mar 2007 19:44:46 +0000\n/johnsmith/?acl",
			"AWS AKIAIOSFODNN7EXAMPLE:c2WLPFtWHVgbEmeEG93a4cG37dM=",
		},
		testCase{
			"DELETE\n\n\nx-amz-date:Tue, 27 Mar 2007 21:20:26 +0000\n/johnsmith/photos/puppy.jpg",
			"AWS AKIAIOSFODNN7EXAMPLE:9b2sXq0KfxsxHtdZkzx/9Ngqyh8=",
		},
	}

	for i, c := range cases {
		// Function
		sts := func(r *http.Request)(string, error) { return c.stringToSign, nil }

		// Signer
		signer, err := newSigner(sts, key)
		AssertEq(nil, err)

		// Call
		req := &http.Request{}
		err = signer.Sign(req)
		AssertEq(nil, err)

		ExpectEq(c.expectedHeaderValue, req.Headers["Authorization"], "Case %d: %v", i, c)
	}
}
<|endoftext|>


<commit_before>package validator

import "testing"

func BenchmarkValidateField(b *testing.B) {
	for n := 0; n < b.N; n++ {
		validate.Field("1", "len=1")
	}
}

func BenchmarkValidateStructSimple(b *testing.B) {

	type Foo struct {
		StringValue string `validate:"min=5,max=10"`
		IntValue    int    `validate:"min=5,max=10"`
	}

	validFoo := &Foo{StringValue: "Foobar", IntValue: 7}
	invalidFoo := &Foo{StringValue: "Fo", IntValue: 3}

	for n := 0; n < b.N; n++ {
		validate.Struct(validFoo)
		validate.Struct(invalidFoo)
	}
}

func BenchmarkTemplateParallelSimple(b *testing.B) {

	type Foo struct {
		StringValue string `validate:"min=5,max=10"`
		IntValue    int    `validate:"min=5,max=10"`
	}

	validFoo := &Foo{StringValue: "Foobar", IntValue: 7}
	invalidFoo := &Foo{StringValue: "Fo", IntValue: 3}

	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			validate.Struct(validFoo)
			validate.Struct(invalidFoo)
		}
	})
}

func BenchmarkValidateStructLarge(b *testing.B) {

	tFail := &TestString{
		Required:  "",
		Len:       "",
		Min:       "",
		Max:       "12345678901",
		MinMax:    "",
		Lt:        "0123456789",
		Lte:       "01234567890",
		Gt:        "1",
		Gte:       "1",
		OmitEmpty: "12345678901",
		Sub: &SubTest{
			Test: "",
		},
		Anonymous: struct {
			A string `validate:"required"`
		}{
			A: "",
		},
		Iface: &Impl{
			F: "12",
		},
	}

	tSuccess := &TestString{
		Required:  "Required",
		Len:       "length==10",
		Min:       "min=1",
		Max:       "1234567890",
		MinMax:    "12345",
		Lt:        "012345678",
		Lte:       "0123456789",
		Gt:        "01234567890",
		Gte:       "0123456789",
		OmitEmpty: "",
		Sub: &SubTest{
			Test: "1",
		},
		SubIgnore: &SubTest{
			Test: "",
		},
		Anonymous: struct {
			A string `validate:"required"`
		}{
			A: "1",
		},
		Iface: &Impl{
			F: "123",
		},
	}

	for n := 0; n < b.N; n++ {
		validate.Struct(tSuccess)
		validate.Struct(tFail)
	}
}

func BenchmarkTemplateParallelLarge(b *testing.B) {

	tFail := &TestString{
		Required:  "",
		Len:       "",
		Min:       "",
		Max:       "12345678901",
		MinMax:    "",
		Lt:        "0123456789",
		Lte:       "01234567890",
		Gt:        "1",
		Gte:       "1",
		OmitEmpty: "12345678901",
		Sub: &SubTest{
			Test: "",
		},
		Anonymous: struct {
			A string `validate:"required"`
		}{
			A: "",
		},
		Iface: &Impl{
			F: "12",
		},
	}

	tSuccess := &TestString{
		Required:  "Required",
		Len:       "length==10",
		Min:       "min=1",
		Max:       "1234567890",
		MinMax:    "12345",
		Lt:        "012345678",
		Lte:       "0123456789",
		Gt:        "01234567890",
		Gte:       "0123456789",
		OmitEmpty: "",
		Sub: &SubTest{
			Test: "1",
		},
		SubIgnore: &SubTest{
			Test: "",
		},
		Anonymous: struct {
			A string `validate:"required"`
		}{
			A: "1",
		},
		Iface: &Impl{
			F: "123",
		},
	}

	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			validate.Struct(tSuccess)
			validate.Struct(tFail)
		}
	})
}
<commit_msg>Benchmark Updates<commit_after>package validator

import "testing"

func BenchmarkField(b *testing.B) {
	for n := 0; n < b.N; n++ {
		validate.Field("1", "len=1")
	}
}

func BenchmarkFieldOrTag(b *testing.B) {
	for n := 0; n < b.N; n++ {
		validate.Field("rgba(0,0,0,1)", "rgb|rgba")
	}
}

func BenchmarkStructSimple(b *testing.B) {

	type Foo struct {
		StringValue string `validate:"min=5,max=10"`
		IntValue    int    `validate:"min=5,max=10"`
	}

	validFoo := &Foo{StringValue: "Foobar", IntValue: 7}
	invalidFoo := &Foo{StringValue: "Fo", IntValue: 3}

	for n := 0; n < b.N; n++ {
		validate.Struct(validFoo)
		validate.Struct(invalidFoo)
	}
}

func BenchmarkStructSimpleParallel(b *testing.B) {

	type Foo struct {
		StringValue string `validate:"min=5,max=10"`
		IntValue    int    `validate:"min=5,max=10"`
	}

	validFoo := &Foo{StringValue: "Foobar", IntValue: 7}
	invalidFoo := &Foo{StringValue: "Fo", IntValue: 3}

	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			validate.Struct(validFoo)
			validate.Struct(invalidFoo)
		}
	})
}

func BenchmarkStructComplex(b *testing.B) {

	tFail := &TestString{
		Required:  "",
		Len:       "",
		Min:       "",
		Max:       "12345678901",
		MinMax:    "",
		Lt:        "0123456789",
		Lte:       "01234567890",
		Gt:        "1",
		Gte:       "1",
		OmitEmpty: "12345678901",
		Sub: &SubTest{
			Test: "",
		},
		Anonymous: struct {
			A string `validate:"required"`
		}{
			A: "",
		},
		Iface: &Impl{
			F: "12",
		},
	}

	tSuccess := &TestString{
		Required:  "Required",
		Len:       "length==10",
		Min:       "min=1",
		Max:       "1234567890",
		MinMax:    "12345",
		Lt:        "012345678",
		Lte:       "0123456789",
		Gt:        "01234567890",
		Gte:       "0123456789",
		OmitEmpty: "",
		Sub: &SubTest{
			Test: "1",
		},
		SubIgnore: &SubTest{
			Test: "",
		},
		Anonymous: struct {
			A string `validate:"required"`
		}{
			A: "1",
		},
		Iface: &Impl{
			F: "123",
		},
	}

	for n := 0; n < b.N; n++ {
		validate.Struct(tSuccess)
		validate.Struct(tFail)
	}
}

func BenchmarkStructComplexParallel(b *testing.B) {

	tFail := &TestString{
		Required:  "",
		Len:       "",
		Min:       "",
		Max:       "12345678901",
		MinMax:    "",
		Lt:        "0123456789",
		Lte:       "01234567890",
		Gt:        "1",
		Gte:       "1",
		OmitEmpty: "12345678901",
		Sub: &SubTest{
			Test: "",
		},
		Anonymous: struct {
			A string `validate:"required"`
		}{
			A: "",
		},
		Iface: &Impl{
			F: "12",
		},
	}

	tSuccess := &TestString{
		Required:  "Required",
		Len:       "length==10",
		Min:       "min=1",
		Max:       "1234567890",
		MinMax:    "12345",
		Lt:        "012345678",
		Lte:       "0123456789",
		Gt:        "01234567890",
		Gte:       "0123456789",
		OmitEmpty: "",
		Sub: &SubTest{
			Test: "1",
		},
		SubIgnore: &SubTest{
			Test: "",
		},
		Anonymous: struct {
			A string `validate:"required"`
		}{
			A: "1",
		},
		Iface: &Impl{
			F: "123",
		},
	}

	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			validate.Struct(tSuccess)
			validate.Struct(tFail)
		}
	})
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net/http"
	"time"
)

const numEncoders = 5

func main() {
	jsonCh := make(chan encoderArg)
	base64Ch := make(chan encoderArg)
	stopCh := make(chan struct{})

	log.Printf("starting %d encoders", numEncoders)
	for i := 0; i < numEncoders; i++ {
		go jsonEncoder(jsonCh, stopCh)
		go base64Encoder(base64Ch, stopCh)
	}

	http.HandleFunc("/json", func(w http.ResponseWriter, r *http.Request) {
		arg := newEncoderArg(r.URL.Query().Get("val"))
		jsonCh <- arg
		select {
		case err := <-arg.errCh:
			http.Error(w, err.Error(), http.StatusInternalServerError)
		case ret := <-arg.retCh:
			w.Write(ret)
		case <-time.After(100 * time.Millisecond):
			http.Error(w, "failed to encode within 100ms", http.StatusInternalServerError)
		}
	})

	http.HandleFunc("/base64", func(w http.ResponseWriter, r *http.Request) {
		arg := newEncoderArg(r.URL.Query().Get("val"))
		base64Ch <- arg
		select {
		case err := <-arg.errCh:
			http.Error(w, err.Error(), http.StatusInternalServerError)
		case ret := <-arg.retCh:
			w.Write(ret)
		case <-time.After(100 * time.Millisecond):
			http.Error(w, "failed to encode within 100ms", http.StatusInternalServerError)
		}
	})

	http.HandleFunc("/stop", func(w http.ResponseWriter, r *http.Request) {
		close(stopCh)
		w.Write([]byte("stopped"))
	})

	log.Printf("listening on port 8080")
	http.ListenAndServe(":8080", nil)
}
<commit_msg>add n.b.<commit_after>package main

import (
	"log"
	"net/http"
	"time"
)

const numEncoders = 5

func main() {
	jsonCh := make(chan encoderArg)
	base64Ch := make(chan encoderArg)
	stopCh := make(chan struct{})

	log.Printf("starting %d encoders", numEncoders)
	for i := 0; i < numEncoders; i++ {
		go jsonEncoder(jsonCh, stopCh)
		go base64Encoder(base64Ch, stopCh)
	}

	http.HandleFunc("/json", func(w http.ResponseWriter, r *http.Request) {
		arg := newEncoderArg(r.URL.Query().Get("val"))
		jsonCh <- arg
		select {
		case err := <-arg.errCh:
			http.Error(w, err.Error(), http.StatusInternalServerError)
		case ret := <-arg.retCh:
			w.Write(ret)
		case <-time.After(100 * time.Millisecond):
			http.Error(w, "failed to encode within 100ms", http.StatusInternalServerError)
		}
	})

	http.HandleFunc("/base64", func(w http.ResponseWriter, r *http.Request) {
		arg := newEncoderArg(r.URL.Query().Get("val"))
		base64Ch <- arg
		select {
		case err := <-arg.errCh:
			http.Error(w, err.Error(), http.StatusInternalServerError)
		case ret := <-arg.retCh:
			w.Write(ret)
		case <-time.After(100 * time.Millisecond):
			http.Error(w, "failed to encode within 100ms", http.StatusInternalServerError)
		}
	})

	http.HandleFunc("/stop", func(w http.ResponseWriter, r *http.Request) {
		// NOTE: multiple calls to stop won't work here because you can't close a closed channel.
		// consider this package to do this kind of cancellation for production code:
		// https://godoc.org/context
		close(stopCh)
		w.Write([]byte("stopped"))
	})

	log.Printf("listening on port 8080")
	http.ListenAndServe(":8080", nil)
}
<|endoftext|>


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

package block_device_utils

import (
	"bufio"
	"github.com/IBM/ubiquity/utils/logs"
	"path"
	"path/filepath"
	"regexp"
	"strings"
	"fmt"
)

const multipathCmd = "multipath"

func (b *blockDeviceUtils) ReloadMultipath() error {
	defer b.logger.Trace(logs.DEBUG)()
	if err := b.exec.IsExecutable(multipathCmd); err != nil {
		return b.logger.ErrorRet(&commandNotFoundError{multipathCmd, err}, "failed")
	}
	args := []string{"-r"}
	if _, err := b.exec.Execute(multipathCmd, args); err != nil {
		return b.logger.ErrorRet(&commandExecuteError{multipathCmd, err}, "failed")
	}
	return nil
}

func (b *blockDeviceUtils) Discover(volumeWwn string) (string, error) {
	defer b.logger.Trace(logs.DEBUG)()
	if err := b.exec.IsExecutable(multipathCmd); err != nil {
		return "", b.logger.ErrorRet(&commandNotFoundError{multipathCmd, err}, "failed")
	}
	args := []string{"-ll"}
	outputBytes, err := b.exec.Execute(multipathCmd, args)
	if err != nil {
		return "", b.logger.ErrorRet(&commandExecuteError{multipathCmd, err}, "failed")
	}
	scanner := bufio.NewScanner(strings.NewReader(string(outputBytes[:])))
	pattern := "(?i)" + volumeWwn
	regex, err := regexp.Compile(pattern)
	if err != nil {
		return "", b.logger.ErrorRet(err, "failed")
	}
	dev := ""
	for scanner.Scan() {
		if regex.MatchString(scanner.Text()) {
			dev = strings.Split(scanner.Text(), " ")[0]
			break
		}
	}

	if dev == "" {
		dev, err = b.DiscoverBySgInq(string(outputBytes[:]), volumeWwn)
		if err != nil {
			return "", b.logger.ErrorRet(&volumeNotFoundError{volumeWwn}, "failed")
		} else {
			b.logger.Debug(fmt.Sprintf("WWN %s was found using sg_inq, the device is %s.", volumeWwn, dev))
		}
	}
	mpath := b.mpathDevFullPath(dev)
	if _, err = b.exec.Stat(mpath); err != nil {
		return "", b.logger.ErrorRet(err, "Stat failed")
	}
	b.logger.Info("discovered", logs.Args{{"volumeWwn", volumeWwn}, {"mpath", mpath}})
	return mpath, nil
}

func (b *blockDeviceUtils) mpathDevFullPath(dev string) (string) {
	return path.Join(string(filepath.Separator), "dev", "mapper", dev)
}

func (b *blockDeviceUtils) DiscoverBySgInq(mpathOutput string, volumeWwn string) (string, error) {
	defer b.logger.Trace(logs.DEBUG)()

	scanner := bufio.NewScanner(strings.NewReader(mpathOutput))
	pattern := "(?i)" + "^mpath"
	regex, err := regexp.Compile(pattern)
	if err != nil {
		return "", b.logger.ErrorRet(err, "failed")
	}
	dev := ""
	for scanner.Scan() {
		if regex.MatchString(scanner.Text()) {
			dev = strings.Split(scanner.Text(), " ")[0]
			mpathFullPath := b.mpathDevFullPath(dev)
			wwn, err := b.GetWwnByScsiInq(mpathFullPath)
			if err != nil {
				return "", b.logger.ErrorRet(&volumeNotFoundError{volumeWwn}, "failed")
			}
			if wwn == volumeWwn{
				return dev, nil
			}
		}
	}
	return "", nil
}

func (b *blockDeviceUtils) GetWwnByScsiInq(dev string) (string, error) {
	defer b.logger.Trace(logs.DEBUG)()
	/* scsi inq example
		sg_inq -p 0x83 /dev/mapper/mpathhe
		VPD INQUIRY: Device Identification page
		  Designation descriptor number 1, descriptor length: 20
			designator_type: NAA,  code_set: Binary
			associated with the addressed logical unit
			  NAA 6, IEEE Company_id: 0x1738
			  Vendor Specific Identifier: 0xcfc9035eb
			  Vendor Specific Identifier Extension: 0xcea5f6
			  [0x6001738cfc9035eb0000000000ceaaaa]
		  Designation descriptor number 2, descriptor length: 52
			designator_type: T10 vendor identification,  code_set: ASCII
			associated with the addressed logical unit
			  vendor id: IBM
			  vendor specific: 2810XIV          60035EB0000000000CEAAAA
		  Designation descriptor number 3, descriptor length: 43
			designator_type: vendor specific [0x0],  code_set: ASCII
			associated with the addressed logical unit
			  vendor specific: vol=u_k8s_longevity_ibm-ubiquity-db
		  Designation descriptor number 4, descriptor length: 37
			designator_type: vendor specific [0x0],  code_set: ASCII
			associated with the addressed logical unit
			  vendor specific: host=k8s-acceptance-v18-node1
		  Designation descriptor number 5, descriptor length: 8
			designator_type: Target port group,  code_set: Binary
			associated with the target port
			  Target port group: 0x0
		  Designation descriptor number 6, descriptor length: 8
			designator_type: Relative target port,  code_set: Binary
			associated with the target port
			  Relative target port: 0xd22
	*/
	sgInqCmd := "sg_inq"

	args := []string{"-p",  "0x83", dev}
	outputBytes, err := b.exec.Execute(sgInqCmd, args)
	if err != nil {
		return "", b.logger.ErrorRet(&commandExecuteError{sgInqCmd, err}, "failed")
	}
	wwnRegex := `\[0x(.*?)\]`
	wwnRegexCompiled, err := regexp.Compile(wwnRegex)
	pattern := "(?i)" + "Vendor Specific Identifier Extension:"
	scanner := bufio.NewScanner(strings.NewReader(string(outputBytes[:])))
	regex, err := regexp.Compile(pattern)
	if err != nil {
		return "", b.logger.ErrorRet(err, "failed")
	}
	wwn := ""
	found := false
	for scanner.Scan() {
		line := scanner.Text()
		if found {
			matches := wwnRegexCompiled.FindStringSubmatch(line)
			if len(matches) != 2 {
				return "", b.logger.ErrorRet(&noRegexWwnMatchInScsiInqError{ dev, line }, "failed")
			}
			wwn = matches[1]
			return wwn, nil
		}
		if regex.MatchString(line) {
			found = true
			// next line is the line we need
			continue
		}

	}
	return "", b.logger.ErrorRet(&volumeNotFoundError{wwn}, "failed")
}

func (b *blockDeviceUtils) Cleanup(mpath string) error {
	defer b.logger.Trace(logs.DEBUG)()
	dev := path.Base(mpath)
	dmsetupCmd := "dmsetup"
	if err := b.exec.IsExecutable(dmsetupCmd); err != nil {
		return b.logger.ErrorRet(&commandNotFoundError{dmsetupCmd, err}, "failed")
	}
	args := []string{"message", dev, "0", "fail_if_no_path"}
	if _, err := b.exec.Execute(dmsetupCmd, args); err != nil {
		return b.logger.ErrorRet(&commandExecuteError{dmsetupCmd, err}, "failed")
	}
	if err := b.exec.IsExecutable(multipathCmd); err != nil {
		return b.logger.ErrorRet(&commandNotFoundError{multipathCmd, err}, "failed")
	}
	args = []string{"-f", dev}
	if _, err := b.exec.Execute(multipathCmd, args); err != nil {
		return b.logger.ErrorRet(&commandExecuteError{multipathCmd, err}, "failed")
	}
	b.logger.Info("flushed", logs.Args{{"mpath", mpath}})
	return nil
}
<commit_msg>Added more debugging issues, and an error in case of wwn not found in mpath output.<commit_after>/**
 * Copyright 2017 IBM Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package block_device_utils

import (
	"bufio"
	"github.com/IBM/ubiquity/utils/logs"
	"path"
	"path/filepath"
	"regexp"
	"strings"
	"fmt"
)

const multipathCmd = "multipath"

func (b *blockDeviceUtils) ReloadMultipath() error {
	defer b.logger.Trace(logs.DEBUG)()
	if err := b.exec.IsExecutable(multipathCmd); err != nil {
		return b.logger.ErrorRet(&commandNotFoundError{multipathCmd, err}, "failed")
	}
	args := []string{"-r"}
	if _, err := b.exec.Execute(multipathCmd, args); err != nil {
		return b.logger.ErrorRet(&commandExecuteError{multipathCmd, err}, "failed")
	}
	return nil
}

func (b *blockDeviceUtils) Discover(volumeWwn string) (string, error) {
	defer b.logger.Trace(logs.DEBUG)()
	if err := b.exec.IsExecutable(multipathCmd); err != nil {
		return "", b.logger.ErrorRet(&commandNotFoundError{multipathCmd, err}, "failed")
	}
	args := []string{"-ll"}
	outputBytes, err := b.exec.Execute(multipathCmd, args)
	if err != nil {
		return "", b.logger.ErrorRet(&commandExecuteError{multipathCmd, err}, "failed")
	}
	scanner := bufio.NewScanner(strings.NewReader(string(outputBytes[:])))
	pattern := "(?i)" + volumeWwn
	regex, err := regexp.Compile(pattern)
	if err != nil {
		return "", b.logger.ErrorRet(err, "failed")
	}
	dev := ""
	for scanner.Scan() {
		if regex.MatchString(scanner.Text()) {
			dev = strings.Split(scanner.Text(), " ")[0]
			break
		}
	}

	if dev == "" {
		dev, err = b.DiscoverBySgInq(string(outputBytes[:]), volumeWwn)
		if err != nil {
			return "", b.logger.ErrorRet(&volumeNotFoundError{volumeWwn}, "failed")
		} else {
			b.logger.Debug(fmt.Sprintf("WWN %s was found using sg_inq, the device is %s.", volumeWwn, dev))
		}
	}
	mpath := b.mpathDevFullPath(dev)
	if _, err = b.exec.Stat(mpath); err != nil {
		return "", b.logger.ErrorRet(err, "Stat failed")
	}
	b.logger.Info("discovered", logs.Args{{"volumeWwn", volumeWwn}, {"mpath", mpath}})
	return mpath, nil
}

func (b *blockDeviceUtils) mpathDevFullPath(dev string) (string) {
	return path.Join(string(filepath.Separator), "dev", "mapper", dev)
}

func (b *blockDeviceUtils) DiscoverBySgInq(mpathOutput string, volumeWwn string) (string, error) {
	defer b.logger.Trace(logs.DEBUG)()

	scanner := bufio.NewScanner(strings.NewReader(mpathOutput))
	pattern := "(?i)" + "^mpath"
	regex, err := regexp.Compile(pattern)
	if err != nil {
		return "", b.logger.ErrorRet(err, "failed")
	}
	dev := ""
	for scanner.Scan() {
		line := scanner.Text()
		b.logger.Debug(fmt.Sprintf("%s", line))
		if regex.MatchString(line) {
			dev = strings.Split(line, " ")[0]
			mpathFullPath := b.mpathDevFullPath(dev)
			wwn, err := b.GetWwnByScsiInq(mpathFullPath)
			if err != nil {
				return "", b.logger.ErrorRet(&volumeNotFoundError{volumeWwn}, "failed")
			}
			if wwn == volumeWwn{
				return dev, nil
			}
		}
	}
	return "", b.logger.ErrorRet(&volumeNotFoundError{volumeWwn}, "failed")
}

func (b *blockDeviceUtils) GetWwnByScsiInq(dev string) (string, error) {
	defer b.logger.Trace(logs.DEBUG)()
	/* scsi inq example
		sg_inq -p 0x83 /dev/mapper/mpathhe
		VPD INQUIRY: Device Identification page
		  Designation descriptor number 1, descriptor length: 20
			designator_type: NAA,  code_set: Binary
			associated with the addressed logical unit
			  NAA 6, IEEE Company_id: 0x1738
			  Vendor Specific Identifier: 0xcfc9035eb
			  Vendor Specific Identifier Extension: 0xcea5f6
			  [0x6001738cfc9035eb0000000000ceaaaa]
		  Designation descriptor number 2, descriptor length: 52
			designator_type: T10 vendor identification,  code_set: ASCII
			associated with the addressed logical unit
			  vendor id: IBM
			  vendor specific: 2810XIV          60035EB0000000000CEAAAA
		  Designation descriptor number 3, descriptor length: 43
			designator_type: vendor specific [0x0],  code_set: ASCII
			associated with the addressed logical unit
			  vendor specific: vol=u_k8s_longevity_ibm-ubiquity-db
		  Designation descriptor number 4, descriptor length: 37
			designator_type: vendor specific [0x0],  code_set: ASCII
			associated with the addressed logical unit
			  vendor specific: host=k8s-acceptance-v18-node1
		  Designation descriptor number 5, descriptor length: 8
			designator_type: Target port group,  code_set: Binary
			associated with the target port
			  Target port group: 0x0
		  Designation descriptor number 6, descriptor length: 8
			designator_type: Relative target port,  code_set: Binary
			associated with the target port
			  Relative target port: 0xd22
	*/
	sgInqCmd := "sg_inq"

	args := []string{"-p",  "0x83", dev}
	outputBytes, err := b.exec.Execute(sgInqCmd, args)
	if err != nil {
		return "", b.logger.ErrorRet(&commandExecuteError{sgInqCmd, err}, "failed")
	}
	wwnRegex := `\[0x(.*?)\]`
	wwnRegexCompiled, err := regexp.Compile(wwnRegex)
	pattern := "(?i)" + "Vendor Specific Identifier Extension:"
	scanner := bufio.NewScanner(strings.NewReader(string(outputBytes[:])))
	regex, err := regexp.Compile(pattern)
	if err != nil {
		return "", b.logger.ErrorRet(err, "failed")
	}
	wwn := ""
	found := false
	for scanner.Scan() {
		line := scanner.Text()
		if found {
			matches := wwnRegexCompiled.FindStringSubmatch(line)
			if len(matches) != 2 {
				return "", b.logger.ErrorRet(&noRegexWwnMatchInScsiInqError{ dev, line }, "failed")
			}
			wwn = matches[1]
			return wwn, nil
		}
		if regex.MatchString(line) {
			found = true
			// next line is the line we need
			continue
		}

	}
	return "", b.logger.ErrorRet(&volumeNotFoundError{wwn}, "failed")
}

func (b *blockDeviceUtils) Cleanup(mpath string) error {
	defer b.logger.Trace(logs.DEBUG)()
	dev := path.Base(mpath)
	dmsetupCmd := "dmsetup"
	if err := b.exec.IsExecutable(dmsetupCmd); err != nil {
		return b.logger.ErrorRet(&commandNotFoundError{dmsetupCmd, err}, "failed")
	}
	args := []string{"message", dev, "0", "fail_if_no_path"}
	if _, err := b.exec.Execute(dmsetupCmd, args); err != nil {
		return b.logger.ErrorRet(&commandExecuteError{dmsetupCmd, err}, "failed")
	}
	if err := b.exec.IsExecutable(multipathCmd); err != nil {
		return b.logger.ErrorRet(&commandNotFoundError{multipathCmd, err}, "failed")
	}
	args = []string{"-f", dev}
	if _, err := b.exec.Execute(multipathCmd, args); err != nil {
		return b.logger.ErrorRet(&commandExecuteError{multipathCmd, err}, "failed")
	}
	b.logger.Info("flushed", logs.Args{{"mpath", mpath}})
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/tischda/gotimer/registry"
	"io/ioutil"
	"os"
	"regexp"
	"testing"
	"time"
	"strconv"
)

var sut Timer
var mockRegistry = registry.NewMockRegistry()

func init() {
	sut = Timer{
		registry: mockRegistry,
	}
}

func TestStart(t *testing.T) {
	sut.start("t1")
	actual := mockRegistry.Timers["t1"]
	if actual == 0 {
		t.Errorf("Expected: >0, was: %q", actual)
	}
}

func TestStop(t *testing.T) {
	sut.start("t2")
	time.Sleep(10 * time.Millisecond)
	actual := sut.getDuration("t2")
	if actual < 9*time.Millisecond || actual > 14*time.Millisecond {
		t.Errorf("Expected: 10 msec, was: %q", actual)
	}
}

func TestClear(t *testing.T) {
	sut.start("t3")
	sut.clear("t3")
	_, exists := mockRegistry.Timers["t3"]
	if exists {
		t.Errorf("Expected: false, was: %q", strconv.FormatBool(exists))
	}
}

func TestList(t *testing.T) {
	sut.clear("")
	sut.start("t1")
	sut.start("t2")

	expected := "[t1 t2]\n"
	actual := captureOutput(func() { sut.list("") })
	if actual != expected {
		t.Errorf("Expected: %q, was: %q", expected, actual)
	}
}

func TestExec(t *testing.T) {
	r, _ := regexp.Compile(execTestRxp)
	actual := captureOutput(func() { sut.exec(execTestCmd) })
	if !r.MatchString(actual) {
		t.Errorf("Expected: %q, was: %q", execTestRxp, actual)
	}
}

// Captures Stdout and returns output of function f()
func captureOutput(f func()) string {
	// redirect output
	old := os.Stdout
	r, w, _ := os.Pipe()
	os.Stdout = w

	f()

	// reset output again
	w.Close()
	os.Stdout = old

	captured, _ := ioutil.ReadAll(r)
	return string(captured)
}
<commit_msg>increase test range<commit_after>package main

import (
	"io/ioutil"
	"os"
	"regexp"
	"strconv"
	"testing"
	"time"

	"github.com/tischda/gotimer/registry"
)

var sut Timer
var mockRegistry = registry.NewMockRegistry()

func init() {
	sut = Timer{
		registry: mockRegistry,
	}
}

func TestStart(t *testing.T) {
	sut.start("t1")
	actual := mockRegistry.Timers["t1"]
	if actual == 0 {
		t.Errorf("Expected: >0, was: %q", actual)
	}
}

func TestStop(t *testing.T) {
	sut.start("t2")
	time.Sleep(10 * time.Millisecond)
	actual := sut.getDuration("t2")
	if actual < 9*time.Millisecond || actual > 18*time.Millisecond {
		t.Errorf("Expected: ~10 msec, was: %q", actual)
	}
}

func TestClear(t *testing.T) {
	sut.start("t3")
	sut.clear("t3")
	_, exists := mockRegistry.Timers["t3"]
	if exists {
		t.Errorf("Expected: false, was: %q", strconv.FormatBool(exists))
	}
}

func TestList(t *testing.T) {
	sut.clear("")
	sut.start("t1")
	sut.start("t2")

	expected := "[t1 t2]\n"
	actual := captureOutput(func() { sut.list("") })
	if actual != expected {
		t.Errorf("Expected: %q, was: %q", expected, actual)
	}
}

func TestExec(t *testing.T) {
	r, _ := regexp.Compile(execTestRxp)
	actual := captureOutput(func() { sut.exec(execTestCmd) })
	if !r.MatchString(actual) {
		t.Errorf("Expected: %q, was: %q", execTestRxp, actual)
	}
}

// Captures Stdout and returns output of function f()
func captureOutput(f func()) string {
	// redirect output
	old := os.Stdout
	r, w, _ := os.Pipe()
	os.Stdout = w

	f()

	// reset output again
	w.Close()
	os.Stdout = old

	captured, _ := ioutil.ReadAll(r)
	return string(captured)
}
<|endoftext|>


<commit_before>package form

import (
	"io/ioutil"
	"math"
	"net/http"
	"net/url"
	"reflect"
	"regexp"
	"strings"
	"testing"
)

type X struct {
	A string
}

func TestCreateTypeMap(t *testing.T) {
	for n, test := range [...]struct {
		Input  reflect.Type
		Output typeMap
	}{
		{ // 1
			Input: reflect.TypeOf(struct {
				A int
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 2
			Input: reflect.TypeOf(struct {
				A int `form:"B"`
			}{}),
			Output: typeMap{
				"B": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 3
			Input: reflect.TypeOf(struct {
				A int `form:",required"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Required: true,
					Index:    []int{0},
				},
			},
		},
		{ // 4
			Input: reflect.TypeOf(struct {
				A int `form:",post"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Post:  true,
					Index: []int{0},
				},
			},
		},
		{ // 5
			Input: reflect.TypeOf(struct {
				A int `form:",post,required"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Post:     true,
					Required: true,
					Index:    []int{0},
				},
			},
		},
		{ // 6
			Input: reflect.TypeOf(struct {
				A int `form:",required,post"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Post:     true,
					Required: true,
					Index:    []int{0},
				},
			},
		},
		{ // 7
			Input: reflect.TypeOf(struct {
				A int `min:"-20"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  -20,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 8
			Input: reflect.TypeOf(struct {
				A int `max:"-20"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  -20,
					},
					Index: []int{0},
				},
			},
		},
		{ // 9
			Input: reflect.TypeOf(struct {
				A int8
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 8,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 10
			Input: reflect.TypeOf(struct {
				A int16
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 16,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 11
			Input: reflect.TypeOf(struct {
				A int32
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 32,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 12
			Input: reflect.TypeOf(struct {
				A int64
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 13
			Input: reflect.TypeOf(struct {
				A uint
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 64,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 14
			Input: reflect.TypeOf(struct {
				A uint `min:"10"`
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 64,
						min:  10,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 15
			Input: reflect.TypeOf(struct {
				A uint `min:"-1"`
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 64,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 16
			Input: reflect.TypeOf(struct {
				A uint `max:"100"`
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 64,
						max:  100,
					},
					Index: []int{0},
				},
			},
		},
		{ // 17
			Input: reflect.TypeOf(struct {
				A uint8
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 8,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 18
			Input: reflect.TypeOf(struct {
				A uint16
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 16,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 19
			Input: reflect.TypeOf(struct {
				A uint32
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 32,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 20
			Input: reflect.TypeOf(struct {
				A uint
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 64,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 21
			Input: reflect.TypeOf(struct {
				A float32
			}{}),
			Output: typeMap{
				"A": {
					processor: float{
						bits: 32,
						min:  -math.MaxFloat64,
						max:  math.MaxFloat64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 22
			Input: reflect.TypeOf(struct {
				A float64
			}{}),
			Output: typeMap{
				"A": {
					processor: float{
						bits: 64,
						min:  -math.MaxFloat64,
						max:  math.MaxFloat64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 23
			Input: reflect.TypeOf(struct {
				A float64 `min:"-10"`
			}{}),
			Output: typeMap{
				"A": {
					processor: float{
						bits: 64,
						min:  -10,
						max:  math.MaxFloat64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 24
			Input: reflect.TypeOf(struct {
				A float64 `max:"10"`
			}{}),
			Output: typeMap{
				"A": {
					processor: float{
						bits: 64,
						min:  -math.MaxFloat64,
						max:  10,
					},
					Index: []int{0},
				},
			},
		},
		{ // 25
			Input: reflect.TypeOf(struct {
				A string
			}{}),
			Output: typeMap{
				"A": {
					processor: str{},
					Index:     []int{0},
				},
			},
		},
		{ // 26
			Input: reflect.TypeOf(struct {
				A string `regex:"/aaa/"`
			}{}),
			Output: typeMap{
				"A": {
					processor: str{
						regex: regexp.MustCompile("/aaa/"),
					},
					Index: []int{0},
				},
			},
		},
		{ // 27
			Input: reflect.TypeOf(struct {
				A bool
			}{}),
			Output: typeMap{
				"A": {
					processor: boolean{},
					Index:     []int{0},
				},
			},
		},
		{ // 28
			Input: reflect.TypeOf(struct {
				A []bool
			}{}),
			Output: typeMap{
				"A": {
					processor: slice{
						processor: boolean{},
						typ:       reflect.TypeOf(false),
					},
					Index: []int{0},
				},
			},
		},
		{ // 29
			Input: reflect.TypeOf(struct {
				X
			}{}),
			Output: typeMap{
				"A": {
					processor: str{},
					Index:     []int{0, 0},
				},
			},
		},
		{ // 29
			Input: reflect.TypeOf(struct {
				X
				A bool
			}{}),
			Output: typeMap{
				"A": {
					processor: boolean{},
					Index:     []int{1},
				},
			},
		},
	} {
		output := createTypeMap(test.Input)
		if !reflect.DeepEqual(output, test.Output) {
			t.Errorf("test %d: expecting output %v, got %v", n+1, test.Output, output)
		}
	}
}

func TestProcess(t *testing.T) {
	for n, test := range [...]struct {
		Get, Post url.Values
		Output    interface{}
		Err       error
	}{
		{ // 1
			url.Values{
				"A": []string{"1"},
			},
			url.Values{},
			struct {
				A int
			}{
				A: 1,
			},
			nil,
		},
		{ // 2
			url.Values{},
			url.Values{
				"A": []string{"1"},
			},
			struct {
				A int
			}{
				A: 1,
			},
			nil,
		},
		{ // 3
			url.Values{
				"A": []string{"1"},
			},
			url.Values{
				"A": []string{"2"},
			},
			struct {
				A int `form:",post"`
			}{
				A: 2,
			},
			nil,
		},
		{ // 4
			url.Values{},
			url.Values{},
			struct {
				A int `form:",required"`
			}{},
			ErrorMap{
				"A": ErrRequiredMissing,
			},
		},
		{ // 5
			url.Values{
				"B": []string{"10"},
			},
			url.Values{},
			struct {
				A int `form:"B"`
			}{
				A: 10,
			},
			nil,
		},
		{ // 6
			url.Values{
				"A": []string{"10"},
			},
			url.Values{},
			struct {
				A int `min:"15"`
			}{},
			ErrorMap{
				"A": ErrNotInRange,
			},
		},
		{ // 7
			url.Values{
				"A": []string{"10"},
			},
			url.Values{},
			struct {
				A int `max:"5"`
			}{},
			ErrorMap{
				"A": ErrNotInRange,
			},
		},
	} {
		r := http.Request{
			Method: http.MethodPost,
			URL: &url.URL{
				RawQuery: test.Get.Encode(),
			},
			Header: http.Header{
				"Content-Type": []string{"application/x-www-form-urlencoded"},
			},
			Body: ioutil.NopCloser(strings.NewReader(test.Post.Encode())),
		}
		output := reflect.New(reflect.TypeOf(test.Output))
		err := Process(&r, output.Interface())
		if err != nil {
			if test.Err == nil {
				t.Errorf("test %d: unexpected error: %s", n+1, err)
			} else if !reflect.DeepEqual(err, test.Err) {
				t.Errorf("test %d: expecting error: %s\ngot: %s", n+1, test.Err, err)
			}
		} else if test.Err != nil {
			t.Errorf("test %d: got no error when expecting: %s", n+1, test.Err)
		}
		if o := output.Elem().Interface(); !reflect.DeepEqual(o, test.Output) {
			t.Errorf("test %d: expecting output: %#v\ngot: %#v", n+1, test.Output, o)
		}
	}
}
<commit_msg>added 'in range' test<commit_after>package form

import (
	"io/ioutil"
	"math"
	"net/http"
	"net/url"
	"reflect"
	"regexp"
	"strings"
	"testing"
)

type X struct {
	A string
}

func TestCreateTypeMap(t *testing.T) {
	for n, test := range [...]struct {
		Input  reflect.Type
		Output typeMap
	}{
		{ // 1
			Input: reflect.TypeOf(struct {
				A int
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 2
			Input: reflect.TypeOf(struct {
				A int `form:"B"`
			}{}),
			Output: typeMap{
				"B": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 3
			Input: reflect.TypeOf(struct {
				A int `form:",required"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Required: true,
					Index:    []int{0},
				},
			},
		},
		{ // 4
			Input: reflect.TypeOf(struct {
				A int `form:",post"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Post:  true,
					Index: []int{0},
				},
			},
		},
		{ // 5
			Input: reflect.TypeOf(struct {
				A int `form:",post,required"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Post:     true,
					Required: true,
					Index:    []int{0},
				},
			},
		},
		{ // 6
			Input: reflect.TypeOf(struct {
				A int `form:",required,post"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Post:     true,
					Required: true,
					Index:    []int{0},
				},
			},
		},
		{ // 7
			Input: reflect.TypeOf(struct {
				A int `min:"-20"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  -20,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 8
			Input: reflect.TypeOf(struct {
				A int `max:"-20"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  -20,
					},
					Index: []int{0},
				},
			},
		},
		{ // 9
			Input: reflect.TypeOf(struct {
				A int8
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 8,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 10
			Input: reflect.TypeOf(struct {
				A int16
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 16,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 11
			Input: reflect.TypeOf(struct {
				A int32
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 32,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 12
			Input: reflect.TypeOf(struct {
				A int64
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 13
			Input: reflect.TypeOf(struct {
				A uint
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 64,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 14
			Input: reflect.TypeOf(struct {
				A uint `min:"10"`
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 64,
						min:  10,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 15
			Input: reflect.TypeOf(struct {
				A uint `min:"-1"`
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 64,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 16
			Input: reflect.TypeOf(struct {
				A uint `max:"100"`
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 64,
						max:  100,
					},
					Index: []int{0},
				},
			},
		},
		{ // 17
			Input: reflect.TypeOf(struct {
				A uint8
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 8,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 18
			Input: reflect.TypeOf(struct {
				A uint16
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 16,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 19
			Input: reflect.TypeOf(struct {
				A uint32
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 32,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 20
			Input: reflect.TypeOf(struct {
				A uint
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 64,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 21
			Input: reflect.TypeOf(struct {
				A float32
			}{}),
			Output: typeMap{
				"A": {
					processor: float{
						bits: 32,
						min:  -math.MaxFloat64,
						max:  math.MaxFloat64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 22
			Input: reflect.TypeOf(struct {
				A float64
			}{}),
			Output: typeMap{
				"A": {
					processor: float{
						bits: 64,
						min:  -math.MaxFloat64,
						max:  math.MaxFloat64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 23
			Input: reflect.TypeOf(struct {
				A float64 `min:"-10"`
			}{}),
			Output: typeMap{
				"A": {
					processor: float{
						bits: 64,
						min:  -10,
						max:  math.MaxFloat64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 24
			Input: reflect.TypeOf(struct {
				A float64 `max:"10"`
			}{}),
			Output: typeMap{
				"A": {
					processor: float{
						bits: 64,
						min:  -math.MaxFloat64,
						max:  10,
					},
					Index: []int{0},
				},
			},
		},
		{ // 25
			Input: reflect.TypeOf(struct {
				A string
			}{}),
			Output: typeMap{
				"A": {
					processor: str{},
					Index:     []int{0},
				},
			},
		},
		{ // 26
			Input: reflect.TypeOf(struct {
				A string `regex:"/aaa/"`
			}{}),
			Output: typeMap{
				"A": {
					processor: str{
						regex: regexp.MustCompile("/aaa/"),
					},
					Index: []int{0},
				},
			},
		},
		{ // 27
			Input: reflect.TypeOf(struct {
				A bool
			}{}),
			Output: typeMap{
				"A": {
					processor: boolean{},
					Index:     []int{0},
				},
			},
		},
		{ // 28
			Input: reflect.TypeOf(struct {
				A []bool
			}{}),
			Output: typeMap{
				"A": {
					processor: slice{
						processor: boolean{},
						typ:       reflect.TypeOf(false),
					},
					Index: []int{0},
				},
			},
		},
		{ // 29
			Input: reflect.TypeOf(struct {
				X
			}{}),
			Output: typeMap{
				"A": {
					processor: str{},
					Index:     []int{0, 0},
				},
			},
		},
		{ // 29
			Input: reflect.TypeOf(struct {
				X
				A bool
			}{}),
			Output: typeMap{
				"A": {
					processor: boolean{},
					Index:     []int{1},
				},
			},
		},
	} {
		output := createTypeMap(test.Input)
		if !reflect.DeepEqual(output, test.Output) {
			t.Errorf("test %d: expecting output %v, got %v", n+1, test.Output, output)
		}
	}
}

func TestProcess(t *testing.T) {
	for n, test := range [...]struct {
		Get, Post url.Values
		Output    interface{}
		Err       error
	}{
		{ // 1
			url.Values{
				"A": []string{"1"},
			},
			url.Values{},
			struct {
				A int
			}{
				A: 1,
			},
			nil,
		},
		{ // 2
			url.Values{},
			url.Values{
				"A": []string{"1"},
			},
			struct {
				A int
			}{
				A: 1,
			},
			nil,
		},
		{ // 3
			url.Values{
				"A": []string{"1"},
			},
			url.Values{
				"A": []string{"2"},
			},
			struct {
				A int `form:",post"`
			}{
				A: 2,
			},
			nil,
		},
		{ // 4
			url.Values{},
			url.Values{},
			struct {
				A int `form:",required"`
			}{},
			ErrorMap{
				"A": ErrRequiredMissing,
			},
		},
		{ // 5
			url.Values{
				"B": []string{"10"},
			},
			url.Values{},
			struct {
				A int `form:"B"`
			}{
				A: 10,
			},
			nil,
		},
		{ // 6
			url.Values{
				"A": []string{"10"},
			},
			url.Values{},
			struct {
				A int `min:"15"`
			}{},
			ErrorMap{
				"A": ErrNotInRange,
			},
		},
		{ // 7
			url.Values{
				"A": []string{"10"},
			},
			url.Values{},
			struct {
				A int `max:"5"`
			}{},
			ErrorMap{
				"A": ErrNotInRange,
			},
		},
		{ // 8
			url.Values{
				"A": []string{"10"},
			},
			url.Values{},
			struct {
				A int `min:"5" max:"15"`
			}{
				A: 10,
			},
			nil,
		},
	} {
		r := http.Request{
			Method: http.MethodPost,
			URL: &url.URL{
				RawQuery: test.Get.Encode(),
			},
			Header: http.Header{
				"Content-Type": []string{"application/x-www-form-urlencoded"},
			},
			Body: ioutil.NopCloser(strings.NewReader(test.Post.Encode())),
		}
		output := reflect.New(reflect.TypeOf(test.Output))
		err := Process(&r, output.Interface())
		if err != nil {
			if test.Err == nil {
				t.Errorf("test %d: unexpected error: %s", n+1, err)
			} else if !reflect.DeepEqual(err, test.Err) {
				t.Errorf("test %d: expecting error: %s\ngot: %s", n+1, test.Err, err)
			}
		} else if test.Err != nil {
			t.Errorf("test %d: got no error when expecting: %s", n+1, test.Err)
		}
		if o := output.Elem().Interface(); !reflect.DeepEqual(o, test.Output) {
			t.Errorf("test %d: expecting output: %#v\ngot: %#v", n+1, test.Output, o)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"io/ioutil"
	"fmt"
	"net/http"
	"os"
)

func main() {

	tok := os.Getenv("TOKEN")

    client := &http.Client{}

	auth := "Bearer " + tok
	fmt.Printf("%s\n", auth)

	req, err := http.NewRequest("GET", "https://graph.microsoft.com/v1.0/me/events", nil)
	req.Header.Add("Authorization", "Bearer " + tok)
	res, err := client.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer res.Body.Close()
	body, err := ioutil.ReadAll(res.Body)
	fmt.Printf("%s", body)
}
<commit_msg>parsing calendar events<commit_after>package main

import (
	"log"
	"io/ioutil"
	"fmt"
	"net/http"
	"os"
	"encoding/json"
)

func main() {

	tok := os.Getenv("TOKEN")

    client := &http.Client{}

	auth := "Bearer " + tok
	fmt.Printf("%s\n", auth)

	req, err := http.NewRequest("GET", "https://graph.microsoft.com/v1.0/me/events", nil)
	req.Header.Add("Authorization", "Bearer " + tok)
	res, err := client.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer res.Body.Close()
	body, err := ioutil.ReadAll(res.Body)
	fmt.Printf("%s\n", body)

	foo := Events{}
	json.Unmarshal(body, &foo)

	fmt.Println("-------------------")
	fmt.Printf("%+v\n", foo)
}

type Event struct {
	Odata_etag string `json:"@odata.etag"`
	Attendees  []struct {
		EmailAddress struct {
			Address string `json:"address"`
			Name    string `json:"name"`
		} `json:"emailAddress"`
		Status struct {
			Response string `json:"response"`
			Time     string `json:"time"`
		} `json:"status"`
		Type string `json:"type"`
	} `json:"attendees"`
	Body struct {
		Content     string `json:"content"`
		ContentType string `json:"contentType"`
	} `json:"body"`
	BodyPreview     string        `json:"bodyPreview"`
	Categories      []interface{} `json:"categories"`
	ChangeKey       string        `json:"changeKey"`
	CreatedDateTime string        `json:"createdDateTime"`
	End             struct {
		DateTime string `json:"dateTime"`
		TimeZone string `json:"timeZone"`
	} `json:"end"`
	HasAttachments       bool   `json:"hasAttachments"`
	ICalUID              string `json:"iCalUId"`
	ID                   string `json:"id"`
	Importance           string `json:"importance"`
	IsAllDay             bool   `json:"isAllDay"`
	IsCancelled          bool   `json:"isCancelled"`
	IsOrganizer          bool   `json:"isOrganizer"`
	IsReminderOn         bool   `json:"isReminderOn"`
	LastModifiedDateTime string `json:"lastModifiedDateTime"`
	Location             struct {
		DisplayName string `json:"displayName"`
	} `json:"location"`
	OnlineMeetingURL string `json:"onlineMeetingUrl"`
	Organizer        struct {
		EmailAddress struct {
			Address string `json:"address"`
			Name    string `json:"name"`
		} `json:"emailAddress"`
	} `json:"organizer"`
	OriginalEndTimeZone   string `json:"originalEndTimeZone"`
	OriginalStartTimeZone string `json:"originalStartTimeZone"`
	Recurrence            struct {
		Pattern struct {
			DayOfMonth     int64    `json:"dayOfMonth"`
			DaysOfWeek     []string `json:"daysOfWeek"`
			FirstDayOfWeek string   `json:"firstDayOfWeek"`
			Index          string   `json:"index"`
			Interval       int64    `json:"interval"`
			Month          int64    `json:"month"`
			Type           string   `json:"type"`
		} `json:"pattern"`
		Range struct {
			EndDate             string `json:"endDate"`
			NumberOfOccurrences int64  `json:"numberOfOccurrences"`
			RecurrenceTimeZone  string `json:"recurrenceTimeZone"`
			StartDate           string `json:"startDate"`
			Type                string `json:"type"`
		} `json:"range"`
	} `json:"recurrence"`
	ReminderMinutesBeforeStart int64 `json:"reminderMinutesBeforeStart"`
	ResponseRequested          bool  `json:"responseRequested"`
	ResponseStatus             struct {
		Response string `json:"response"`
		Time     string `json:"time"`
	} `json:"responseStatus"`
	Sensitivity    string      `json:"sensitivity"`
	SeriesMasterID interface{} `json:"seriesMasterId"`
	ShowAs         string      `json:"showAs"`
	Start          struct {
		DateTime string `json:"dateTime"`
		TimeZone string `json:"timeZone"`
	} `json:"start"`
	Subject string `json:"subject"`
	Type    string `json:"type"`
	WebLink string `json:"webLink"`
}

type Events struct {
	Odata_context  string `json:"@odata.context"`
	Odata_nextLink string `json:"@odata.nextLink"`
	Value          []Event
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"net"

	"github.com/AdRoll/hologram/protocol"
)

var host = flag.String("host", "localhost", "IP or hostname to ping")
var port = flag.Int("port", 3100, "Port to connect to for ping")

func main() {
	flag.Parse()
	connString := fmt.Sprintf("%s:%d", *host, *port)

	conn, err := net.Dial("tcp", connString)
	if err != nil {
		panic(err)
	}

	fmt.Printf("sending ping to %s...\n", connString)
	err = protocol.Write(conn, &protocol.Message{Ping: &protocol.Ping{}})
	response, err := protocol.Read(conn)

	if err != nil {
		panic(err)
	}

	if response.GetPing() != nil {
		fmt.Println("Got pong!")
	}
}
<commit_msg>Fix hologram-ping to connect using TLS<commit_after>package main

import (
	"flag"
	"fmt"
	"crypto/tls"
	"crypto/x509"
	"github.com/AdRoll/hologram/protocol"
)

var host = flag.String("host", "localhost", "IP or hostname to ping")
var port = flag.Int("port", 3100, "Port to connect to for ping")

func main() {
	flag.Parse()
	connString := fmt.Sprintf("%s:%d", *host, *port)

	pool := x509.NewCertPool()

	tlsConf := &tls.Config{
		RootCAs: pool,
		// Hologram only uses TLS to ensure the credentials that go across the wire are kept secret, and since go uses
		// ECDHE by default, we actually don't care about leaking keys or authenticating either end of the connection.
		InsecureSkipVerify: true,
	}

	conn, err := tls.Dial("tcp", connString, tlsConf)
	if err != nil {
		panic(err)
	}

	fmt.Printf("sending ping to %s...\n", connString)
	err = protocol.Write(conn, &protocol.Message{Ping: &protocol.Ping{}})
	response, err := protocol.Read(conn)

	if err != nil {
		panic(err)
	}

	if response.GetPing() != nil {
		fmt.Println("Got pong!")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
	"time"

	"github.com/funkygao/gafka/ctx"
)

type neverEnding byte

var gw *Gateway

func (b neverEnding) Read(p []byte) (n int, err error) {
	if len(p) < 16 {
		for i := range p {
			p[i] = byte(b)
		}
	} else {
		b.Read(p[:len(p)/2])
		copy(p[len(p)/2:], p)
	}
	return len(p), nil
}

func BenchmarkNeverending(b *testing.B) {
	buf := make([]byte, 4096)
	A := neverEnding('A')
	for i := 0; i < b.N; i++ {
		A.Read(buf)
	}
}

func newGatewayForTest(b *testing.B, store string) *Gateway {
	options.zone = "local"
	options.cluster = "me"
	options.pubHttpAddr = ":9191"
	options.subHttpAddr = ":9192"
	options.store = store
	options.debug = false
	options.logLevel = "info"

	ctx.LoadConfig("/etc/kateway.cf")

	gw := NewGateway("1", time.Hour)
	if err := gw.Start(); err != nil {
		b.Fatal(err)
	}

	return gw
}

func runBenchmarkPub(b *testing.B, store string) {
	if gw == nil {
		gw = newGatewayForTest(b, store)
	}

	b.ReportAllocs()
	const msgSize = 1 << 10
	b.SetBytes(msgSize)
	httpReqRaw := strings.TrimSpace(fmt.Sprintf(`
POST /topics/v1/foobar HTTP/1.1
Host: localhost:9191
User-Agent: Go-http-client/1.1
Content-Length: %d
Content-Type: application/x-www-form-urlencoded
Appid: myappid
Pubkey: mypubkey
Accept-Encoding: gzip`, msgSize)) + "\r\n\r\n"

	req, err := http.ReadRequest(bufio.NewReader(strings.NewReader(httpReqRaw)))
	if err != nil {
		b.Fatal(err)
	}

	rw := httptest.NewRecorder()
	lr := io.LimitReader(neverEnding('a'), msgSize)
	body := ioutil.NopCloser(lr)

	for i := 0; i < b.N; i++ {
		rw.Body.Reset()
		lr.(*io.LimitedReader).N = msgSize
		req.Body = body
		gw.pubHandler(rw, req)
	}
}

func BenchmarkPubKafka(b *testing.B) {
	runBenchmarkPub(b, "kafka")
}

func BenchmarkPubDumb(b *testing.B) {
	runBenchmarkPub(b, "dumb")
}
<commit_msg>performance compare between gorilla and httprouter<commit_after>package main

import (
	"bufio"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
	"time"

	"github.com/funkygao/gafka/ctx"
	"github.com/gorilla/mux"
	"github.com/julienschmidt/httprouter"
)

type neverEnding byte

var gw *Gateway

func (b neverEnding) Read(p []byte) (n int, err error) {
	if len(p) < 16 {
		for i := range p {
			p[i] = byte(b)
		}
	} else {
		b.Read(p[:len(p)/2])
		copy(p[len(p)/2:], p)
	}
	return len(p), nil
}

func BenchmarkNeverending(b *testing.B) {
	buf := make([]byte, 4096)
	A := neverEnding('A')
	for i := 0; i < b.N; i++ {
		A.Read(buf)
	}
}

func newGatewayForTest(b *testing.B, store string) *Gateway {
	options.zone = "local"
	options.cluster = "me"
	options.pubHttpAddr = ":9191"
	options.subHttpAddr = ":9192"
	options.store = store
	options.debug = false
	options.logLevel = "info"

	ctx.LoadConfig("/etc/kateway.cf")

	gw := NewGateway("1", time.Hour)
	if err := gw.Start(); err != nil {
		b.Fatal(err)
	}

	return gw
}

func runBenchmarkPub(b *testing.B, store string) {
	if gw == nil {
		gw = newGatewayForTest(b, store)
	}

	b.ReportAllocs()
	const msgSize = 1 << 10
	b.SetBytes(msgSize)
	httpReqRaw := strings.TrimSpace(fmt.Sprintf(`
POST /topics/v1/foobar HTTP/1.1
Host: localhost:9191
User-Agent: Go-http-client/1.1
Content-Length: %d
Content-Type: application/x-www-form-urlencoded
Appid: myappid
Pubkey: mypubkey
Accept-Encoding: gzip`, msgSize)) + "\r\n\r\n"

	req, err := http.ReadRequest(bufio.NewReader(strings.NewReader(httpReqRaw)))
	if err != nil {
		b.Fatal(err)
	}

	rw := httptest.NewRecorder()
	lr := io.LimitReader(neverEnding('a'), msgSize)
	body := ioutil.NopCloser(lr)

	for i := 0; i < b.N; i++ {
		rw.Body.Reset()
		lr.(*io.LimitedReader).N = msgSize
		req.Body = body
		gw.pubHandler(rw, req)
	}
}

func BenchmarkPubKafka(b *testing.B) {
	runBenchmarkPub(b, "kafka")
}

func BenchmarkPubDumb(b *testing.B) {
	runBenchmarkPub(b, "dumb")
}

func BenchmarkGorillaMux(b *testing.B) {
	router := mux.NewRouter()
	handler := func(w http.ResponseWriter, r *http.Request) {}
	router.HandleFunc("/topics/{topic}/{ver}", handler)
	router.HandleFunc("/ws/topics/{topic}/{ver}", handler)
	router.HandleFunc("/ver", handler)
	router.HandleFunc("/help", handler)
	router.HandleFunc("/stat", handler)
	router.HandleFunc("/ping", handler)
	router.HandleFunc("/clusters", handler)

	request, _ := http.NewRequest("GET", "/topics/anything/v1", nil)
	for i := 0; i < b.N; i++ {
		router.ServeHTTP(nil, request)
	}
}

func BenchmarkHttpRouter(b *testing.B) {
	router := httprouter.New()
	handler := func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {}
	router.POST("/topics/:topic/:ver", handler)
	router.POST("/ws/topics/:topic/:ver", handler)
	router.GET("/ver", handler)
	router.GET("/help", handler)
	router.GET("/stat", handler)
	router.GET("/ping", handler)
	router.GET("/clusters", handler)

	request, _ := http.NewRequest("POST", "/topics/anything/v1", nil)
	for i := 0; i < b.N; i++ {
		router.ServeHTTP(nil, request)
	}
}
<|endoftext|>