text: // Copyright 2015 Google Inc. All rights reserved.
  // Use of this source code is governed by the Apache 2.0
  // license that can be found in the LICENSE file.
  
  package internal
  
  import (
  	"errors"
  	"os"
  
  	"github.com/golang/protobuf/proto"
  	netcontext "golang.org/x/net/context"
  )
  
  var errNotAppEngineContext = errors.New("not an App Engine context")
  
  type CallOverrideFunc func(ctx netcontext.Context, service, method string, in, out proto.Message) error
  
  var callOverrideKey = "holds []CallOverrideFunc"
  
  func WithCallOverride(ctx netcontext.Context, f CallOverrideFunc) netcontext.Context {
  	// We avoid appending to any existing call override
  	// so we don't risk overwriting a popped stack below.
  	var cofs []CallOverrideFunc
  	if uf, ok := ctx.Value(&callOverrideKey).([]CallOverrideFunc); ok {
  		cofs = append(cofs, uf...)
  	}
  	cofs = append(cofs, f)
  	return netcontext.WithValue(ctx, &callOverrideKey, cofs)
  }
  
  func callOverrideFromContext(ctx netcontext.Context) (CallOverrideFunc, netcontext.Context, bool) {
  	cofs, _ := ctx.Value(&callOverrideKey).([]CallOverrideFunc)
  	if len(cofs) == 0 {
  		return nil, nil, false
  	}
  	// We found a list of overrides; grab the last, and reconstitute a
  	// context that will hide it.
  	f := cofs[len(cofs)-1]
  	ctx = netcontext.WithValue(ctx, &callOverrideKey, cofs[:len(cofs)-1])
  	return f, ctx, true
  }
  
  type logOverrideFunc func(level int64, format string, args ...interface{})
  
  var logOverrideKey = "holds a logOverrideFunc"
  
  func WithLogOverride(ctx netcontext.Context, f logOverrideFunc) netcontext.Context {
  	return netcontext.WithValue(ctx, &logOverrideKey, f)
  }
  
  var appIDOverrideKey = "holds a string, being the full app ID"
  
  func WithAppIDOverride(ctx netcontext.Context, appID string) netcontext.Context {
  	return netcontext.WithValue(ctx, &appIDOverrideKey, appID)
  }
  
  var namespaceKey = "holds the namespace string"
  
  func withNamespace(ctx netcontext.Context, ns string) netcontext.Context {
  	return netcontext.WithValue(ctx, &namespaceKey, ns)
  }
  
  func NamespaceFromContext(ctx netcontext.Context) string {
  	// If there's no namespace, return the empty string.
  	ns, _ := ctx.Value(&namespaceKey).(string)
  	return ns
  }
  
  // FullyQualifiedAppID returns the fully-qualified application ID.
  // This may contain a partition prefix (e.g. "s~" for High Replication apps),
  // or a domain prefix (e.g. "example.com:").
  func FullyQualifiedAppID(ctx netcontext.Context) string {
  	if id, ok := ctx.Value(&appIDOverrideKey).(string); ok {
  		return id
  	}
  	return fullyQualifiedAppID(ctx)
  }
  
  func Logf(ctx netcontext.Context, level int64, format string, args ...interface{}) {
  	if f, ok := ctx.Value(&logOverrideKey).(logOverrideFunc); ok {
  		f(level, format, args...)
  		return
  	}
  	c := fromContext(ctx)
  	if c == nil {
  		panic(errNotAppEngineContext)
  	}
  	logf(c, level, format, args...)
  }
  
  // NamespacedContext wraps a Context to support namespaces.
  func NamespacedContext(ctx netcontext.Context, namespace string) netcontext.Context {
  	return withNamespace(ctx, namespace)
  }
  
  // SetTestEnv sets the env variables for testing background ticket in Flex.
  func SetTestEnv() func() {
  	var environ = []struct {
  		key, value string
  	}{
  		{"GAE_LONG_APP_ID", "my-app-id"},
  		{"GAE_MINOR_VERSION", "067924799508853122"},
  		{"GAE_MODULE_INSTANCE", "0"},
  		{"GAE_MODULE_NAME", "default"},
  		{"GAE_MODULE_VERSION", "20150612t184001"},
  	}
  
  	for _, v := range environ {
  		old := os.Getenv(v.key)
  		os.Setenv(v.key, v.value)
  		v.value = old
  	}
  	return func() { // Restore old environment after the test completes.
  		for _, v := range environ {
  			if v.value == "" {
  				os.Unsetenv(v.key)
  				continue
  			}
  			os.Setenv(v.key, v.value)
  		}
  	}
  }
  