<commit_before>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package libkb

import (
	"fmt"
	"time"

	keybase1 "github.com/keybase/client/go/protocol/keybase1"
	jsonw "github.com/keybase/go-jsonw"
	"golang.org/x/net/context"
	"stathat.com/c/ramcache"
)

type ResolveResult struct {
	uid                keybase1.UID
	body               *jsonw.Wrapper
	err                error
	queriedKbUsername  string
	queriedByUID       bool
	resolvedKbUsername string
	cachedAt           time.Time
	mutable            bool
}

const (
	resolveCacheTTL           = 12 * time.Hour
	ResolveCacheMaxAge        = 12 * time.Hour
	ResolveCacheMaxAgeMutable = 20 * time.Minute
	resolveCacheMaxAgeErrored = 5 * time.Second
)

func (res *ResolveResult) GetUID() keybase1.UID {
	return res.uid
}

func (res *ResolveResult) GetUsername() string {
	return res.resolvedKbUsername
}
func (res *ResolveResult) GetNormalizedUsername() NormalizedUsername {
	return NewNormalizedUsername(res.GetUsername())
}
func (res *ResolveResult) GetNormalizedQueriedUsername() NormalizedUsername {
	return NewNormalizedUsername(res.queriedKbUsername)
}

func (res *ResolveResult) WasKBAssertion() bool {
	return res.queriedKbUsername != "" || res.queriedByUID
}

func (res *ResolveResult) GetError() error {
	return res.err
}

func (res *ResolveResult) GetBody() *jsonw.Wrapper {
	return res.body
}

func (r *Resolver) ResolveWithBody(input string) ResolveResult {
	return r.resolve(input, true)
}

func (r *Resolver) Resolve(input string) ResolveResult {
	return r.resolve(input, false)
}

func (r *Resolver) resolve(input string, withBody bool) (res ResolveResult) {
	defer r.G().Trace(fmt.Sprintf("Resolving username %q", input), func() error { return res.err })()

	var au AssertionURL
	if au, res.err = ParseAssertionURL(r.G().MakeAssertionContext(), input, false); res.err != nil {
		return res
	}
	res = r.resolveURL(context.TODO(), au, input, withBody, false)
	return res
}

func (r *Resolver) ResolveFullExpression(ctx context.Context, input string) (res ResolveResult) {
	return r.resolveFullExpression(ctx, input, false, false)
}

func (r *Resolver) ResolveFullExpressionNeedUsername(ctx context.Context, input string) (res ResolveResult) {
	return r.resolveFullExpression(ctx, input, false, true)
}

func (r *Resolver) ResolveFullExpressionWithBody(ctx context.Context, input string) (res ResolveResult) {
	return r.resolveFullExpression(ctx, input, true, false)
}

func (r *Resolver) resolveFullExpression(ctx context.Context, input string, withBody bool, needUsername bool) (res ResolveResult) {
	defer r.G().CTrace(ctx, fmt.Sprintf("Resolver#resolveFullExpression(%q)", input), func() error { return res.err })()

	var expr AssertionExpression
	expr, res.err = AssertionParseAndOnly(r.G().MakeAssertionContext(), input)
	if res.err != nil {
		return res
	}
	u := FindBestIdentifyComponentURL(expr)
	if u == nil {
		res.err = ResolutionError{Input: input, Msg: "Cannot find a resolvable factor"}
		return res
	}
	return r.resolveURL(ctx, u, input, withBody, needUsername)
}

func (r *Resolver) getFromDiskCache(ctx context.Context, key string) (ret *ResolveResult) {
	defer r.G().CTraceOK(ctx, fmt.Sprintf("Resolver#getFromDiskCache(%q)", key), func() bool { return ret != nil })()
	var uid keybase1.UID
	found, err := r.G().LocalDb.GetInto(&uid, resolveDbKey(key))
	r.Stats.diskGets++
	if err != nil {
		r.G().Log.CWarningf(ctx, "Problem fetching resolve result from local DB: %s", err)
		return nil
	}
	if !found {
		r.Stats.diskGetMisses++
		return nil
	}
	r.Stats.diskGetHits++
	return &ResolveResult{uid: uid}
}

func (r *Resolver) resolveURL(ctx context.Context, au AssertionURL, input string, withBody bool, needUsername bool) ResolveResult {

	// A standard keybase UID, so it's already resolved... unless we explicitly
	// need it!
	if !needUsername {
		if tmp := au.ToUID(); tmp.Exists() {
			return ResolveResult{uid: tmp}
		}
	}

	ck := au.CacheKey()

	if p := r.getFromMemCache(ctx, ck); p != nil && (!needUsername || len(p.resolvedKbUsername) > 0) {
		return *p
	}

	if p := r.getFromDiskCache(ctx, ck); p != nil && (!needUsername || len(p.resolvedKbUsername) > 0) {
		p.mutable = !au.IsKeybase()
		r.putToMemCache(ck, *p)
		return *p
	}

	res := r.resolveURLViaServerLookup(ctx, au, input, withBody)

	// Cache for a shorter period of time if it's not a Keybase identity
	res.mutable = !au.IsKeybase()
	r.putToMemCache(ck, res)
	r.putToDiskCache(ck, res)

	return res
}

func (r *Resolver) resolveURLViaServerLookup(ctx context.Context, au AssertionURL, input string, withBody bool) (res ResolveResult) {
	defer r.G().CTrace(ctx, fmt.Sprintf("Resolver#resolveURLViaServerLookup(input = %q)", input), func() error { return res.err })()

	var key, val string
	var ares *APIRes
	var l int

	if au.IsKeybase() {
		res.queriedKbUsername = au.GetValue()
	} else if au.IsUID() {
		res.queriedByUID = true
	}

	if key, val, res.err = au.ToLookup(); res.err != nil {
		return
	}

	ha := HTTPArgsFromKeyValuePair(key, S{val})
	ha.Add("multi", I{1})
	fields := "basics"
	if withBody {
		fields += ",public_keys,pictures"
	}
	ha.Add("fields", S{fields})
	ares, res.err = r.G().API.Get(APIArg{
		Endpoint:       "user/lookup",
		NeedSession:    false,
		Args:           ha,
		AppStatusCodes: []int{SCOk, SCNotFound, SCDeleted},
		NetContext:     ctx,
	})

	if res.err != nil {
		r.G().Log.CDebugf(ctx, "API user/lookup %q error: %s", input, res.err)
		return
	}
	switch ares.AppStatus.Code {
	case SCNotFound:
		r.G().Log.CDebugf(ctx, "API user/lookup %q not found", input)
		res.err = NotFoundError{}
		return
	case SCDeleted:
		r.G().Log.CDebugf(ctx, "API user/lookup %q deleted", input)
		res.err = DeletedError{Msg: fmt.Sprintf("user %q deleted", input)}
		return
	}

	var them *jsonw.Wrapper
	if them, res.err = ares.Body.AtKey("them").ToArray(); res.err != nil {
		return
	}

	if l, res.err = them.Len(); res.err != nil {
		return
	}

	if l == 0 {
		res.err = ResolutionError{Input: input, Msg: "No resolution found"}
	} else if l > 1 {
		res.err = ResolutionError{Input: input, Msg: "Identify is ambiguous"}
	} else {
		res.body = them.AtIndex(0)
		res.uid, res.err = GetUID(res.body.AtKey("id"))
		if res.err == nil {
			res.resolvedKbUsername, res.err = res.body.AtPath("basics.username").GetString()
		}
	}

	return
}

type ResolveCacheStats struct {
	misses          int
	timeouts        int
	mutableTimeouts int
	errorTimeouts   int
	hits            int
	diskGets        int
	diskGetHits     int
	diskGetMisses   int
	diskPuts        int
}

type Resolver struct {
	Contextified
	cache   *ramcache.Ramcache
	Stats   ResolveCacheStats
	NowFunc func() time.Time
}

func (s ResolveCacheStats) Eq(m, t, mt, et, h int) bool {
	return (s.misses == m) && (s.timeouts == t) && (s.mutableTimeouts == mt) && (s.errorTimeouts == et) && (s.hits == h)
}

func NewResolver(g *GlobalContext) *Resolver {
	return &Resolver{
		Contextified: NewContextified(g),
		cache:        nil,
		NowFunc:      func() time.Time { return time.Now() },
	}
}

func (r *Resolver) EnableCaching() {
	cache := ramcache.New()
	cache.MaxAge = ResolveCacheMaxAge
	cache.TTL = resolveCacheTTL
	r.cache = cache
}

func (r *Resolver) Shutdown() {
	if r.cache == nil {
		return
	}
	r.cache.Shutdown()
}

func (r *Resolver) getFromMemCache(ctx context.Context, key string) (ret *ResolveResult) {
	defer r.G().CTraceOK(ctx, fmt.Sprintf("Resolver#getFromMemCache(%q)", key), func() bool { return ret != nil })()
	if r.cache == nil {
		return nil
	}
	res, _ := r.cache.Get(key)
	if res == nil {
		r.Stats.misses++
		return nil
	}
	rres, ok := res.(*ResolveResult)
	if !ok {
		r.Stats.misses++
		return nil
	}
	now := r.NowFunc()
	if now.Sub(rres.cachedAt) > ResolveCacheMaxAge {
		r.Stats.timeouts++
		return nil
	}
	if rres.mutable && now.Sub(rres.cachedAt) > ResolveCacheMaxAgeMutable {
		r.Stats.mutableTimeouts++
		return nil
	}
	if rres.err != nil && now.Sub(rres.cachedAt) > resolveCacheMaxAgeErrored {
		r.Stats.errorTimeouts++
		return nil
	}
	r.Stats.hits++
	return rres
}

func resolveDbKey(key string) DbKey {
	return DbKey{
		Typ: DBResolveUsernameToUID,
		Key: NewNormalizedUsername(key).String(),
	}
}

func (r *Resolver) putToDiskCache(key string, res ResolveResult) {
	// Only cache immutable resolutions to disk
	if res.mutable || res.err != nil {
		return
	}
	r.Stats.diskPuts++
	err := r.G().LocalDb.PutObj(resolveDbKey(key), nil, res.uid)
	if err != nil {
		r.G().Log.Warning("Cannot put resolve result to disk: %s", err)
	}
}

// Put receives a copy of a ResolveResult, clears out the body
// to avoid caching data that can go stale, and stores the result.
func (r *Resolver) putToMemCache(key string, res ResolveResult) {
	if r.cache == nil {
		return
	}
	if res.err == nil {
		return
	}
	res.cachedAt = r.NowFunc()
	res.body = nil // Don't cache body
	r.cache.Set(key, &res)
}
<commit_msg>fix for trivial fix<commit_after>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package libkb

import (
	"fmt"
	"time"

	keybase1 "github.com/keybase/client/go/protocol/keybase1"
	jsonw "github.com/keybase/go-jsonw"
	"golang.org/x/net/context"
	"stathat.com/c/ramcache"
)

type ResolveResult struct {
	uid                keybase1.UID
	body               *jsonw.Wrapper
	err                error
	queriedKbUsername  string
	queriedByUID       bool
	resolvedKbUsername string
	cachedAt           time.Time
	mutable            bool
}

const (
	resolveCacheTTL           = 12 * time.Hour
	ResolveCacheMaxAge        = 12 * time.Hour
	ResolveCacheMaxAgeMutable = 20 * time.Minute
	resolveCacheMaxAgeErrored = 5 * time.Second
)

func (res *ResolveResult) GetUID() keybase1.UID {
	return res.uid
}

func (res *ResolveResult) GetUsername() string {
	return res.resolvedKbUsername
}
func (res *ResolveResult) GetNormalizedUsername() NormalizedUsername {
	return NewNormalizedUsername(res.GetUsername())
}
func (res *ResolveResult) GetNormalizedQueriedUsername() NormalizedUsername {
	return NewNormalizedUsername(res.queriedKbUsername)
}

func (res *ResolveResult) WasKBAssertion() bool {
	return res.queriedKbUsername != "" || res.queriedByUID
}

func (res *ResolveResult) GetError() error {
	return res.err
}

func (res *ResolveResult) GetBody() *jsonw.Wrapper {
	return res.body
}

func (r *Resolver) ResolveWithBody(input string) ResolveResult {
	return r.resolve(input, true)
}

func (r *Resolver) Resolve(input string) ResolveResult {
	return r.resolve(input, false)
}

func (r *Resolver) resolve(input string, withBody bool) (res ResolveResult) {
	defer r.G().Trace(fmt.Sprintf("Resolving username %q", input), func() error { return res.err })()

	var au AssertionURL
	if au, res.err = ParseAssertionURL(r.G().MakeAssertionContext(), input, false); res.err != nil {
		return res
	}
	res = r.resolveURL(context.TODO(), au, input, withBody, false)
	return res
}

func (r *Resolver) ResolveFullExpression(ctx context.Context, input string) (res ResolveResult) {
	return r.resolveFullExpression(ctx, input, false, false)
}

func (r *Resolver) ResolveFullExpressionNeedUsername(ctx context.Context, input string) (res ResolveResult) {
	return r.resolveFullExpression(ctx, input, false, true)
}

func (r *Resolver) ResolveFullExpressionWithBody(ctx context.Context, input string) (res ResolveResult) {
	return r.resolveFullExpression(ctx, input, true, false)
}

