func (s *stringMapPropagator) ExtractToWorkflow(ctx workflow.Context, reader workflow.HeaderReader) (workflow.Context, error) {
	if err := reader.ForEachKey(func(key string, value []byte) error {
		if _, ok := s.keys[key]; ok {
			ctx = workflow.WithValue(ctx, contextKey(key), string(value))
		}
		return nil
	}); err != nil {
		return nil, err
	}
	return ctx, nil
}
ExtractToWorkflow extracts values from headers and puts them into context
package test
import (
	"context"
	"fmt"
	"os"
	"strings"
	"go.uber.org/yarpc"
	"go.uber.org/yarpc/transport/grpc"
	"go.uber.org/yarpc/transport/tchannel"
	"go.uber.org/cadence/.gen/go/cadence/workflowserviceclient"
	apiv1 "go.uber.org/cadence/.gen/proto/api/v1"
	"go.uber.org/cadence/compatibility"
	"go.uber.org/cadence/workflow"
)
type (
	Config struct {
		ServiceAddr       string
		ServiceName       string
		IsStickyOff       bool
		EnableGrpcAdapter bool
		Debug             bool
	}
	contextKey string
)
func newConfig() Config {
	cfg := Config{
		ServiceName:       "cadence-frontend",
		ServiceAddr:       "127.0.0.1:7933",
		EnableGrpcAdapter: false,
		IsStickyOff:       true,
	}
	if name := getEnvServiceName(); name != "" {
		cfg.ServiceName = name
	}
	if addr := getEnvServiceAddr(); addr != "" {
		cfg.ServiceAddr = addr
	}
	if so := getEnvStickyOff(); so != "" {
		cfg.IsStickyOff = so == "true"
	}
	if grpc := getEnableGrpcAdapter(); grpc != "" {
		cfg.EnableGrpcAdapter = grpc == "true"
	}
	if debug := getDebug(); debug != "" {
		cfg.Debug = debug == "true"
	}
	return cfg
}
func getEnvServiceName() string {
	return strings.TrimSpace(os.Getenv("SERVICE_NAME"))
}
func getEnvServiceAddr() string {
	return strings.TrimSpace(os.Getenv("SERVICE_ADDR"))
}
func getEnvStickyOff() string {
	return strings.ToLower(strings.TrimSpace(os.Getenv("STICKY_OFF")))
}
func getEnableGrpcAdapter() string {
	return strings.ToLower(strings.TrimSpace(os.Getenv("ENABLE_GRPC_ADAPTER")))
}
func getDebug() string {
	return strings.ToLower(strings.TrimSpace(os.Getenv("DEBUG")))
}
type rpcClient struct {
	workflowserviceclient.Interface
	dispatcher *yarpc.Dispatcher
}
func (c *rpcClient) Close() {
	c.dispatcher.Stop()
}
func newRPCClient(
	serviceName string, serviceAddr string) (*rpcClient, error) {
	transport, err := tchannel.NewTransport(tchannel.ServiceName("integration-test"))
	if err != nil {
		return nil, err
	}
	outbound := transport.NewSingleOutbound(serviceAddr)
	dispatcher := yarpc.NewDispatcher(yarpc.Config{
		Name: "integration-test",
		Outbounds: yarpc.Outbounds{
			serviceName: {
				Unary: outbound,
			},
		},
	})
	if err := dispatcher.Start(); err != nil {
		return nil, err
	}
	client := workflowserviceclient.New(dispatcher.ClientConfig(serviceName))
	return &rpcClient{Interface: client, dispatcher: dispatcher}, nil
}
func newGRPCAdapterClient(
	serviceName string, serviceAddr string) (*rpcClient, error) {
	transport := grpc.NewTransport()
	outbound := transport.NewSingleOutbound(serviceAddr)
	dispatcher := yarpc.NewDispatcher(yarpc.Config{
		Name: "integration-test",
		Outbounds: yarpc.Outbounds{
			serviceName: {
				Unary: outbound,
			},
		},
	})
	if err := dispatcher.Start(); err != nil {
		return nil, err
	}
	clientConfig := dispatcher.ClientConfig(serviceName)
	adapter := compatibility.NewThrift2ProtoAdapter(
		apiv1.NewDomainAPIYARPCClient(clientConfig),
		apiv1.NewWorkflowAPIYARPCClient(clientConfig),
		apiv1.NewWorkerAPIYARPCClient(clientConfig),
		apiv1.NewVisibilityAPIYARPCClient(clientConfig))
	return &rpcClient{Interface: adapter, dispatcher: dispatcher}, nil
}
type stringMapPropagator struct {
	keys map[string]struct{}
}
func NewStringMapPropagator(keys []string) workflow.ContextPropagator {
	keyMap := make(map[string]struct{}, len(keys))
	for _, key := range keys {
		keyMap[key] = struct{}{}
	}
	return &stringMapPropagator{keyMap}
}
func (s *stringMapPropagator) Inject(ctx context.Context, writer workflow.HeaderWriter) error {
	for key := range s.keys {
		value, ok := ctx.Value(contextKey(key)).(string)
		if !ok {
			return fmt.Errorf("unable to extract key from context %v", key)
		}
		writer.Set(key, []byte(value))
	}
	return nil
}
func (s *stringMapPropagator) InjectFromWorkflow(ctx workflow.Context, writer workflow.HeaderWriter) error {
	for key := range s.keys {
		value, ok := ctx.Value(contextKey(key)).(string)
		if !ok {
			return fmt.Errorf("unable to extract key from context %v", key)
		}
		writer.Set(key, []byte(value))
	}
	return nil
}
func (s *stringMapPropagator) Extract(ctx context.Context, reader workflow.HeaderReader) (context.Context, error) {
	if err := reader.ForEachKey(func(key string, value []byte) error {
		if _, ok := s.keys[key]; ok {
			ctx = context.WithValue(ctx, contextKey(key), string(value))
		}
		return nil
	}); err != nil {
		return nil, err
	}
	return ctx, nil
}