func TestCheckAuthDisplayName(n string) TestCheckFunc {
	return func(resp *logical.Response) error {
		if resp.Auth == nil {
			return fmt.Errorf("no auth in response")
		}
		if n != "" && resp.Auth.DisplayName != "mnt-"+n {
			return fmt.Errorf("invalid display name: %#v", resp.Auth.DisplayName)
		}
		return nil
	}
}
TestCheckAuthDisplayName is a helper to check that a request generated a
valid display name.
package testing
import (
	"crypto/tls"
	"fmt"
	"os"
	"reflect"
	"sort"
	"testing"
	log "github.com/mgutz/logxi/v1"
	"github.com/hashicorp/errwrap"
	"github.com/hashicorp/vault/api"
	"github.com/hashicorp/vault/helper/logformat"
	"github.com/hashicorp/vault/http"
	"github.com/hashicorp/vault/logical"
	"github.com/hashicorp/vault/physical"
	"github.com/hashicorp/vault/vault"
)
const TestEnvVar = "VAULT_ACC"
type TestCase struct {
	PreCheck func()
	Backend logical.Backend
	Factory logical.Factory
	Steps []TestStep
	Teardown TestTeardownFunc
	AcceptanceTest bool
}
type TestStep struct {
	Operation logical.Operation
	Path string
	Data map[string]interface{}
	Check TestCheckFunc
	PreFlight PreFlightFunc
	ErrorOk bool
	Unauthenticated bool
	RemoteAddr string
	ConnState *tls.ConnectionState
}
type TestCheckFunc func(*logical.Response) error
type PreFlightFunc func(*logical.Request) error
type TestTeardownFunc func() error
func Test(tt TestT, c TestCase) {
	if c.AcceptanceTest && os.Getenv(TestEnvVar) == "" {
		tt.Skip(fmt.Sprintf(
			"Acceptance tests skipped unless env '%s' set",
			TestEnvVar))
		return
	}
	if c.AcceptanceTest && !testTesting && !testing.Verbose() {
		tt.Fatal("Acceptance tests must be run with the -v flag on tests")
		return
	}
	if c.PreCheck != nil {
		c.PreCheck()
	}
	if c.Backend == nil && c.Factory == nil {
		tt.Fatal("Must provide either Backend or Factory")
		return
	}
	logger := logformat.NewVaultLogger(log.LevelTrace)
	core, err := vault.NewCore(&vault.CoreConfig{
		Physical: physical.NewInmem(logger),
		LogicalBackends: map[string]logical.Factory{
			"test": func(conf *logical.BackendConfig) (logical.Backend, error) {
				if c.Backend != nil {
					return c.Backend, nil
				}
				return c.Factory(conf)
			},
		},
		DisableMlock: true,
	})
	if err != nil {
		tt.Fatal("error initializing core: ", err)
		return
	}
	init, err := core.Initialize(&vault.InitParams{
		BarrierConfig: &vault.SealConfig{
			SecretShares:    1,
			SecretThreshold: 1,
		},
		RecoveryConfig: nil,
	})
	if err != nil {
		tt.Fatal("error initializing core: ", err)
		return
	}
	if unsealed, err := core.Unseal(init.SecretShares[0]); err != nil {
		tt.Fatal("error unsealing core: ", err)
		return
	} else if !unsealed {
		tt.Fatal("vault shouldn't be sealed")
		return
	}
	ln, addr := http.TestServer(nil, core)
	defer ln.Close()
	clientConfig := api.DefaultConfig()
	clientConfig.Address = addr
	client, err := api.NewClient(clientConfig)
	if err != nil {
		tt.Fatal("error initializing HTTP client: ", err)
		return
	}
	client.SetToken(init.RootToken)
	prefix := "mnt"
	mountInfo := &api.MountInput{
		Type:        "test",
		Description: "acceptance test",
	}
	if err := client.Sys().Mount(prefix, mountInfo); err != nil {
		tt.Fatal("error mounting backend: ", err)
		return
	}
	var revoke []*logical.Request
	for i, s := range c.Steps {
		if log.IsWarn() {
			log.Warn("Executing test step", "step_number", i+1)
		}
		req := &logical.Request{
			Operation: s.Operation,
			Path:      s.Path,
			Data:      s.Data,
		}
		if !s.Unauthenticated {
			req.ClientToken = client.Token()
		}
		if s.RemoteAddr != "" {
			req.Connection = &logical.Connection{RemoteAddr: s.RemoteAddr}
		}
		if s.ConnState != nil {
			req.Connection = &logical.Connection{ConnState: s.ConnState}
		}
		if s.PreFlight != nil {
			ct := req.ClientToken
			req.ClientToken = ""
			if err := s.PreFlight(req); err != nil {
				tt.Error(fmt.Sprintf("Failed preflight for step %d: %s", i+1, err))
				break
			}
			req.ClientToken = ct
		}
		req.Path = fmt.Sprintf("%s/%s", prefix, req.Path)
		resp, err := core.HandleRequest(req)
		if resp != nil && resp.Secret != nil {
			revoke = append(revoke, &logical.Request{
				Operation: logical.UpdateOperation,
				Path:      "sys/revoke/" + resp.Secret.LeaseID,
			})
		}
		if err != nil {
			if s.ErrorOk {
				err = nil
			} else {
				tt.Error(fmt.Sprintf("Failed step %d: %s", i+1, err))
				break
			}
		}
		if resp.IsError() && !s.ErrorOk {
			err = fmt.Errorf("Erroneous response:\n\n%#v", resp)
		}
		if err == nil && s.Check != nil {
			err = s.Check(resp)
		}
		if err != nil {
			tt.Error(fmt.Sprintf("Failed step %d: %s", i+1, err))
			break
		}
	}
	var failedRevokes []*logical.Secret
	for _, req := range revoke {
		if log.IsWarn() {
			log.Warn("Revoking secret", "secret", fmt.Sprintf("%#v", req))
		}
		req.ClientToken = client.Token()
		resp, err := core.HandleRequest(req)
		if err == nil && resp.IsError() {
			err = fmt.Errorf("Erroneous response:\n\n%#v", resp)
		}
		if err != nil {
			failedRevokes = append(failedRevokes, req.Secret)
			tt.Error(fmt.Sprintf("Revoke error: %s", err))
		}
	}
	log.Warn("Requesting RollbackOperation")
	req := logical.RollbackRequest(prefix + "/")
	req.Data["immediate"] = true
	req.ClientToken = client.Token()
	resp, err := core.HandleRequest(req)
	if err == nil && resp.IsError() {
		err = fmt.Errorf("Erroneous response:\n\n%#v", resp)
	}
	if err != nil {
		if !errwrap.Contains(err, logical.ErrUnsupportedOperation.Error()) {
			tt.Error(fmt.Sprintf("[ERR] Rollback error: %s", err))
		}
	}
	if len(failedRevokes) > 0 {
		for _, s := range failedRevokes {
			tt.Error(fmt.Sprintf(
				"WARNING: Revoking the following secret failed. It may\n"+
					"still exist. Please verify:\n\n%#v",
				s))
		}
	}
	if c.Teardown != nil {
		c.Teardown()
	}
}
func TestCheckMulti(fs ...TestCheckFunc) TestCheckFunc {
	return func(resp *logical.Response) error {
		for _, f := range fs {
			if err := f(resp); err != nil {
				return err
			}
		}
		return nil
	}
}
func TestCheckAuth(policies []string) TestCheckFunc {
	return func(resp *logical.Response) error {
		if resp == nil || resp.Auth == nil {
			return fmt.Errorf("no auth in response")
		}
		expected := make([]string, len(policies))
		copy(expected, policies)
		sort.Strings(expected)
		ret := make([]string, len(resp.Auth.Policies))
		copy(ret, resp.Auth.Policies)
		sort.Strings(ret)
		if !reflect.DeepEqual(ret, expected) {
			return fmt.Errorf("invalid policies: expected %#v, got %#v", expected, ret)
		}
		return nil
	}
}