func (r *Resolver) resolveFullExpression(ctx context.Context, input string, withBody bool, needUsername bool) (res ResolveResult) {
	defer r.G().CTrace(ctx, fmt.Sprintf("Resolver#resolveFullExpression(%q)", input), func() error { return res.err })()

	var expr AssertionExpression
	expr, res.err = AssertionParseAndOnly(r.G().MakeAssertionContext(), input)
	if res.err != nil {
		return res
	}
	u := FindBestIdentifyComponentURL(expr)
	if u == nil {
		res.err = ResolutionError{Input: input, Msg: "Cannot find a resolvable factor"}
		return res
	}
	return r.resolveURL(ctx, u, input, withBody, needUsername)
}

func (r *Resolver) getFromDiskCache(ctx context.Context, key string) (ret *ResolveResult) {
	defer r.G().CTraceOK(ctx, fmt.Sprintf("Resolver#getFromDiskCache(%q)", key), func() bool { return ret != nil })()
	var uid keybase1.UID
	found, err := r.G().LocalDb.GetInto(&uid, resolveDbKey(key))
	r.Stats.diskGets++
	if err != nil {
		r.G().Log.CWarningf(ctx, "Problem fetching resolve result from local DB: %s", err)
		return nil
	}
	if !found {
		r.Stats.diskGetMisses++
		return nil
	}
	r.Stats.diskGetHits++
	return &ResolveResult{uid: uid}
}

func (r *Resolver) resolveURL(ctx context.Context, au AssertionURL, input string, withBody bool, needUsername bool) ResolveResult {

	// A standard keybase UID, so it's already resolved... unless we explicitly
	// need it!
	if !needUsername {
		if tmp := au.ToUID(); tmp.Exists() {
			return ResolveResult{uid: tmp}
		}
	}

	ck := au.CacheKey()

	if p := r.getFromMemCache(ctx, ck); p != nil && (!needUsername || len(p.resolvedKbUsername) > 0) {
		return *p
	}

	if p := r.getFromDiskCache(ctx, ck); p != nil && (!needUsername || len(p.resolvedKbUsername) > 0) {
		p.mutable = !au.IsKeybase()
		r.putToMemCache(ck, *p)
		return *p
	}

	res := r.resolveURLViaServerLookup(ctx, au, input, withBody)

	// Cache for a shorter period of time if it's not a Keybase identity
	res.mutable = !au.IsKeybase()
	r.putToMemCache(ck, res)
	r.putToDiskCache(ck, res)

	return res
}

func (r *Resolver) resolveURLViaServerLookup(ctx context.Context, au AssertionURL, input string, withBody bool) (res ResolveResult) {
	defer r.G().CTrace(ctx, fmt.Sprintf("Resolver#resolveURLViaServerLookup(input = %q)", input), func() error { return res.err })()

	var key, val string
	var ares *APIRes
	var l int

	if au.IsKeybase() {
		res.queriedKbUsername = au.GetValue()
	} else if au.IsUID() {
		res.queriedByUID = true
	}

	if key, val, res.err = au.ToLookup(); res.err != nil {
		return
	}

	ha := HTTPArgsFromKeyValuePair(key, S{val})
	ha.Add("multi", I{1})
	fields := "basics"
	if withBody {
		fields += ",public_keys,pictures"
	}
	ha.Add("fields", S{fields})
	ares, res.err = r.G().API.Get(APIArg{
		Endpoint:       "user/lookup",
		NeedSession:    false,
		Args:           ha,
		AppStatusCodes: []int{SCOk, SCNotFound, SCDeleted},
		NetContext:     ctx,
	})

	if res.err != nil {
		r.G().Log.CDebugf(ctx, "API user/lookup %q error: %s", input, res.err)
		return
	}
	switch ares.AppStatus.Code {
	case SCNotFound:
		r.G().Log.CDebugf(ctx, "API user/lookup %q not found", input)
		res.err = NotFoundError{}
		return
	case SCDeleted:
		r.G().Log.CDebugf(ctx, "API user/lookup %q deleted", input)
		res.err = DeletedError{Msg: fmt.Sprintf("user %q deleted", input)}
		return
	}

	var them *jsonw.Wrapper
	if them, res.err = ares.Body.AtKey("them").ToArray(); res.err != nil {
		return
	}

	if l, res.err = them.Len(); res.err != nil {
		return
	}

	if l == 0 {
		res.err = ResolutionError{Input: input, Msg: "No resolution found"}
	} else if l > 1 {
		res.err = ResolutionError{Input: input, Msg: "Identify is ambiguous"}
	} else {
		res.body = them.AtIndex(0)
		res.uid, res.err = GetUID(res.body.AtKey("id"))
		if res.err == nil {
			res.resolvedKbUsername, res.err = res.body.AtPath("basics.username").GetString()
		}
	}

	return
}

type ResolveCacheStats struct {
	misses          int
	timeouts        int
	mutableTimeouts int
	errorTimeouts   int
	hits            int
	diskGets        int
	diskGetHits     int
	diskGetMisses   int
	diskPuts        int
}

type Resolver struct {
	Contextified
	cache   *ramcache.Ramcache
	Stats   ResolveCacheStats
	NowFunc func() time.Time
}

func (s ResolveCacheStats) Eq(m, t, mt, et, h int) bool {
	return (s.misses == m) && (s.timeouts == t) && (s.mutableTimeouts == mt) && (s.errorTimeouts == et) && (s.hits == h)
}

func NewResolver(g *GlobalContext) *Resolver {
	return &Resolver{
		Contextified: NewContextified(g),
		cache:        nil,
		NowFunc:      func() time.Time { return time.Now() },
	}
}

func (r *Resolver) EnableCaching() {
	cache := ramcache.New()
	cache.MaxAge = ResolveCacheMaxAge
	cache.TTL = resolveCacheTTL
	r.cache = cache
}

func (r *Resolver) Shutdown() {
	if r.cache == nil {
		return
	}
	r.cache.Shutdown()
}

func (r *Resolver) getFromMemCache(ctx context.Context, key string) (ret *ResolveResult) {
	defer r.G().CTraceOK(ctx, fmt.Sprintf("Resolver#getFromMemCache(%q)", key), func() bool { return ret != nil })()
	if r.cache == nil {
		return nil
	}
	res, _ := r.cache.Get(key)
	if res == nil {
		r.Stats.misses++
		return nil
	}
	rres, ok := res.(*ResolveResult)
	if !ok {
		r.Stats.misses++
		return nil
	}
	now := r.NowFunc()
	if now.Sub(rres.cachedAt) > ResolveCacheMaxAge {
		r.Stats.timeouts++
		return nil
	}
	if rres.mutable && now.Sub(rres.cachedAt) > ResolveCacheMaxAgeMutable {
		r.Stats.mutableTimeouts++
		return nil
	}
	if rres.err != nil && now.Sub(rres.cachedAt) > resolveCacheMaxAgeErrored {
		r.Stats.errorTimeouts++
		return nil
	}
	r.Stats.hits++
	return rres
}

func resolveDbKey(key string) DbKey {
	return DbKey{
		Typ: DBResolveUsernameToUID,
		Key: NewNormalizedUsername(key).String(),
	}
}

func (r *Resolver) putToDiskCache(key string, res ResolveResult) {
	// Only cache immutable resolutions to disk
	if res.mutable {
		return
	}
	// Don't cache errors
	if res.err != nil {
		return
	}
	r.Stats.diskPuts++
	err := r.G().LocalDb.PutObj(resolveDbKey(key), nil, res.uid)
	if err != nil {
		r.G().Log.Warning("Cannot put resolve result to disk: %s", err)
	}
}

// Put receives a copy of a ResolveResult, clears out the body
// to avoid caching data that can go stale, and stores the result.
func (r *Resolver) putToMemCache(key string, res ResolveResult) {
	if r.cache == nil {
		return
	}
	// Don't cache errors
	if res.err != nil {
		return
	}
	res.cachedAt = r.NowFunc()
	res.body = nil // Don't cache body
	r.cache.Set(key, &res)
}
<|endoftext|>


<commit_before>package venom

import (
	"regexp"
	"strings"

	"github.com/fsamin/go-dump"
	"github.com/sirupsen/logrus"
)

func (v *Venom) initTestCaseContext(ts *TestSuite, tc *TestCase) (TestCaseContext, error) {
	var errContext error
	_, tc.Context, errContext = ts.Templater.ApplyOnMap(tc.Context)
	if errContext != nil {
		return nil, errContext
	}
	tcc, errContext := v.ContextWrap(tc)
	if errContext != nil {
		return nil, errContext
	}
	if err := tcc.Init(); err != nil {
		return nil, err
	}
	return tcc, nil
}

var varRegEx, _ = regexp.Compile("{{.*}}")

//Parse the testcase to find unreplaced and extracted variables
func (v *Venom) parseTestCase(ts *TestSuite, tc *TestCase) ([]string, []string, error) {
	tcc, err := v.initTestCaseContext(ts, tc)
	if err != nil {
		return nil, nil, err
	}
	defer tcc.Close()

	vars := []string{}
	extractedVars := []string{}

	for stepNumber, stepIn := range tc.TestSteps {
		step, erra := ts.Templater.ApplyOnStep(stepNumber, stepIn)
		if erra != nil {
			return nil, nil, erra
		}

		exec, err := v.WrapExecutor(step, tcc)
		if err != nil {
			return nil, nil, err
		}

		withZero, ok := exec.executor.(executorWithZeroValueResult)
		if ok {
			defaultResult := withZero.ZeroValueResult()
			dumpE, err := dump.ToStringMap(defaultResult, dump.WithDefaultLowerCaseFormatter())
			if err != nil {
				return nil, nil, err
			}

			for k := range dumpE {
				extractedVars = append(extractedVars, tc.Name+"."+k)
			}
		}

		dumpE, err := dump.ToStringMap(step, dump.WithDefaultLowerCaseFormatter())
		if err != nil {
			return nil, nil, err
		}

		for k, v := range dumpE {
			if strings.HasPrefix(k, "extracts.") {
				for _, extractVar := range extractPattern.FindAllString(v, -1) {
					varname := extractVar[2:strings.Index(extractVar, "=")]
					var found bool
					for i := 0; i < len(extractedVars); i++ {
						if extractedVars[i] == varname {
							found = true
							break
						}
					}
					if !found {
						extractedVars = append(extractedVars, tc.Name+"."+varname)
					}
				}
				continue
			}

			if varRegEx.MatchString(v) {
				var found bool
				for i := 0; i < len(vars); i++ {
					if vars[i] == k {
						found = true
						break
					}
				}

				for i := 0; i < len(extractedVars); i++ {
					s := varRegEx.FindString(v)
					prefix := "{{." + extractedVars[i]
					if strings.HasPrefix(s, prefix) {
						found = true
						break
					}
				}
				if !found {
					s := varRegEx.FindString(v)
					s = strings.Replace(s, "{{.", "", -1)
					s = strings.Replace(s, "}}", "", -1)
					vars = append(vars, s)
				}
			}
		}

	}
	return vars, extractedVars, nil
}

func (v *Venom) runTestCase(ts *TestSuite, tc *TestCase, l Logger) {
	tcc, err := v.initTestCaseContext(ts, tc)
	if err != nil {
		tc.Errors = append(tc.Errors, Failure{Value: RemoveNotPrintableChar(err.Error())})
		return
	}
	defer tcc.Close()

	if _l, ok := l.(*logrus.Entry); ok {
		l = _l.WithField("x.testcase", tc.Name)
	}

	ts.Templater.Add("", map[string]string{"venom.testcase": tc.Name})
	for stepNumber, stepIn := range tc.TestSteps {
		step, erra := ts.Templater.ApplyOnStep(stepNumber, stepIn)
		if erra != nil {
			tc.Errors = append(tc.Errors, Failure{Value: RemoveNotPrintableChar(erra.Error())})
			break
		}

		e, err := v.WrapExecutor(step, tcc)
		if err != nil {
			tc.Errors = append(tc.Errors, Failure{Value: RemoveNotPrintableChar(err.Error())})
			break
		}

		v.RunTestStep(tcc, e, ts, tc, stepNumber, step, l)

		if len(tc.Failures) > 0 || len(tc.Errors) > 0 {
			break
		}
	}
}
<commit_msg>fix(venom): add vars to extracted vars check func (#165)<commit_after>package venom

import (
	"regexp"
	"strings"

	"github.com/fsamin/go-dump"
	"github.com/sirupsen/logrus"
)

func (v *Venom) initTestCaseContext(ts *TestSuite, tc *TestCase) (TestCaseContext, error) {
	var errContext error
	_, tc.Context, errContext = ts.Templater.ApplyOnMap(tc.Context)
	if errContext != nil {
		return nil, errContext
	}
	tcc, errContext := v.ContextWrap(tc)
	if errContext != nil {
		return nil, errContext
	}
	if err := tcc.Init(); err != nil {
		return nil, err
	}
	return tcc, nil
}

var varRegEx, _ = regexp.Compile("{{.*}}")

//Parse the testcase to find unreplaced and extracted variables
func (v *Venom) parseTestCase(ts *TestSuite, tc *TestCase) ([]string, []string, error) {
	tcc, err := v.initTestCaseContext(ts, tc)
	if err != nil {
		return nil, nil, err
	}
	defer tcc.Close()

	vars := []string{}
	extractedVars := make([]string, 0, len(ts.Vars))

	for k := range ts.Vars {
		extractedVars = append(extractedVars, k)
	}

	for stepNumber, stepIn := range tc.TestSteps {
		step, erra := ts.Templater.ApplyOnStep(stepNumber, stepIn)
		if erra != nil {
			return nil, nil, erra
		}

		exec, err := v.WrapExecutor(step, tcc)
		if err != nil {
			return nil, nil, err
		}

		withZero, ok := exec.executor.(executorWithZeroValueResult)
		if ok {
			defaultResult := withZero.ZeroValueResult()
			dumpE, err := dump.ToStringMap(defaultResult, dump.WithDefaultLowerCaseFormatter())
			if err != nil {
				return nil, nil, err
			}

			for k := range dumpE {
				extractedVars = append(extractedVars, tc.Name+"."+k)
			}
		}

		dumpE, err := dump.ToStringMap(step, dump.WithDefaultLowerCaseFormatter())
		if err != nil {
			return nil, nil, err
		}

		for k, v := range dumpE {
			if strings.HasPrefix(k, "extracts.") {
				for _, extractVar := range extractPattern.FindAllString(v, -1) {
					varname := extractVar[2:strings.Index(extractVar, "=")]
					var found bool
					for i := 0; i < len(extractedVars); i++ {
						if extractedVars[i] == varname {
							found = true
							break
						}
					}
					if !found {
						extractedVars = append(extractedVars, tc.Name+"."+varname)
					}
				}
				continue
			}

			if varRegEx.MatchString(v) {
				var found bool
				for i := 0; i < len(vars); i++ {
					if vars[i] == k {
						found = true
						break
					}
				}

				for i := 0; i < len(extractedVars); i++ {
					s := varRegEx.FindString(v)
					prefix := "{{." + extractedVars[i]
					if strings.HasPrefix(s, prefix) {
						found = true
						break
					}
				}
				if !found {
					s := varRegEx.FindString(v)
					s = strings.Replace(s, "{{.", "", -1)
					s = strings.Replace(s, "}}", "", -1)
					vars = append(vars, s)
				}
			}
		}

	}
	return vars, extractedVars, nil
}

func (v *Venom) runTestCase(ts *TestSuite, tc *TestCase, l Logger) {
	tcc, err := v.initTestCaseContext(ts, tc)
	if err != nil {
		tc.Errors = append(tc.Errors, Failure{Value: RemoveNotPrintableChar(err.Error())})
		return
	}
	defer tcc.Close()

	if _l, ok := l.(*logrus.Entry); ok {
		l = _l.WithField("x.testcase", tc.Name)
	}

	ts.Templater.Add("", map[string]string{"venom.testcase": tc.Name})
	for stepNumber, stepIn := range tc.TestSteps {
		step, erra := ts.Templater.ApplyOnStep(stepNumber, stepIn)
		if erra != nil {
			tc.Errors = append(tc.Errors, Failure{Value: RemoveNotPrintableChar(erra.Error())})
			break
		}

		e, err := v.WrapExecutor(step, tcc)
		if err != nil {
			tc.Errors = append(tc.Errors, Failure{Value: RemoveNotPrintableChar(err.Error())})
			break
		}

		v.RunTestStep(tcc, e, ts, tc, stepNumber, step, l)

		if len(tc.Failures) > 0 || len(tc.Errors) > 0 {
			break
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2012-2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package uniter_test

import (
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"

	gc "launchpad.net/gocheck"

	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/state/api/params"
	jc "launchpad.net/juju-core/testing/checkers"
)

// These tests are copies of the old git-deployer-related tests, to test that
// the uniter with the manifest-deployer work patched out still works how it
// used to; thus demonstrating that the *other* tests that verify manifest
// deployer behaviour in the presence of an old git deployer are working against
// an accurate representation of the base state.
// The only actual behaviour change is that we no longer commit changes after
// each hook execution; this is reflected by checking that it's dirty in a couple
// of places where we once checked it was not.

var upgradeGitConflictsTests = []uniterTest{
	// Upgrade scenarios - handling conflicts.
	ut(
		"upgrade: conflicting files",
		startGitUpgradeError{},

		// NOTE: this is just dumbly committing the conflicts, but AFAICT this
		// is the only reasonable solution; if the user tells us it's resolved
		// we have to take their word for it.
		resolveError{state.ResolvedNoHooks},
		waitHooks{"upgrade-charm", "config-changed"},
		waitUnit{
			status: params.StatusStarted,
			charm:  1,
		},
		verifyGitCharm{revision: 1},
	), ut(
		`upgrade: conflicting directories`,
		createCharm{
			customize: func(c *gc.C, ctx *context, path string) {
				err := os.Mkdir(filepath.Join(path, "data"), 0755)
				c.Assert(err, gc.IsNil)
				appendHook(c, path, "start", "echo DATA > data/newfile")
			},
		},
		serveCharm{},
		createUniter{},
		waitUnit{
			status: params.StatusStarted,
		},
		waitHooks{"install", "config-changed", "start"},
		verifyGitCharm{},

		createCharm{
			revision: 1,
			customize: func(c *gc.C, ctx *context, path string) {
				data := filepath.Join(path, "data")
				err := ioutil.WriteFile(data, []byte("<nelson>ha ha</nelson>"), 0644)
				c.Assert(err, gc.IsNil)
			},
		},
		serveCharm{},
		upgradeCharm{revision: 1},
		waitUnit{
			status: params.StatusError,
			info:   "upgrade failed",
			charm:  1,
		},
		verifyWaiting{},
		verifyGitCharm{dirty: true},

		resolveError{state.ResolvedNoHooks},
		waitHooks{"upgrade-charm", "config-changed"},
		waitUnit{
			status: params.StatusStarted,
			charm:  1,
		},
		verifyGitCharm{revision: 1},
	), ut(
		"upgrade conflict resolved with forced upgrade",
		startGitUpgradeError{},
		createCharm{
			revision: 2,
			customize: func(c *gc.C, ctx *context, path string) {
				otherdata := filepath.Join(path, "otherdata")
				err := ioutil.WriteFile(otherdata, []byte("blah"), 0644)
				c.Assert(err, gc.IsNil)
			},
		},
		serveCharm{},
		upgradeCharm{revision: 2, forced: true},
		waitUnit{
			status: params.StatusStarted,
			charm:  2,
		},
		waitHooks{"upgrade-charm", "config-changed"},
		verifyGitCharm{revision: 2},
		custom{func(c *gc.C, ctx *context) {
			// otherdata should exist (in v2)
			otherdata, err := ioutil.ReadFile(filepath.Join(ctx.path, "charm", "otherdata"))
			c.Assert(err, gc.IsNil)
			c.Assert(string(otherdata), gc.Equals, "blah")

			// ignore should not (only in v1)
			_, err = os.Stat(filepath.Join(ctx.path, "charm", "ignore"))
			c.Assert(err, jc.Satisfies, os.IsNotExist)

			// data should contain what was written in the start hook
			data, err := ioutil.ReadFile(filepath.Join(ctx.path, "charm", "data"))
			c.Assert(err, gc.IsNil)
			c.Assert(string(data), gc.Equals, "STARTDATA\n")
		}},
	), ut(
		"upgrade conflict service dying",
		startGitUpgradeError{},
		serviceDying,
		verifyWaiting{},
		resolveError{state.ResolvedNoHooks},
		waitHooks{"upgrade-charm", "config-changed", "stop"},
		waitUniterDead{},
	), ut(
		"upgrade conflict unit dying",
		startGitUpgradeError{},
		unitDying,
		verifyWaiting{},
		resolveError{state.ResolvedNoHooks},
		waitHooks{"upgrade-charm", "config-changed", "stop"},
		waitUniterDead{},
	), ut(
		"upgrade conflict unit dead",
		startGitUpgradeError{},
		unitDead,
		waitUniterDead{},
		waitHooks{},
	),
}

func (s *UniterSuite) TestUniterUpgradeGitConflicts(c *gc.C) {
	patchedTests := make([]uniterTest, len(upgradeGitConflictsTests))
	for i, test := range upgradeGitConflictsTests {
		patchedTests[i] = ut(test.summary, prepareGitUniter{test.steps})
	}
	s.runUniterTests(c, patchedTests)
}

type verifyGitCharm struct {
	revision int
	dirty    bool
}

func (s verifyGitCharm) step(c *gc.C, ctx *context) {
	charmPath := filepath.Join(ctx.path, "charm")
	if !s.dirty {
		revisionPath := filepath.Join(charmPath, "revision")
		content, err := ioutil.ReadFile(revisionPath)
		c.Assert(err, gc.IsNil)
		c.Assert(string(content), gc.Equals, strconv.Itoa(s.revision))
		err = ctx.unit.Refresh()
		c.Assert(err, gc.IsNil)
		url, ok := ctx.unit.CharmURL()
		c.Assert(ok, gc.Equals, true)
		c.Assert(url, gc.DeepEquals, curl(s.revision))
	}

	// Before we try to check the git status, make sure expected hooks are all
	// complete, to prevent the test and the uniter interfering with each other.
	step(c, ctx, waitHooks{})
	step(c, ctx, waitHooks{})
	cmd := exec.Command("git", "status")
	cmd.Dir = filepath.Join(ctx.path, "charm")
	out, err := cmd.CombinedOutput()
	c.Assert(err, gc.IsNil)
	cmp := gc.Matches
	if s.dirty {
		cmp = gc.Not(gc.Matches)
	}
	c.Assert(string(out), cmp, "(# )?On branch master\nnothing to commit.*\n")
}

type startGitUpgradeError struct{}

func (s startGitUpgradeError) step(c *gc.C, ctx *context) {
	steps := []stepper{
		createCharm{
			customize: func(c *gc.C, ctx *context, path string) {
				appendHook(c, path, "start", "echo STARTDATA > data")
			},
		},
		serveCharm{},
		createUniter{},
		waitUnit{
			status: params.StatusStarted,
		},
		waitHooks{"install", "config-changed", "start"},
		verifyGitCharm{dirty: true},

		createCharm{
			revision: 1,
			customize: func(c *gc.C, ctx *context, path string) {
				data := filepath.Join(path, "data")
				err := ioutil.WriteFile(data, []byte("<nelson>ha ha</nelson>"), 0644)
				c.Assert(err, gc.IsNil)
				ignore := filepath.Join(path, "ignore")
				err = ioutil.WriteFile(ignore, []byte("anything"), 0644)
				c.Assert(err, gc.IsNil)
			},
		},
		serveCharm{},
		upgradeCharm{revision: 1},
		waitUnit{
			status: params.StatusError,
			info:   "upgrade failed",
			charm:  1,
		},
		verifyWaiting{},
		verifyGitCharm{dirty: true},
	}
	for _, s_ := range steps {
		step(c, ctx, s_)
	}
}
<commit_msg>and bring old tests in line with disable-hook-snapshot<commit_after>// Copyright 2012-2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package uniter_test

import (
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"

	gc "launchpad.net/gocheck"

	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/state/api/params"
	jc "launchpad.net/juju-core/testing/checkers"
)

// These tests are copies of the old git-deployer-related tests, to test that
// the uniter with the manifest-deployer work patched out still works how it
// used to; thus demonstrating that the *other* tests that verify manifest
// deployer behaviour in the presence of an old git deployer are working against
// an accurate representation of the base state.
// The only actual behaviour change is that we no longer commit changes after
// each hook execution; this is reflected by checking that it's dirty in a couple
// of places where we once checked it was not.

var upgradeGitConflictsTests = []uniterTest{
	// Upgrade scenarios - handling conflicts.
	ut(
		"upgrade: conflicting files",
		startGitUpgradeError{},

		// NOTE: this is just dumbly committing the conflicts, but AFAICT this
		// is the only reasonable solution; if the user tells us it's resolved
		// we have to take their word for it.
		resolveError{state.ResolvedNoHooks},
		waitHooks{"upgrade-charm", "config-changed"},
		waitUnit{
			status: params.StatusStarted,
			charm:  1,
		},
		verifyGitCharm{revision: 1},
	), ut(
		`upgrade: conflicting directories`,
		createCharm{
			customize: func(c *gc.C, ctx *context, path string) {
				err := os.Mkdir(filepath.Join(path, "data"), 0755)
				c.Assert(err, gc.IsNil)
				appendHook(c, path, "start", "echo DATA > data/newfile")
			},
		},
		serveCharm{},
		createUniter{},
		waitUnit{
			status: params.StatusStarted,
		},
		waitHooks{"install", "config-changed", "start"},
		verifyGitCharm{dirty: true},

		createCharm{
			revision: 1,
			customize: func(c *gc.C, ctx *context, path string) {
				data := filepath.Join(path, "data")
				err := ioutil.WriteFile(data, []byte("<nelson>ha ha</nelson>"), 0644)
				c.Assert(err, gc.IsNil)
			},
		},
		serveCharm{},
		upgradeCharm{revision: 1},
		waitUnit{
			status: params.StatusError,
			info:   "upgrade failed",
			charm:  1,
		},
		verifyWaiting{},
		verifyGitCharm{dirty: true},

		resolveError{state.ResolvedNoHooks},
		waitHooks{"upgrade-charm", "config-changed"},
		waitUnit{
			status: params.StatusStarted,
			charm:  1,
		},
		verifyGitCharm{revision: 1},
	), ut(
		"upgrade conflict resolved with forced upgrade",
		startGitUpgradeError{},
		createCharm{
			revision: 2,
			customize: func(c *gc.C, ctx *context, path string) {
				otherdata := filepath.Join(path, "otherdata")
				err := ioutil.WriteFile(otherdata, []byte("blah"), 0644)
				c.Assert(err, gc.IsNil)
			},
		},
		serveCharm{},
		upgradeCharm{revision: 2, forced: true},
		waitUnit{
			status: params.StatusStarted,
			charm:  2,
		},
		waitHooks{"upgrade-charm", "config-changed"},
		verifyGitCharm{revision: 2},
		custom{func(c *gc.C, ctx *context) {
			// otherdata should exist (in v2)
			otherdata, err := ioutil.ReadFile(filepath.Join(ctx.path, "charm", "otherdata"))
			c.Assert(err, gc.IsNil)
			c.Assert(string(otherdata), gc.Equals, "blah")

			// ignore should not (only in v1)
			_, err = os.Stat(filepath.Join(ctx.path, "charm", "ignore"))
			c.Assert(err, jc.Satisfies, os.IsNotExist)

			// data should contain what was written in the start hook
			data, err := ioutil.ReadFile(filepath.Join(ctx.path, "charm", "data"))
			c.Assert(err, gc.IsNil)
			c.Assert(string(data), gc.Equals, "STARTDATA\n")
		}},
	), ut(
		"upgrade conflict service dying",
		startGitUpgradeError{},
		serviceDying,
		verifyWaiting{},
		resolveError{state.ResolvedNoHooks},
		waitHooks{"upgrade-charm", "config-changed", "stop"},
		waitUniterDead{},
	), ut(
		"upgrade conflict unit dying",
		startGitUpgradeError{},
		unitDying,
		verifyWaiting{},
		resolveError{state.ResolvedNoHooks},
		waitHooks{"upgrade-charm", "config-changed", "stop"},
		waitUniterDead{},
	), ut(
		"upgrade conflict unit dead",
		startGitUpgradeError{},
		unitDead,
		waitUniterDead{},
		waitHooks{},
	),
}

func (s *UniterSuite) TestUniterUpgradeGitConflicts(c *gc.C) {
	patchedTests := make([]uniterTest, len(upgradeGitConflictsTests))
	for i, test := range upgradeGitConflictsTests {
		patchedTests[i] = ut(test.summary, prepareGitUniter{test.steps})
	}
	s.runUniterTests(c, patchedTests)
}

type verifyGitCharm struct {
	revision int
	dirty    bool
}

func (s verifyGitCharm) step(c *gc.C, ctx *context) {
	charmPath := filepath.Join(ctx.path, "charm")
	if !s.dirty {
		revisionPath := filepath.Join(charmPath, "revision")
		content, err := ioutil.ReadFile(revisionPath)
		c.Assert(err, gc.IsNil)
		c.Assert(string(content), gc.Equals, strconv.Itoa(s.revision))
		err = ctx.unit.Refresh()
		c.Assert(err, gc.IsNil)
		url, ok := ctx.unit.CharmURL()
		c.Assert(ok, gc.Equals, true)
		c.Assert(url, gc.DeepEquals, curl(s.revision))
	}

	// Before we try to check the git status, make sure expected hooks are all
	// complete, to prevent the test and the uniter interfering with each other.
	step(c, ctx, waitHooks{})
	step(c, ctx, waitHooks{})
	cmd := exec.Command("git", "status")
	cmd.Dir = filepath.Join(ctx.path, "charm")
	out, err := cmd.CombinedOutput()
	c.Assert(err, gc.IsNil)
	cmp := gc.Matches
	if s.dirty {
		cmp = gc.Not(gc.Matches)
	}
	c.Assert(string(out), cmp, "(# )?On branch master\nnothing to commit.*\n")
}

type startGitUpgradeError struct{}

func (s startGitUpgradeError) step(c *gc.C, ctx *context) {
	steps := []stepper{
		createCharm{
			customize: func(c *gc.C, ctx *context, path string) {
				appendHook(c, path, "start", "echo STARTDATA > data")
			},
		},
		serveCharm{},
		createUniter{},
		waitUnit{
			status: params.StatusStarted,
		},
		waitHooks{"install", "config-changed", "start"},
		verifyGitCharm{dirty: true},

		createCharm{
			revision: 1,
			customize: func(c *gc.C, ctx *context, path string) {
				data := filepath.Join(path, "data")
				err := ioutil.WriteFile(data, []byte("<nelson>ha ha</nelson>"), 0644)
				c.Assert(err, gc.IsNil)
				ignore := filepath.Join(path, "ignore")
				err = ioutil.WriteFile(ignore, []byte("anything"), 0644)
				c.Assert(err, gc.IsNil)
			},
		},
		serveCharm{},
		upgradeCharm{revision: 1},
		waitUnit{
			status: params.StatusError,
			info:   "upgrade failed",
			charm:  1,
		},
		verifyWaiting{},
		verifyGitCharm{dirty: true},
	}
	for _, s_ := range steps {
		step(c, ctx, s_)
	}
}
<|endoftext|>


<commit_before>package sarama

import (
	"fmt"
	"time"
)

// Protocol, http://kafka.apache.org/protocol.html
// v1
// v2 = v3 = v4
// v5 = v6 = v7
// Produce Response (Version: 7) => [responses] throttle_time_ms
//   responses => topic [partition_responses]
//     topic => STRING
//     partition_responses => partition error_code base_offset log_append_time log_start_offset
//       partition => INT32
//       error_code => INT16
//       base_offset => INT64
//       log_append_time => INT64
//       log_start_offset => INT64
//   throttle_time_ms => INT32

// partition_responses in protocol
type ProduceResponseBlock struct {
	Err         KError    // v0, error_code
	Offset      int64     // v0, base_offset
	Timestamp   time.Time // v2, log_append_time, and the broker is configured with `LogAppendTime`
	StartOffset int64     // v5, log_start_offset
}

func (b *ProduceResponseBlock) decode(pd packetDecoder, version int16) (err error) {
	tmp, err := pd.getInt16()
	if err != nil {
		return err
	}
	b.Err = KError(tmp)

	b.Offset, err = pd.getInt64()
	if err != nil {
		return err
	}

	if version >= 2 {
		if millis, err := pd.getInt64(); err != nil {
			return err
		} else if millis != -1 {
			b.Timestamp = time.Unix(millis/1000, (millis%1000)*int64(time.Millisecond))
		}
	}

	if version >= 5 {
		b.StartOffset, err = pd.getInt64()
		if err != nil {
			return err
		}
	}

	return nil
}

func (b *ProduceResponseBlock) encode(pe packetEncoder, version int16) (err error) {
	pe.putInt16(int16(b.Err))
	pe.putInt64(b.Offset)

	if version >= 2 {
		timestamp := int64(-1)
		if !b.Timestamp.Before(time.Unix(0, 0)) {
			timestamp = b.Timestamp.UnixNano() / int64(time.Millisecond)
		} else if !b.Timestamp.IsZero() {
			return PacketEncodingError{fmt.Sprintf("invalid timestamp (%v)", b.Timestamp)}
		}
		pe.putInt64(timestamp)
	}

	if version >= 5 {
		pe.putInt64(b.StartOffset)
	}

	return nil
}

type ProduceResponse struct {
	Blocks       map[string]map[int32]*ProduceResponseBlock // v0, responses
	Version      int16
	ThrottleTime time.Duration // v1, throttle_time_ms
}

func (r *ProduceResponse) decode(pd packetDecoder, version int16) (err error) {
	r.Version = version

	numTopics, err := pd.getArrayLength()
	if err != nil {
		return err
	}

	r.Blocks = make(map[string]map[int32]*ProduceResponseBlock, numTopics)
	for i := 0; i < numTopics; i++ {
		name, err := pd.getString()
		if err != nil {
			return err
		}

		numBlocks, err := pd.getArrayLength()
		if err != nil {
			return err
		}

		r.Blocks[name] = make(map[int32]*ProduceResponseBlock, numBlocks)

		for j := 0; j < numBlocks; j++ {
			id, err := pd.getInt32()
			if err != nil {
				return err
			}

			block := new(ProduceResponseBlock)
			err = block.decode(pd, version)
			if err != nil {
				return err
			}
			r.Blocks[name][id] = block
		}
	}

	if r.Version >= 1 {
		millis, err := pd.getInt32()
		if err != nil {
			return err
		}

		r.ThrottleTime = time.Duration(millis) * time.Millisecond
	}

	return nil
}

func (r *ProduceResponse) encode(pe packetEncoder) error {
	err := pe.putArrayLength(len(r.Blocks))
	if err != nil {
		return err
	}
	for topic, partitions := range r.Blocks {
		err = pe.putString(topic)
		if err != nil {
			return err
		}
		err = pe.putArrayLength(len(partitions))
		if err != nil {
			return err
		}
		for id, prb := range partitions {
			pe.putInt32(id)
			err = prb.encode(pe, r.Version)
			if err != nil {
				return err
			}
		}
	}

	if r.Version >= 1 {
		pe.putInt32(int32(r.ThrottleTime / time.Millisecond))
	}
	return nil
}

func (r *ProduceResponse) key() int16 {
	return 0
}

func (r *ProduceResponse) version() int16 {
	return r.Version
}

func (r *ProduceResponse) GetBlock(topic string, partition int32) *ProduceResponseBlock {
	if r.Blocks == nil {
		return nil
	}

	if r.Blocks[topic] == nil {
		return nil
	}

	return r.Blocks[topic][partition]
}

// Testing API

func (r *ProduceResponse) AddTopicPartition(topic string, partition int32, err KError) {
	if r.Blocks == nil {
		r.Blocks = make(map[string]map[int32]*ProduceResponseBlock)
	}
	byTopic, ok := r.Blocks[topic]
	if !ok {
		byTopic = make(map[int32]*ProduceResponseBlock)
		r.Blocks[topic] = byTopic
	}
	block := &ProduceResponseBlock{
		Err: err,
	}
	if r.Version >= 2 {
		block.Timestamp = time.Now()
	}
	byTopic[partition] = block
}
<commit_msg>produce_response.go: remove unused functions<commit_after>package sarama

import (
	"fmt"
	"time"
)

// Protocol, http://kafka.apache.org/protocol.html
// v1
// v2 = v3 = v4
// v5 = v6 = v7
// Produce Response (Version: 7) => [responses] throttle_time_ms
//   responses => topic [partition_responses]
//     topic => STRING
//     partition_responses => partition error_code base_offset log_append_time log_start_offset
//       partition => INT32
//       error_code => INT16
//       base_offset => INT64
//       log_append_time => INT64
//       log_start_offset => INT64
//   throttle_time_ms => INT32

// partition_responses in protocol
type ProduceResponseBlock struct {
	Err         KError    // v0, error_code
	Offset      int64     // v0, base_offset
	Timestamp   time.Time // v2, log_append_time, and the broker is configured with `LogAppendTime`
	StartOffset int64     // v5, log_start_offset
}

func (b *ProduceResponseBlock) decode(pd packetDecoder, version int16) (err error) {
	tmp, err := pd.getInt16()
	if err != nil {
		return err
	}
	b.Err = KError(tmp)

	b.Offset, err = pd.getInt64()
	if err != nil {
		return err
	}

	if version >= 2 {
		if millis, err := pd.getInt64(); err != nil {
			return err
		} else if millis != -1 {
			b.Timestamp = time.Unix(millis/1000, (millis%1000)*int64(time.Millisecond))
		}
	}

	if version >= 5 {
		b.StartOffset, err = pd.getInt64()
		if err != nil {
			return err
		}
	}

	return nil
}

func (b *ProduceResponseBlock) encode(pe packetEncoder, version int16) (err error) {
	pe.putInt16(int16(b.Err))
	pe.putInt64(b.Offset)

	if version >= 2 {
		timestamp := int64(-1)
		if !b.Timestamp.Before(time.Unix(0, 0)) {
			timestamp = b.Timestamp.UnixNano() / int64(time.Millisecond)
		} else if !b.Timestamp.IsZero() {
			return PacketEncodingError{fmt.Sprintf("invalid timestamp (%v)", b.Timestamp)}
		}
		pe.putInt64(timestamp)
	}

	if version >= 5 {
		pe.putInt64(b.StartOffset)
	}

	return nil
}

type ProduceResponse struct {
	Blocks       map[string]map[int32]*ProduceResponseBlock // v0, responses
	Version      int16
	ThrottleTime time.Duration // v1, throttle_time_ms
}

func (r *ProduceResponse) decode(pd packetDecoder, version int16) (err error) {
	r.Version = version

	numTopics, err := pd.getArrayLength()
	if err != nil {
		return err
	}

	r.Blocks = make(map[string]map[int32]*ProduceResponseBlock, numTopics)
	for i := 0; i < numTopics; i++ {
		name, err := pd.getString()
		if err != nil {
			return err
		}

		numBlocks, err := pd.getArrayLength()
		if err != nil {
			return err
		}

		r.Blocks[name] = make(map[int32]*ProduceResponseBlock, numBlocks)

		for j := 0; j < numBlocks; j++ {
			id, err := pd.getInt32()
			if err != nil {
				return err
			}

			block := new(ProduceResponseBlock)
			err = block.decode(pd, version)
			if err != nil {
				return err
			}
			r.Blocks[name][id] = block
		}
	}

	if r.Version >= 1 {
		millis, err := pd.getInt32()
		if err != nil {
			return err
		}

		r.ThrottleTime = time.Duration(millis) * time.Millisecond
	}

	return nil
}

func (r *ProduceResponse) encode(pe packetEncoder) error {
	err := pe.putArrayLength(len(r.Blocks))
	if err != nil {
		return err
	}
	for topic, partitions := range r.Blocks {
		err = pe.putString(topic)
		if err != nil {
			return err
		}
		err = pe.putArrayLength(len(partitions))
		if err != nil {
			return err
		}
		for id, prb := range partitions {
			pe.putInt32(id)
			err = prb.encode(pe, r.Version)
			if err != nil {
				return err
			}
		}
	}

	if r.Version >= 1 {
		pe.putInt32(int32(r.ThrottleTime / time.Millisecond))
	}
	return nil
}

func (r *ProduceResponse) GetBlock(topic string, partition int32) *ProduceResponseBlock {
	if r.Blocks == nil {
		return nil
	}

	if r.Blocks[topic] == nil {
		return nil
	}

	return r.Blocks[topic][partition]
}

// Testing API

func (r *ProduceResponse) AddTopicPartition(topic string, partition int32, err KError) {
	if r.Blocks == nil {
		r.Blocks = make(map[string]map[int32]*ProduceResponseBlock)
	}
	byTopic, ok := r.Blocks[topic]
	if !ok {
		byTopic = make(map[int32]*ProduceResponseBlock)
		r.Blocks[topic] = byTopic
	}
	block := &ProduceResponseBlock{
		Err: err,
	}
	if r.Version >= 2 {
		block.Timestamp = time.Now()
	}
	byTopic[partition] = block
}
<|endoftext|>


<commit_before>// Copyright 2017 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package service

import (
	"fmt"
	"strings"

	"github.com/keybase/client/go/chat"
	"github.com/keybase/client/go/chat/globals"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/protocol/chat1"
	keybase1 "github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/client/go/teams"
	"github.com/keybase/go-framed-msgpack-rpc/rpc"
	"golang.org/x/net/context"
)

type TeamsHandler struct {
	*BaseHandler
	globals.Contextified
	gregor *gregorHandler
	connID libkb.ConnectionID
}

var _ keybase1.TeamsInterface = (*TeamsHandler)(nil)

func NewTeamsHandler(xp rpc.Transporter, id libkb.ConnectionID, g *globals.Context, gregor *gregorHandler) *TeamsHandler {
	return &TeamsHandler{
		BaseHandler:  NewBaseHandler(g.ExternalG(), xp),
		Contextified: globals.NewContextified(g),
		gregor:       gregor,
		connID:       id,
	}
}

func (h *TeamsHandler) TeamCreate(ctx context.Context, arg keybase1.TeamCreateArg) (res keybase1.TeamCreateResult, err error) {
	defer h.G().CTraceTimed(ctx, fmt.Sprintf("TeamCreate(%s)", arg.Name), func() error { return err })()
	teamName, err := keybase1.TeamNameFromString(arg.Name)
	if err != nil {
		return res, err
	}
	if !teamName.IsRootTeam() {
		h.G().Log.CDebugf(ctx, "TeamCreate: creating a new subteam: %s", arg.Name)
		if teamName.Depth() == 0 {
			return res, fmt.Errorf("empty team name")
		}
		parentName, err := teamName.Parent()
		if err != nil {
			return res, err
		}
		if _, err = teams.CreateSubteam(ctx, h.G().ExternalG(), string(teamName.LastPart()), parentName); err != nil {
			return res, err
		}
	} else {
		if err := teams.CreateRootTeam(ctx, h.G().ExternalG(), teamName.String()); err != nil {
			return res, err
		}
		res.CreatorAdded = true
	}

	if arg.SendChatNotification {
		res.ChatSent = h.sendTeamChatWelcomeMessage(ctx, teamName.String(), h.G().Env.GetUsername().String())
	}
	return res, nil
}

func (h *TeamsHandler) TeamGet(ctx context.Context, arg keybase1.TeamGetArg) (res keybase1.TeamDetails, err error) {
	defer h.G().CTraceTimed(ctx, fmt.Sprintf("TeamGet(%s)", arg.Name), func() error { return err })()
	return teams.Details(ctx, h.G().ExternalG(), arg.Name, arg.ForceRepoll)
}

func (h *TeamsHandler) TeamList(ctx context.Context, arg keybase1.TeamListArg) (res keybase1.AnnotatedTeamList, err error) {
	defer h.G().CTraceTimed(ctx, fmt.Sprintf("TeamList(%s)", arg.UserAssertion), func() error { return err })()
	x, err := teams.List(ctx, h.G().ExternalG(), arg)
	if err != nil {
		return keybase1.AnnotatedTeamList{}, err
	}
	return *x, nil
}

func (h *TeamsHandler) TeamChangeMembership(ctx context.Context, arg keybase1.TeamChangeMembershipArg) error {
	return teams.ChangeRoles(ctx, h.G().ExternalG(), arg.Name, arg.Req)
}

func (h *TeamsHandler) sendTeamChatWelcomeMessage(ctx context.Context, team, user string) (res bool) {
	var err error
	defer func() {
		if err != nil {
			h.G().Log.CWarningf(ctx, "failed to send team welcome message: %s", err.Error())
		}
	}()
	teamDetails, err := teams.Details(ctx, h.G().ExternalG(), team, true)
	if err != nil {
		return false
	}

	var ownerNames, adminNames, writerNames, readerNames []string
	for _, owner := range teamDetails.Members.Owners {
		ownerNames = append(ownerNames, owner.Username)
	}
	for _, admin := range teamDetails.Members.Admins {
		adminNames = append(adminNames, admin.Username)
	}
	for _, writer := range teamDetails.Members.Writers {
		writerNames = append(writerNames, writer.Username)
	}
	for _, reader := range teamDetails.Members.Readers {
		readerNames = append(readerNames, reader.Username)
	}
	var lines []string
	if len(ownerNames) > 0 {
		lines = append(lines, fmt.Sprintf("  owners: %s", strings.Join(ownerNames, ",")))
	}
	if len(adminNames) > 0 {
		lines = append(lines, fmt.Sprintf("  admins: %s", strings.Join(adminNames, ",")))
	}
	if len(writerNames) > 0 {
		lines = append(lines, fmt.Sprintf("  writers: %s", strings.Join(writerNames, ",")))
	}
	if len(readerNames) > 0 {
		lines = append(lines, fmt.Sprintf("  readers: %s", strings.Join(readerNames, ",")))
	}
	memberBody := strings.Join(lines, "\n")
	body := fmt.Sprintf("Hello @channel! I've just added @%s to this team. Current members:\n\n```%s```\n\n_More info on teams:_ keybase.io/blog/introducing-keybase-teams\n_To leave this team, visit the team tab or run `keybase team leave %s`_",
		user, memberBody, team)

	// Ensure we have chat available, since TeamAddMember may also be
	// coming from a standalone launch.
	h.G().ExternalG().StartStandaloneChat()

	if err = chat.SendTextByName(ctx, h.G(), team, &chat.DefaultTeamTopic, chat1.ConversationMembersType_TEAM,
		keybase1.TLFIdentifyBehavior_CHAT_CLI, body, h.gregor.GetClient); err != nil {
		return false
	}

	return true
}

func (h *TeamsHandler) TeamAddMember(ctx context.Context, arg keybase1.TeamAddMemberArg) (res keybase1.TeamAddMemberResult, err error) {
	defer h.G().CTraceTimed(ctx, fmt.Sprintf("TeamAddMember(%s,%s)", arg.Name, arg.Username),
		func() error { return err })()
	if arg.Email != "" {
		if err := teams.InviteEmailMember(ctx, h.G().ExternalG(), arg.Name, arg.Email, arg.Role); err != nil {
			return keybase1.TeamAddMemberResult{}, err
		}
		return keybase1.TeamAddMemberResult{Invited: true, EmailSent: true}, nil
	}
	result, err := teams.AddMember(ctx, h.G().ExternalG(), arg.Name, arg.Username, arg.Role)
	if err != nil {
		return keybase1.TeamAddMemberResult{}, err
	}
	if !arg.SendChatNotification {
		return result, nil
	}

	if result.Invited {
		return result, nil
	}

	result.ChatSent = h.sendTeamChatWelcomeMessage(ctx, arg.Name, result.User.Username)
	return result, nil
}

func (h *TeamsHandler) TeamRemoveMember(ctx context.Context, arg keybase1.TeamRemoveMemberArg) (err error) {
	defer h.G().CTraceTimed(ctx, fmt.Sprintf("TeamRemoveMember(%s,%s)", arg.Name, arg.Username),
		func() error { return err })()
	return teams.RemoveMember(ctx, h.G().ExternalG(), arg.Name, arg.Username)
}

func (h *TeamsHandler) TeamEditMember(ctx context.Context, arg keybase1.TeamEditMemberArg) (err error) {
	defer h.G().CTraceTimed(ctx, fmt.Sprintf("TeamEditMember(%s,%s)", arg.Name, arg.Username),
		func() error { return err })()
	return teams.EditMember(ctx, h.G().ExternalG(), arg.Name, arg.Username, arg.Role)
}

func (h *TeamsHandler) TeamLeave(ctx context.Context, arg keybase1.TeamLeaveArg) (err error) {
	defer h.G().CTraceTimed(ctx, fmt.Sprintf("TeamLeave(%s)", arg.Name), func() error { return err })()
	return teams.Leave(ctx, h.G().ExternalG(), arg.Name, arg.Permanent)
}

func (h *TeamsHandler) TeamRename(ctx context.Context, arg keybase1.TeamRenameArg) (err error) {
	defer h.G().CTraceTimed(ctx, fmt.Sprintf("TeamRename(%s)", arg.PrevName), func() error { return err })()
	return teams.RenameSubteam(ctx, h.G().ExternalG(), arg.PrevName, arg.NewName)
}

func (h *TeamsHandler) TeamAcceptInvite(ctx context.Context, arg keybase1.TeamAcceptInviteArg) (err error) {
	defer h.G().CTraceTimed(ctx, "TeamAcceptInvite", func() error { return err })()
	return teams.AcceptInvite(ctx, h.G().ExternalG(), arg.Token)
}

func (h *TeamsHandler) TeamRequestAccess(ctx context.Context, arg keybase1.TeamRequestAccessArg) (err error) {
	h.G().CTraceTimed(ctx, "TeamRequestAccess", func() error { return err })()
	return teams.RequestAccess(ctx, h.G().ExternalG(), arg.Name)
}

func (h *TeamsHandler) TeamAcceptInviteOrRequestAccess(ctx context.Context, arg keybase1.TeamAcceptInviteOrRequestAccessArg) (err error) {
	defer h.G().CTraceTimed(ctx, "TeamAcceptInviteOrRequestAccess", func() error { return err })()
	return teams.TeamAcceptInviteOrRequestAccess(ctx, h.G().ExternalG(), arg.TokenOrName)
}

func (h *TeamsHandler) TeamListRequests(ctx context.Context, sessionID int) (res []keybase1.TeamJoinRequest, err error) {
	defer h.G().CTraceTimed(ctx, "TeamListRequests", func() error { return err })()
	return teams.ListRequests(ctx, h.G().ExternalG())
}

func (h *TeamsHandler) TeamIgnoreRequest(ctx context.Context, arg keybase1.TeamIgnoreRequestArg) (err error) {
	defer h.G().CTraceTimed(ctx, "TeamIgnoreRequest", func() error { return err })()
	return teams.IgnoreRequest(ctx, h.G().ExternalG(), arg.Name, arg.Username)
}

func (h *TeamsHandler) TeamTree(ctx context.Context, arg keybase1.TeamTreeArg) (res keybase1.TeamTreeResult, err error) {
	defer h.G().CTraceTimed(ctx, "TeamTree", func() error { return err })()
	return teams.TeamTree(ctx, h.G().ExternalG(), arg)
}

func (h *TeamsHandler) TeamDelete(ctx context.Context, arg keybase1.TeamDeleteArg) (err error) {
	defer h.G().CTraceTimed(ctx, fmt.Sprintf("TeamDelete(%s)", arg.Name), func() error { return err })()
	ui := h.getTeamsUI(arg.SessionID)
	return teams.Delete(ctx, h.G().ExternalG(), ui, arg.Name)
}

func (h *TeamsHandler) LoadTeamPlusApplicationKeys(netCtx context.Context, arg keybase1.LoadTeamPlusApplicationKeysArg) (keybase1.TeamPlusApplicationKeys, error) {
	netCtx = libkb.WithLogTag(netCtx, "LTPAK")
	h.G().Log.CDebugf(netCtx, "+ TeamHandler#LoadTeamPlusApplicationKeys(%+v)", arg)
	return teams.LoadTeamPlusApplicationKeys(netCtx, h.G().ExternalG(), arg.Id, arg.Application, arg.Refreshers)
}

func (h *TeamsHandler) GetTeamRootID(ctx context.Context, id keybase1.TeamID) (keybase1.TeamID, error) {
	return teams.GetRootID(ctx, h.G().ExternalG(), id)
}

func (h *TeamsHandler) LookupImplicitTeam(ctx context.Context, arg keybase1.LookupImplicitTeamArg) (res keybase1.TeamID, err error) {
	defer h.G().CTraceTimed(ctx, fmt.Sprintf("LookupImplicitTeam(%s)", arg.Name), func() error { return err })()
	teamID, _, err := teams.LookupImplicitTeam(ctx, h.G().ExternalG(), arg.Name, arg.Public)
	return teamID, err
}

func (h *TeamsHandler) LookupOrCreateImplicitTeam(ctx context.Context, arg keybase1.LookupOrCreateImplicitTeamArg) (res keybase1.TeamID, err error) {
	defer h.G().CTraceTimed(ctx, fmt.Sprintf("LookupOrCreateImplicitTeam(%s)", arg.Name),
		func() error { return err })()
	teamID, _, err := teams.LookupOrCreateImplicitTeam(ctx, h.G().ExternalG(), arg.Name, arg.Public)
	return teamID, err
}

func (h *TeamsHandler) TeamReAddMemberAfterReset(ctx context.Context, arg keybase1.TeamReAddMemberAfterResetArg) error {
	return teams.ReAddMemberAfterReset(ctx, h.G().ExternalG(), arg.Id, arg.Username)
}
<commit_msg>no more channel mention (#8541)<commit_after>// Copyright 2017 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package service

import (
	"fmt"
	"strings"

	"github.com/keybase/client/go/chat"
	"github.com/keybase/client/go/chat/globals"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/protocol/chat1"
	keybase1 "github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/client/go/teams"
	"github.com/keybase/go-framed-msgpack-rpc/rpc"
	"golang.org/x/net/context"
)

type TeamsHandler struct {
	*BaseHandler
	globals.Contextified
	gregor *gregorHandler
	connID libkb.ConnectionID
}

var _ keybase1.TeamsInterface = (*TeamsHandler)(nil)

func NewTeamsHandler(xp rpc.Transporter, id libkb.ConnectionID, g *globals.Context, gregor *gregorHandler) *TeamsHandler {
	return &TeamsHandler{
		BaseHandler:  NewBaseHandler(g.ExternalG(), xp),
		Contextified: globals.NewContextified(g),
		gregor:       gregor,
		connID:       id,
	}
}

func (h *TeamsHandler) TeamCreate(ctx context.Context, arg keybase1.TeamCreateArg) (res keybase1.TeamCreateResult, err error) {
	defer h.G().CTraceTimed(ctx, fmt.Sprintf("TeamCreate(%s)", arg.Name), func() error { return err })()
	teamName, err := keybase1.TeamNameFromString(arg.Name)
	if err != nil {
		return res, err
	}
	if !teamName.IsRootTeam() {
		h.G().Log.CDebugf(ctx, "TeamCreate: creating a new subteam: %s", arg.Name)
		if teamName.Depth() == 0 {
			return res, fmt.Errorf("empty team name")
		}
		parentName, err := teamName.Parent()
		if err != nil {
			return res, err
		}
		if _, err = teams.CreateSubteam(ctx, h.G().ExternalG(), string(teamName.LastPart()), parentName); err != nil {
			return res, err
		}
	} else {
		if err := teams.CreateRootTeam(ctx, h.G().ExternalG(), teamName.String()); err != nil {
			return res, err
		}
		res.CreatorAdded = true
	}

	if arg.SendChatNotification {
		res.ChatSent = h.sendTeamChatWelcomeMessage(ctx, teamName.String(), h.G().Env.GetUsername().String())
	}
	return res, nil
}

func (h *TeamsHandler) TeamGet(ctx context.Context, arg keybase1.TeamGetArg) (res keybase1.TeamDetails, err error) {
	defer h.G().CTraceTimed(ctx, fmt.Sprintf("TeamGet(%s)", arg.Name), func() error { return err })()
	return teams.Details(ctx, h.G().ExternalG(), arg.Name, arg.ForceRepoll)
}

func (h *TeamsHandler) TeamList(ctx context.Context, arg keybase1.TeamListArg) (res keybase1.AnnotatedTeamList, err error) {
	defer h.G().CTraceTimed(ctx, fmt.Sprintf("TeamList(%s)", arg.UserAssertion), func() error { return err })()
	x, err := teams.List(ctx, h.G().ExternalG(), arg)
	if err != nil {
		return keybase1.AnnotatedTeamList{}, err
	}
	return *x, nil
}

func (h *TeamsHandler) TeamChangeMembership(ctx context.Context, arg keybase1.TeamChangeMembershipArg) error {
	return teams.ChangeRoles(ctx, h.G().ExternalG(), arg.Name, arg.Req)
}

func (h *TeamsHandler) sendTeamChatWelcomeMessage(ctx context.Context, team, user string) (res bool) {
	var err error
	defer func() {
		if err != nil {
			h.G().Log.CWarningf(ctx, "failed to send team welcome message: %s", err.Error())
		}
	}()
	teamDetails, err := teams.Details(ctx, h.G().ExternalG(), team, true)
	if err != nil {
		return false
	}

	var ownerNames, adminNames, writerNames, readerNames []string
	for _, owner := range teamDetails.Members.Owners {
		ownerNames = append(ownerNames, owner.Username)
	}
	for _, admin := range teamDetails.Members.Admins {
		adminNames = append(adminNames, admin.Username)
	}
	for _, writer := range teamDetails.Members.Writers {
		writerNames = append(writerNames, writer.Username)
	}
	for _, reader := range teamDetails.Members.Readers {
		readerNames = append(readerNames, reader.Username)
	}
	var lines []string
	if len(ownerNames) > 0 {
		lines = append(lines, fmt.Sprintf("  owners: %s", strings.Join(ownerNames, ",")))
	}
	if len(adminNames) > 0 {
		lines = append(lines, fmt.Sprintf("  admins: %s", strings.Join(adminNames, ",")))
	}
	if len(writerNames) > 0 {
		lines = append(lines, fmt.Sprintf("  writers: %s", strings.Join(writerNames, ",")))
	}
	if len(readerNames) > 0 {
		lines = append(lines, fmt.Sprintf("  readers: %s", strings.Join(readerNames, ",")))
	}
	memberBody := strings.Join(lines, "\n")
	body := fmt.Sprintf("Hello! I've just added @%s to this team. Current members:\n\n```%s```\n\n_More info on teams:_ keybase.io/blog/introducing-keybase-teams\n_To leave this team, visit the team tab or run `keybase team leave %s`_",
		user, memberBody, team)

	// Ensure we have chat available, since TeamAddMember may also be
	// coming from a standalone launch.
	h.G().ExternalG().StartStandaloneChat()

	if err = chat.SendTextByName(ctx, h.G(), team, &chat.DefaultTeamTopic, chat1.ConversationMembersType_TEAM,
		keybase1.TLFIdentifyBehavior_CHAT_CLI, body, h.gregor.GetClient); err != nil {
		return false
	}

	return true
}

func (h *TeamsHandler) TeamAddMember(ctx context.Context, arg keybase1.TeamAddMemberArg) (res keybase1.TeamAddMemberResult, err error) {
	defer h.G().CTraceTimed(ctx, fmt.Sprintf("TeamAddMember(%s,%s)", arg.Name, arg.Username),
		func() error { return err })()
	if arg.Email != "" {
		if err := teams.InviteEmailMember(ctx, h.G().ExternalG(), arg.Name, arg.Email, arg.Role); err != nil {
			return keybase1.TeamAddMemberResult{}, err
		}
		return keybase1.TeamAddMemberResult{Invited: true, EmailSent: true}, nil
	}
	result, err := teams.AddMember(ctx, h.G().ExternalG(), arg.Name, arg.Username, arg.Role)
	if err != nil {
		return keybase1.TeamAddMemberResult{}, err
	}
	if !arg.SendChatNotification {
		return result, nil
	}

	if result.Invited {
		return result, nil
	}

	result.ChatSent = h.sendTeamChatWelcomeMessage(ctx, arg.Name, result.User.Username)
	return result, nil
}

func (h *TeamsHandler) TeamRemoveMember(ctx context.Context, arg keybase1.TeamRemoveMemberArg) (err error) {
	defer h.G().CTraceTimed(ctx, fmt.Sprintf("TeamRemoveMember(%s,%s)", arg.Name, arg.Username),
		func() error { return err })()
	return teams.RemoveMember(ctx, h.G().ExternalG(), arg.Name, arg.Username)
}

func (h *TeamsHandler) TeamEditMember(ctx context.Context, arg keybase1.TeamEditMemberArg) (err error) {
	defer h.G().CTraceTimed(ctx, fmt.Sprintf("TeamEditMember(%s,%s)", arg.Name, arg.Username),
		func() error { return err })()
	return teams.EditMember(ctx, h.G().ExternalG(), arg.Name, arg.Username, arg.Role)
}

func (h *TeamsHandler) TeamLeave(ctx context.Context, arg keybase1.TeamLeaveArg) (err error) {
	defer h.G().CTraceTimed(ctx, fmt.Sprintf("TeamLeave(%s)", arg.Name), func() error { return err })()
	return teams.Leave(ctx, h.G().ExternalG(), arg.Name, arg.Permanent)
}

func (h *TeamsHandler) TeamRename(ctx context.Context, arg keybase1.TeamRenameArg) (err error) {
	defer h.G().CTraceTimed(ctx, fmt.Sprintf("TeamRename(%s)", arg.PrevName), func() error { return err })()
	return teams.RenameSubteam(ctx, h.G().ExternalG(), arg.PrevName, arg.NewName)
}

func (h *TeamsHandler) TeamAcceptInvite(ctx context.Context, arg keybase1.TeamAcceptInviteArg) (err error) {
	defer h.G().CTraceTimed(ctx, "TeamAcceptInvite", func() error { return err })()
	return teams.AcceptInvite(ctx, h.G().ExternalG(), arg.Token)
}

func (h *TeamsHandler) TeamRequestAccess(ctx context.Context, arg keybase1.TeamRequestAccessArg) (err error) {
	h.G().CTraceTimed(ctx, "TeamRequestAccess", func() error { return err })()
	return teams.RequestAccess(ctx, h.G().ExternalG(), arg.Name)
}

func (h *TeamsHandler) TeamAcceptInviteOrRequestAccess(ctx context.Context, arg keybase1.TeamAcceptInviteOrRequestAccessArg) (err error) {
	defer h.G().CTraceTimed(ctx, "TeamAcceptInviteOrRequestAccess", func() error { return err })()
	return teams.TeamAcceptInviteOrRequestAccess(ctx, h.G().ExternalG(), arg.TokenOrName)
}

func (h *TeamsHandler) TeamListRequests(ctx context.Context, sessionID int) (res []keybase1.TeamJoinRequest, err error) {
	defer h.G().CTraceTimed(ctx, "TeamListRequests", func() error { return err })()
	return teams.ListRequests(ctx, h.G().ExternalG())
}

func (h *TeamsHandler) TeamIgnoreRequest(ctx context.Context, arg keybase1.TeamIgnoreRequestArg) (err error) {
	defer h.G().CTraceTimed(ctx, "TeamIgnoreRequest", func() error { return err })()
	return teams.IgnoreRequest(ctx, h.G().ExternalG(), arg.Name, arg.Username)
}

func (h *TeamsHandler) TeamTree(ctx context.Context, arg keybase1.TeamTreeArg) (res keybase1.TeamTreeResult, err error) {
	defer h.G().CTraceTimed(ctx, "TeamTree", func() error { return err })()
	return teams.TeamTree(ctx, h.G().ExternalG(), arg)
}

func (h *TeamsHandler) TeamDelete(ctx context.Context, arg keybase1.TeamDeleteArg) (err error) {
	defer h.G().CTraceTimed(ctx, fmt.Sprintf("TeamDelete(%s)", arg.Name), func() error { return err })()
	ui := h.getTeamsUI(arg.SessionID)
	return teams.Delete(ctx, h.G().ExternalG(), ui, arg.Name)
}

func (h *TeamsHandler) LoadTeamPlusApplicationKeys(netCtx context.Context, arg keybase1.LoadTeamPlusApplicationKeysArg) (keybase1.TeamPlusApplicationKeys, error) {
	netCtx = libkb.WithLogTag(netCtx, "LTPAK")
	h.G().Log.CDebugf(netCtx, "+ TeamHandler#LoadTeamPlusApplicationKeys(%+v)", arg)
	return teams.LoadTeamPlusApplicationKeys(netCtx, h.G().ExternalG(), arg.Id, arg.Application, arg.Refreshers)
}

func (h *TeamsHandler) GetTeamRootID(ctx context.Context, id keybase1.TeamID) (keybase1.TeamID, error) {
	return teams.GetRootID(ctx, h.G().ExternalG(), id)
}

func (h *TeamsHandler) LookupImplicitTeam(ctx context.Context, arg keybase1.LookupImplicitTeamArg) (res keybase1.TeamID, err error) {
	defer h.G().CTraceTimed(ctx, fmt.Sprintf("LookupImplicitTeam(%s)", arg.Name), func() error { return err })()
	teamID, _, err := teams.LookupImplicitTeam(ctx, h.G().ExternalG(), arg.Name, arg.Public)
	return teamID, err
}

func (h *TeamsHandler) LookupOrCreateImplicitTeam(ctx context.Context, arg keybase1.LookupOrCreateImplicitTeamArg) (res keybase1.TeamID, err error) {
	defer h.G().CTraceTimed(ctx, fmt.Sprintf("LookupOrCreateImplicitTeam(%s)", arg.Name),
		func() error { return err })()
	teamID, _, err := teams.LookupOrCreateImplicitTeam(ctx, h.G().ExternalG(), arg.Name, arg.Public)
	return teamID, err
}

func (h *TeamsHandler) TeamReAddMemberAfterReset(ctx context.Context, arg keybase1.TeamReAddMemberAfterResetArg) error {
	return teams.ReAddMemberAfterReset(ctx, h.G().ExternalG(), arg.Id, arg.Username)
}
<|endoftext|>


<commit_before>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package service

import (
	"time"

	"github.com/keybase/client/go/engine"
	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol"
	rpc "github.com/keybase/go-framed-msgpack-rpc"
	"golang.org/x/net/context"
)

// TrackHandler is the RPC handler for the track interface.
type TrackHandler struct {
	*BaseHandler
	libkb.Contextified

	lastCheckTime time.Time
}

// NewTrackHandler creates a TrackHandler for the xp transport.
func NewTrackHandler(xp rpc.Transporter, g *libkb.GlobalContext) *TrackHandler {
	return &TrackHandler{
		BaseHandler:  NewBaseHandler(xp),
		Contextified: libkb.NewContextified(g),
	}
}

// Track creates a TrackEngine and runs it.
func (h *TrackHandler) Track(_ context.Context, arg keybase1.TrackArg) error {
	earg := engine.TrackEngineArg{
		UserAssertion:    arg.UserAssertion,
		Options:          arg.Options,
		ForceRemoteCheck: arg.ForceRemoteCheck,
	}
	ctx := engine.Context{
		IdentifyUI: h.NewRemoteIdentifyUI(arg.SessionID, h.G()),
		SecretUI:   h.getSecretUI(arg.SessionID),
	}
	eng := engine.NewTrackEngine(&earg, h.G())
	return engine.RunEngine(eng, &ctx)
}

func (h *TrackHandler) TrackWithToken(_ context.Context, arg keybase1.TrackWithTokenArg) error {
	earg := engine.TrackTokenArg{
		Token:   arg.TrackToken,
		Options: arg.Options,
	}
	ctx := engine.Context{
		IdentifyUI: h.NewRemoteIdentifyUI(arg.SessionID, h.G()),
		SecretUI:   h.getSecretUI(arg.SessionID),
	}
	eng := engine.NewTrackToken(&earg, h.G())
	return engine.RunEngine(eng, &ctx)
}

// Untrack creates an UntrackEngine and runs it.
func (h *TrackHandler) Untrack(_ context.Context, arg keybase1.UntrackArg) error {
	earg := engine.UntrackEngineArg{
		Username: arg.Username,
	}
	ctx := engine.Context{
		SecretUI: h.getSecretUI(arg.SessionID),
	}
	eng := engine.NewUntrackEngine(&earg, h.G())
	return engine.RunEngine(eng, &ctx)
}

func (h *TrackHandler) CheckTracking(_ context.Context, sessionID int) error {
	// Rate-limited to once every fifty seconds.
	if !h.G().RateLimits.GetPermission(libkb.CheckTrackingRateLimit, libkb.TrackingRateLimitSeconds * time.Second) {
		h.G().Log.Debug("Skipping CheckTracking due to rate limit.")
		return nil
	}
	return libkb.CheckTracking(h.G())
}

func (h *TrackHandler) FakeTrackingChanged(_ context.Context, arg keybase1.FakeTrackingChangedArg) error {
	user, err := libkb.LoadUser(libkb.LoadUserArg{
		Name: arg.Username,
	})
	if err != nil {
		return err
	}
	h.G().NotifyRouter.HandleTrackingChanged(user.GetUID(), user.GetName())
	return nil
}
<commit_msg>Remove comment now that this is parameterized<commit_after>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package service

import (
	"time"

	"github.com/keybase/client/go/engine"
	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol"
	rpc "github.com/keybase/go-framed-msgpack-rpc"
	"golang.org/x/net/context"
)

// TrackHandler is the RPC handler for the track interface.
type TrackHandler struct {
	*BaseHandler
	libkb.Contextified

	lastCheckTime time.Time
}

// NewTrackHandler creates a TrackHandler for the xp transport.
func NewTrackHandler(xp rpc.Transporter, g *libkb.GlobalContext) *TrackHandler {
	return &TrackHandler{
		BaseHandler:  NewBaseHandler(xp),
		Contextified: libkb.NewContextified(g),
	}
}

// Track creates a TrackEngine and runs it.
func (h *TrackHandler) Track(_ context.Context, arg keybase1.TrackArg) error {
	earg := engine.TrackEngineArg{
		UserAssertion:    arg.UserAssertion,
		Options:          arg.Options,
		ForceRemoteCheck: arg.ForceRemoteCheck,
	}
	ctx := engine.Context{
		IdentifyUI: h.NewRemoteIdentifyUI(arg.SessionID, h.G()),
		SecretUI:   h.getSecretUI(arg.SessionID),
	}
	eng := engine.NewTrackEngine(&earg, h.G())
	return engine.RunEngine(eng, &ctx)
}

func (h *TrackHandler) TrackWithToken(_ context.Context, arg keybase1.TrackWithTokenArg) error {
	earg := engine.TrackTokenArg{
		Token:   arg.TrackToken,
		Options: arg.Options,
	}
	ctx := engine.Context{
		IdentifyUI: h.NewRemoteIdentifyUI(arg.SessionID, h.G()),
		SecretUI:   h.getSecretUI(arg.SessionID),
	}
	eng := engine.NewTrackToken(&earg, h.G())
	return engine.RunEngine(eng, &ctx)
}

// Untrack creates an UntrackEngine and runs it.
func (h *TrackHandler) Untrack(_ context.Context, arg keybase1.UntrackArg) error {
	earg := engine.UntrackEngineArg{
		Username: arg.Username,
	}
	ctx := engine.Context{
		SecretUI: h.getSecretUI(arg.SessionID),
	}
	eng := engine.NewUntrackEngine(&earg, h.G())
	return engine.RunEngine(eng, &ctx)
}

func (h *TrackHandler) CheckTracking(_ context.Context, sessionID int) error {
	if !h.G().RateLimits.GetPermission(libkb.CheckTrackingRateLimit, libkb.TrackingRateLimitSeconds * time.Second) {
		h.G().Log.Debug("Skipping CheckTracking due to rate limit.")
		return nil
	}
	return libkb.CheckTracking(h.G())
}

func (h *TrackHandler) FakeTrackingChanged(_ context.Context, arg keybase1.FakeTrackingChangedArg) error {
	user, err := libkb.LoadUser(libkb.LoadUserArg{
		Name: arg.Username,
	})
	if err != nil {
		return err
	}
	h.G().NotifyRouter.HandleTrackingChanged(user.GetUID(), user.GetName())
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"os"

	"net/http"
	"net/url"

	"github.com/docker/engine-api/client"
	"github.com/docker/engine-api/types"
	"github.com/docker/engine-api/types/filters"
	"golang.org/x/net/context"
)

type skvsResponse struct {
	Key       string `json:"key"`
	Namespace bool   `json:"namespace"`
	Value     string `json:"value"`
}

func printUsage() {
	fmt.Fprintf(os.Stderr, "Usage: %s OPERATION [PARAMS]\n", os.Args[0])
	fmt.Fprintf(os.Stderr, "\nSupported operations:\n")
	fmt.Fprintf(os.Stderr, "\tget KEY\n")
	fmt.Fprintf(os.Stderr, "\tset KEY VALUE\n")
	fmt.Fprintf(os.Stderr, "\tdelete KEY\n")
}

func invalidParameters() {
	printUsage()
	os.Exit(1)
}

func getSKVSIP() (string, error) {
	defaultHeaders := map[string]string{"User-Agent": "protonet-skvs_cli"}
	cli, err := client.NewClient("unix:///var/run/docker.sock", "v1.22", nil, defaultHeaders)
	if err != nil {
		return "", err
	}

	listOptions := types.ContainerListOptions{Filter: filters.NewArgs()}
	listOptions.Filter.Add("name", "skvs")

	containers, err := cli.ContainerList(context.Background(), listOptions)
	if err != nil {
		return "", err
	}
	if len(containers) == 0 {
		return "", errors.New("Found no container named 'skvs'")
	}

	data, err := cli.ContainerInspect(context.Background(), containers[0].ID)
	if err != nil {
		return "", err
	}

	protonetNetworkData, ok := data.NetworkSettings.Networks["protonet"]
	if !ok {
		return "", errors.New("The SKVS container doesn't belong to the network 'protonet'.")
	}

	return protonetNetworkData.IPAddress, nil
}

func get(key string) (string, error) {
	ip, err := getSKVSIP()
	if err != nil {
		return "", err
	}

	requestURL := fmt.Sprintf("http://%s/%s", ip, key)
	resp, err := http.Get(requestURL)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		return "", fmt.Errorf("SKVS responded with %s", resp.Status)
	}

	responseBodyData, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	var responseStruct skvsResponse

	err = json.Unmarshal(responseBodyData, &responseStruct)
	if err != nil {
		return "", err
	}

	return responseStruct.Value, nil
}

func set(key string, value string) error {
	ip, err := getSKVSIP()
	if err != nil {
		return err
	}

	requestURL := fmt.Sprintf("http://%s/%s", ip, key)
	vals := url.Values{}
	vals.Set("value", value)
	resp, err := http.PostForm(requestURL, vals)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		return fmt.Errorf("SKVS responded with %s", resp.Status)
	}

	return nil
}

func delete(key string) error {
	ip, err := getSKVSIP()
	if err != nil {
		return err
	}

	requestURL := fmt.Sprintf("http://%s/%s", ip, key)
	req, err := http.NewRequest("DELETE", requestURL, nil)
	if err != nil {
		return err
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		return fmt.Errorf("SKVS responded with %s", resp.Status)
	}

	return nil
}

func main() {
	if len(os.Args) < 2 {
		invalidParameters()
	}

	switch os.Args[1] {
	case "get":
		if len(os.Args) != 3 {
			invalidParameters()
		}
		value, err := get(os.Args[2])
		if err != nil {
			fmt.Fprintln(os.Stderr, err.Error())
			os.Exit(1)
		}
		fmt.Print(value)
		break
	case "delete":
		if len(os.Args) != 3 {
			invalidParameters()
		}
		err := delete(os.Args[2])
		if err != nil {
			fmt.Fprintln(os.Stderr, err.Error())
			os.Exit(1)
		}
		break
	case "set":
		if len(os.Args) != 4 {
			invalidParameters()
		}
		err := set(os.Args[2], os.Args[3])
		if err != nil {
			fmt.Fprintln(os.Stderr, err.Error())
			os.Exit(1)
		}
		break
	case "--help":
		printUsage()
		break
	case "-h":
		printUsage()
		break
	default:
		invalidParameters()
		break
	}
}
<commit_msg>Remove duplicate code.<commit_after>package main

import (
	"fmt"
	"os"

	"strings"

	skvs "github.com/experimental-platform/platform-skvs/client"
)

type skvsResponse struct {
	Key       string `json:"key"`
	Namespace bool   `json:"namespace"`
	Value     string `json:"value"`
}

func printUsage() {
	fmt.Fprintf(os.Stderr, "Usage: %s OPERATION [PARAMS]\n", os.Args[0])
	fmt.Fprintf(os.Stderr, "\nSupported operations:\n")
	fmt.Fprintf(os.Stderr, "\tget KEY\n")
	fmt.Fprintf(os.Stderr, "\tset KEY VALUE\n")
	fmt.Fprintf(os.Stderr, "\tdelete KEY\n")
}

func invalidParameters() {
	printUsage()
	os.Exit(1)
}

func main() {
	if len(os.Args) < 2 {
		invalidParameters()
	}

	switch strings.ToLower(os.Args[1]) {
	case "get":
		if len(os.Args) != 3 {
			invalidParameters()
		}
		value, err := skvs.Get(os.Args[2])
		if err != nil {
			fmt.Fprintln(os.Stderr, err.Error())
			os.Exit(1)
		}
		fmt.Print(value)
	case "delete":
		if len(os.Args) != 3 {
			invalidParameters()
		}
		err := skvs.Delete(os.Args[2])
		if err != nil {
			fmt.Fprintln(os.Stderr, err.Error())
			os.Exit(1)
		}
	case "set":
		if len(os.Args) != 4 {
			invalidParameters()
		}
		err := skvs.Set(os.Args[2], os.Args[3])
		if err != nil {
			fmt.Fprintln(os.Stderr, err.Error())
			os.Exit(1)
		}
	case "--help", "-h", "help":
		printUsage()
	default:
		invalidParameters()
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package prog

import (
	"fmt"
	"math/rand"
	"os"
	"testing"
	"time"

	"github.com/google/syzkaller/pkg/testutil"
)

// Export guts for testing.

func init() {
	debug = true
}

var (
	CalcChecksumsCall = calcChecksumsCall
	InitTest          = initTest
	initTargetTest    = InitTargetTest
)

func randSource(t *testing.T) rand.Source {
	seed := time.Now().UnixNano()
	if os.Getenv("CI") != "" {
		seed = 0 // required for deterministic coverage reports
	}
	t.Logf("seed=%v", seed)
	return rand.NewSource(seed)
}

func iterCount() int {
	iters := 1000
	if testing.Short() {
		iters /= 10
	}
	if testutil.RaceEnabled {
		iters /= 10
	}
	return iters
}

func initRandomTargetTest(t *testing.T, os, arch string) (*Target, rand.Source, int) {
	target := initTargetTest(t, os, arch)
	return target, randSource(t), iterCount()
}

func initTest(t *testing.T) (*Target, rand.Source, int) {
	return initRandomTargetTest(t, "linux", "amd64")
}

func testEachTarget(t *testing.T, fn func(t *testing.T, target *Target)) {
	t.Parallel()
	for _, target := range AllTargets() {
		target := target
		t.Run(fmt.Sprintf("%v/%v", target.OS, target.Arch), func(t *testing.T) {
			skipTargetRace(t, target)
			t.Parallel()
			fn(t, target)
		})
	}
}

func testEachTargetRandom(t *testing.T, fn func(t *testing.T, target *Target, rs rand.Source, iters int)) {
	t.Parallel()
	targets := AllTargets()
	iters := iterCount()
	iters /= len(targets)
	if iters < 3 {
		iters = 3
	}
	rs0 := randSource(t)
	for _, target := range targets {
		target := target
		rs := rand.NewSource(rs0.Int63())
		t.Run(fmt.Sprintf("%v/%v", target.OS, target.Arch), func(t *testing.T) {
			skipTargetRace(t, target)
			t.Parallel()
			fn(t, target, rs, iters)
		})
	}
}

func skipTargetRace(t *testing.T, target *Target) {
	// Race execution is slow and we are getting timeouts on CI.
	// For tests that run for all targets, leave only 2 targets,
	// this should be enough to detect some races.
	if testutil.RaceEnabled && (target.OS != "test" || target.Arch != "64" && target.Arch != "32") {
		t.Skip("skipping all but test/64 targets in race mode")
	}
}

func initBench(b *testing.B) (*Target, func()) {
	olddebug := debug
	debug = false
	target, err := GetTarget("linux", "amd64")
	if err != nil {
		b.Fatal(err)
	}
	b.ReportAllocs()
	return target, func() { debug = olddebug }
}
<commit_msg>prog: allow to use fixed test seed w/o rebuilding tests<commit_after>// Copyright 2017 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package prog

import (
	"fmt"
	"math/rand"
	"os"
	"strconv"
	"testing"
	"time"

	"github.com/google/syzkaller/pkg/testutil"
)

// Export guts for testing.

func init() {
	debug = true
}

var (
	CalcChecksumsCall = calcChecksumsCall
	InitTest          = initTest
	initTargetTest    = InitTargetTest
)

func randSource(t *testing.T) rand.Source {
	seed := time.Now().UnixNano()
	if fixed := os.Getenv("SYZ_SEED"); fixed != "" {
		seed, _ = strconv.ParseInt(fixed, 0, 64)
	}
	if os.Getenv("CI") != "" {
		seed = 0 // required for deterministic coverage reports
	}
	t.Logf("seed=%v", seed)
	return rand.NewSource(seed)
}

func iterCount() int {
	iters := 1000
	if testing.Short() {
		iters /= 10
	}
	if testutil.RaceEnabled {
		iters /= 10
	}
	return iters
}

func initRandomTargetTest(t *testing.T, os, arch string) (*Target, rand.Source, int) {
	target := initTargetTest(t, os, arch)
	return target, randSource(t), iterCount()
}

func initTest(t *testing.T) (*Target, rand.Source, int) {
	return initRandomTargetTest(t, "linux", "amd64")
}

func testEachTarget(t *testing.T, fn func(t *testing.T, target *Target)) {
	t.Parallel()
	for _, target := range AllTargets() {
		target := target
		t.Run(fmt.Sprintf("%v/%v", target.OS, target.Arch), func(t *testing.T) {
			skipTargetRace(t, target)
			t.Parallel()
			fn(t, target)
		})
	}
}

func testEachTargetRandom(t *testing.T, fn func(t *testing.T, target *Target, rs rand.Source, iters int)) {
	t.Parallel()
	targets := AllTargets()
	iters := iterCount()
	iters /= len(targets)
	if iters < 3 {
		iters = 3
	}
	rs0 := randSource(t)
	for _, target := range targets {
		target := target
		rs := rand.NewSource(rs0.Int63())
		t.Run(fmt.Sprintf("%v/%v", target.OS, target.Arch), func(t *testing.T) {
			skipTargetRace(t, target)
			t.Parallel()
			fn(t, target, rs, iters)
		})
	}
}

func skipTargetRace(t *testing.T, target *Target) {
	// Race execution is slow and we are getting timeouts on CI.
	// For tests that run for all targets, leave only 2 targets,
	// this should be enough to detect some races.
	if testutil.RaceEnabled && (target.OS != "test" || target.Arch != "64" && target.Arch != "32") {
		t.Skip("skipping all but test/64 targets in race mode")
	}
}

func initBench(b *testing.B) (*Target, func()) {
	olddebug := debug
	debug = false
	target, err := GetTarget("linux", "amd64")
	if err != nil {
		b.Fatal(err)
	}
	b.ReportAllocs()
	return target, func() { debug = olddebug }
}
<|endoftext|>


<commit_before>package gocd

import (
	"context"
	"net/url"
	"strings"
)

// EnvironmentsService exposes calls for interacting with Environment objects in the GoCD API.
type EnvironmentsService service

// EnvironmentsResponseLinks describes the HAL _link resource for the api response object for a collection of environment
// objects
//go:generate gocd-response-links-generator -type=EnvironmentsResponseLinks,EnvironmentLinks
type EnvironmentsResponseLinks struct {
	Self *url.URL `json:"self"`
	Doc  *url.URL `json:"doc"`
}

// EnvironmentLinks describes the HAL _link resource for the api response object for a collection of environment objects.
type EnvironmentLinks struct {
	Self *url.URL `json:"self"`
	Doc  *url.URL `json:"doc"`
	Find *url.URL `json:"find"`
}

// EnvironmentsResponse describes the response obejct for a plugin API call.
type EnvironmentsResponse struct {
	Links    *EnvironmentsResponseLinks `json:"_links"`
	Embedded struct {
		Environments []*Environment `json:"environments"`
	} `json:"_embedded"`
}

// Environment describes a group of pipelines and agents
type Environment struct {
	Links                *EnvironmentLinks      `json:"_links,omitempty"`
	Name                 string                 `json:"name"`
	Pipelines            []*Pipeline            `json:"pipelines,omitempty"`
	Agents               []*Agent               `json:"agents,omitempty"`
	EnvironmentVariables []*EnvironmentVariable `json:"environment_variables,omitempty"`
	Version              string                 `json:"version"`
}

// EnvironmentPatchRequest describes the actions to perform on an environment
type EnvironmentPatchRequest struct {
	Pipelines            *PatchStringAction          `json:"pipelines"`
	Agents               *PatchStringAction          `json:"agents"`
	EnvironmentVariables *EnvironmentVariablesAction `json:"environment_variables"`
}

// EnvironmentVariablesAction describes a collection of Environment Variables to add or remove.
type EnvironmentVariablesAction struct {
	Add    []*EnvironmentVariable `json:"add"`
	Remove []*EnvironmentVariable `json:"remove"`
}

// PatchStringAction describes a collection of resources to add or remove.
type PatchStringAction struct {
	Add    []string `json:"add"`
	Remove []string `json:"remove"`
}

// List all environments
func (es *EnvironmentsService) List(ctx context.Context) (*EnvironmentsResponse, *APIResponse, error) {
	e := EnvironmentsResponse{}
	_, resp, err := es.client.getAction(ctx, &APIClientRequest{
		Path:         "admin/environments",
		ResponseBody: &e,
		APIVersion:   apiV2,
	})

	return &e, resp, err
}

// Delete an environment
func (es *EnvironmentsService) Delete(ctx context.Context, name string) (string, *APIResponse, error) {
	return es.client.deleteAction(ctx, "admin/environments/"+name, apiV2)
}

// Create an environment
func (es *EnvironmentsService) Create(ctx context.Context, name string) (*Environment, *APIResponse, error) {
	e := Environment{}
	_, resp, err := es.client.postAction(ctx, &APIClientRequest{
		Path: "admin/environments/",
		RequestBody: Environment{
			Name: name,
		},
		ResponseBody: &e,
		APIVersion:   apiV2,
	})
	if err == nil {
		e.Version = strings.Replace(resp.HTTP.Header.Get("Etag"), "\"", "", -1)
	}
	return &e, resp, err
}

// Get a single environment by name
func (es *EnvironmentsService) Get(ctx context.Context, name string) (*Environment, *APIResponse, error) {
	e := Environment{}
	_, resp, err := es.client.getAction(ctx, &APIClientRequest{
		Path:         "admin/environments/" + name,
		ResponseBody: &e,
		APIVersion:   apiV2,
	})
	if err == nil {
		e.Version = strings.Replace(resp.HTTP.Header.Get("Etag"), "\"", "", -1)
	}

	return &e, resp, err
}

// Patch an environments configuration by adding or removing pipelines, agents, environment variables
func (es *EnvironmentsService) Patch(ctx context.Context, name string, patch *EnvironmentPatchRequest) (*Environment, *APIResponse, error) {
	env := Environment{}
	_, resp, err := es.client.patchAction(ctx, &APIClientRequest{
		Path:         "admin/environments" + name,
		RequestBody:  patch,
		ResponseBody: &env,
		APIVersion:   apiV2,
	})
	if err == nil {
		env.Version = strings.Replace(resp.HTTP.Header.Get("Etag"), "\"", "", -1)
	}

	return &env, resp, err
}
<commit_msg>fixed bad url path<commit_after>package gocd

import (
	"context"
	"net/url"
	"strings"
)

// EnvironmentsService exposes calls for interacting with Environment objects in the GoCD API.
type EnvironmentsService service

// EnvironmentsResponseLinks describes the HAL _link resource for the api response object for a collection of environment
// objects
//go:generate gocd-response-links-generator -type=EnvironmentsResponseLinks,EnvironmentLinks
type EnvironmentsResponseLinks struct {
	Self *url.URL `json:"self"`
	Doc  *url.URL `json:"doc"`
}

// EnvironmentLinks describes the HAL _link resource for the api response object for a collection of environment objects.
type EnvironmentLinks struct {
	Self *url.URL `json:"self"`
	Doc  *url.URL `json:"doc"`
	Find *url.URL `json:"find"`
}

// EnvironmentsResponse describes the response obejct for a plugin API call.
type EnvironmentsResponse struct {
	Links    *EnvironmentsResponseLinks `json:"_links"`
	Embedded struct {
		Environments []*Environment `json:"environments"`
	} `json:"_embedded"`
}

// Environment describes a group of pipelines and agents
type Environment struct {
	Links                *EnvironmentLinks      `json:"_links,omitempty"`
	Name                 string                 `json:"name"`
	Pipelines            []*Pipeline            `json:"pipelines,omitempty"`
	Agents               []*Agent               `json:"agents,omitempty"`
	EnvironmentVariables []*EnvironmentVariable `json:"environment_variables,omitempty"`
	Version              string                 `json:"version"`
}

// EnvironmentPatchRequest describes the actions to perform on an environment
type EnvironmentPatchRequest struct {
	Pipelines            *PatchStringAction          `json:"pipelines"`
	Agents               *PatchStringAction          `json:"agents"`
	EnvironmentVariables *EnvironmentVariablesAction `json:"environment_variables"`
}

// EnvironmentVariablesAction describes a collection of Environment Variables to add or remove.
type EnvironmentVariablesAction struct {
	Add    []*EnvironmentVariable `json:"add"`
	Remove []*EnvironmentVariable `json:"remove"`
}

// PatchStringAction describes a collection of resources to add or remove.
type PatchStringAction struct {
	Add    []string `json:"add"`
	Remove []string `json:"remove"`
}

// List all environments
func (es *EnvironmentsService) List(ctx context.Context) (*EnvironmentsResponse, *APIResponse, error) {
	e := EnvironmentsResponse{}
	_, resp, err := es.client.getAction(ctx, &APIClientRequest{
		Path:         "admin/environments",
		ResponseBody: &e,
		APIVersion:   apiV2,
	})

	return &e, resp, err
}

// Delete an environment
func (es *EnvironmentsService) Delete(ctx context.Context, name string) (string, *APIResponse, error) {
	return es.client.deleteAction(ctx, "admin/environments/"+name, apiV2)
}

// Create an environment
func (es *EnvironmentsService) Create(ctx context.Context, name string) (*Environment, *APIResponse, error) {
	e := Environment{}
	_, resp, err := es.client.postAction(ctx, &APIClientRequest{
		Path: "admin/environments/",
		RequestBody: Environment{
			Name: name,
		},
		ResponseBody: &e,
		APIVersion:   apiV2,
	})
	if err == nil {
		e.Version = strings.Replace(resp.HTTP.Header.Get("Etag"), "\"", "", -1)
	}
	return &e, resp, err
}

// Get a single environment by name
func (es *EnvironmentsService) Get(ctx context.Context, name string) (*Environment, *APIResponse, error) {
	e := Environment{}
	_, resp, err := es.client.getAction(ctx, &APIClientRequest{
		Path:         "admin/environments/" + name,
		ResponseBody: &e,
		APIVersion:   apiV2,
	})
	if err == nil {
		e.Version = strings.Replace(resp.HTTP.Header.Get("Etag"), "\"", "", -1)
	}

	return &e, resp, err
}

// Patch an environments configuration by adding or removing pipelines, agents, environment variables
func (es *EnvironmentsService) Patch(ctx context.Context, name string, patch *EnvironmentPatchRequest) (*Environment, *APIResponse, error) {
	env := Environment{}
	_, resp, err := es.client.patchAction(ctx, &APIClientRequest{
		Path:         "admin/environments/" + name,
		RequestBody:  patch,
		ResponseBody: &env,
		APIVersion:   apiV2,
	})
	if err == nil {
		env.Version = strings.Replace(resp.HTTP.Header.Get("Etag"), "\"", "", -1)
	}

	return &env, resp, err
}
<|endoftext|>