diff --git a/builtin/logical/ssh/backend_test.go b/builtin/logical/ssh/backend_test.go index d461686189..5b28e6ea20 100644 --- a/builtin/logical/ssh/backend_test.go +++ b/builtin/logical/ssh/backend_test.go @@ -13,8 +13,8 @@ import ( "time" "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/helper/testhelpers/corehelpers" "github.com/hashicorp/vault/sdk/logical" - "golang.org/x/crypto/ssh" "github.com/hashicorp/vault/builtin/credential/userpass" @@ -519,7 +519,7 @@ func newTestingFactory(t *testing.T) func(ctx context.Context, conf *logical.Bac defaultLeaseTTLVal := 2 * time.Minute maxLeaseTTLVal := 10 * time.Minute return Factory(context.Background(), &logical.BackendConfig{ - Logger: vault.NewTestLogger(t), + Logger: corehelpers.NewTestLogger(t), StorageView: &logical.InmemStorage{}, System: &logical.StaticSystemView{ DefaultLeaseTTLVal: defaultLeaseTTLVal, diff --git a/command/auth_tune_test.go b/command/auth_tune_test.go index 635a70f44b..ca5a6d78c5 100644 --- a/command/auth_tune_test.go +++ b/command/auth_tune_test.go @@ -6,8 +6,8 @@ import ( "github.com/go-test/deep" "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/helper/testhelpers/corehelpers" "github.com/hashicorp/vault/sdk/helper/consts" - "github.com/hashicorp/vault/vault" "github.com/mitchellh/cli" ) @@ -76,7 +76,7 @@ func TestAuthTuneCommand_Run(t *testing.T) { t.Run("integration", func(t *testing.T) { t.Run("flags_all", func(t *testing.T) { t.Parallel() - pluginDir, cleanup := vault.MakeTestPluginDir(t) + pluginDir, cleanup := corehelpers.MakeTestPluginDir(t) defer cleanup(t) client, _, closer := testVaultServerPluginDir(t, pluginDir) diff --git a/command/plugin_deregister_test.go b/command/plugin_deregister_test.go index fc3bc5801e..f517dac63c 100644 --- a/command/plugin_deregister_test.go +++ b/command/plugin_deregister_test.go @@ -5,8 +5,8 @@ import ( "testing" "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/helper/testhelpers/corehelpers" "github.com/hashicorp/vault/sdk/helper/consts" - "github.com/hashicorp/vault/vault" "github.com/mitchellh/cli" ) @@ -77,7 +77,7 @@ func TestPluginDeregisterCommand_Run(t *testing.T) { t.Run("integration", func(t *testing.T) { t.Parallel() - pluginDir, cleanup := vault.MakeTestPluginDir(t) + pluginDir, cleanup := corehelpers.MakeTestPluginDir(t) defer cleanup(t) client, _, closer := testVaultServerPluginDir(t, pluginDir) @@ -135,7 +135,7 @@ func TestPluginDeregisterCommand_Run(t *testing.T) { t.Run("integration with version", func(t *testing.T) { t.Parallel() - pluginDir, cleanup := vault.MakeTestPluginDir(t) + pluginDir, cleanup := corehelpers.MakeTestPluginDir(t) defer cleanup(t) client, _, closer := testVaultServerPluginDir(t, pluginDir) @@ -183,7 +183,7 @@ func TestPluginDeregisterCommand_Run(t *testing.T) { t.Run("integration with missing version", func(t *testing.T) { t.Parallel() - pluginDir, cleanup := vault.MakeTestPluginDir(t) + pluginDir, cleanup := corehelpers.MakeTestPluginDir(t) defer cleanup(t) client, _, closer := testVaultServerPluginDir(t, pluginDir) diff --git a/command/plugin_info_test.go b/command/plugin_info_test.go index 714ac1e59b..4e4924ed44 100644 --- a/command/plugin_info_test.go +++ b/command/plugin_info_test.go @@ -4,9 +4,9 @@ import ( "strings" "testing" + "github.com/hashicorp/vault/helper/testhelpers/corehelpers" "github.com/hashicorp/vault/helper/versions" "github.com/hashicorp/vault/sdk/helper/consts" - "github.com/hashicorp/vault/vault" "github.com/mitchellh/cli" ) @@ -75,7 +75,7 @@ func TestPluginInfoCommand_Run(t *testing.T) { t.Run("default", func(t *testing.T) { t.Parallel() - pluginDir, cleanup := vault.MakeTestPluginDir(t) + pluginDir, cleanup := corehelpers.MakeTestPluginDir(t) defer cleanup(t) client, _, closer := testVaultServerPluginDir(t, pluginDir) @@ -106,7 +106,7 @@ func TestPluginInfoCommand_Run(t *testing.T) { t.Run("version flag", func(t *testing.T) { t.Parallel() - pluginDir, cleanup := vault.MakeTestPluginDir(t) + pluginDir, cleanup := corehelpers.MakeTestPluginDir(t) defer cleanup(t) client, _, closer := testVaultServerPluginDir(t, pluginDir) @@ -152,7 +152,7 @@ func TestPluginInfoCommand_Run(t *testing.T) { t.Run("field", func(t *testing.T) { t.Parallel() - pluginDir, cleanup := vault.MakeTestPluginDir(t) + pluginDir, cleanup := corehelpers.MakeTestPluginDir(t) defer cleanup(t) client, _, closer := testVaultServerPluginDir(t, pluginDir) diff --git a/command/plugin_register_test.go b/command/plugin_register_test.go index c2047d070f..f2522a61e1 100644 --- a/command/plugin_register_test.go +++ b/command/plugin_register_test.go @@ -7,8 +7,8 @@ import ( "testing" "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/helper/testhelpers/corehelpers" "github.com/hashicorp/vault/sdk/helper/consts" - "github.com/hashicorp/vault/vault" "github.com/mitchellh/cli" ) @@ -80,7 +80,7 @@ func TestPluginRegisterCommand_Run(t *testing.T) { t.Run("integration", func(t *testing.T) { t.Parallel() - pluginDir, cleanup := vault.MakeTestPluginDir(t) + pluginDir, cleanup := corehelpers.MakeTestPluginDir(t) defer cleanup(t) client, _, closer := testVaultServerPluginDir(t, pluginDir) @@ -129,7 +129,7 @@ func TestPluginRegisterCommand_Run(t *testing.T) { t.Run("integration with version", func(t *testing.T) { t.Parallel() - pluginDir, cleanup := vault.MakeTestPluginDir(t) + pluginDir, cleanup := corehelpers.MakeTestPluginDir(t) defer cleanup(t) client, _, closer := testVaultServerPluginDir(t, pluginDir) diff --git a/command/plugin_reload_test.go b/command/plugin_reload_test.go index 5713d1a150..1554bf947f 100644 --- a/command/plugin_reload_test.go +++ b/command/plugin_reload_test.go @@ -5,8 +5,8 @@ import ( "testing" "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/helper/testhelpers/corehelpers" "github.com/hashicorp/vault/sdk/helper/consts" - "github.com/hashicorp/vault/vault" "github.com/mitchellh/cli" ) @@ -83,7 +83,7 @@ func TestPluginReloadCommand_Run(t *testing.T) { t.Run("integration", func(t *testing.T) { t.Parallel() - pluginDir, cleanup := vault.MakeTestPluginDir(t) + pluginDir, cleanup := corehelpers.MakeTestPluginDir(t) defer cleanup(t) client, _, closer := testVaultServerPluginDir(t, pluginDir) diff --git a/command/secrets_tune_test.go b/command/secrets_tune_test.go index 41c6bd2f6f..2d2799bb50 100644 --- a/command/secrets_tune_test.go +++ b/command/secrets_tune_test.go @@ -6,8 +6,8 @@ import ( "github.com/go-test/deep" "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/helper/testhelpers/corehelpers" "github.com/hashicorp/vault/sdk/helper/consts" - "github.com/hashicorp/vault/vault" "github.com/mitchellh/cli" ) @@ -150,7 +150,7 @@ func TestSecretsTuneCommand_Run(t *testing.T) { t.Run("integration", func(t *testing.T) { t.Run("flags_all", func(t *testing.T) { t.Parallel() - pluginDir, cleanup := vault.MakeTestPluginDir(t) + pluginDir, cleanup := corehelpers.MakeTestPluginDir(t) defer cleanup(t) client, _, closer := testVaultServerPluginDir(t, pluginDir) diff --git a/helper/testhelpers/corehelpers/corehelpers.go b/helper/testhelpers/corehelpers/corehelpers.go new file mode 100644 index 0000000000..db94ecc94a --- /dev/null +++ b/helper/testhelpers/corehelpers/corehelpers.go @@ -0,0 +1,420 @@ +// Package corehelpers contains testhelpers that don't depend on package vault, +// and thus can be used within vault (as well as elsewhere.) +package corehelpers + +import ( + "bytes" + "context" + "crypto/sha256" + "io/ioutil" + "os" + "path/filepath" + "sync" + "time" + + "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/audit" + "github.com/hashicorp/vault/builtin/credential/approle" + "github.com/hashicorp/vault/plugins/database/mysql" + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/helper/consts" + "github.com/hashicorp/vault/sdk/helper/salt" + "github.com/hashicorp/vault/sdk/logical" + "github.com/mitchellh/go-testing-interface" +) + +// RetryUntil runs f until it returns a nil result or the timeout is reached. +// If a nil result hasn't been obtained by timeout, calls t.Fatal. +func RetryUntil(t testing.T, timeout time.Duration, f func() error) { + t.Helper() + deadline := time.Now().Add(timeout) + var err error + for time.Now().Before(deadline) { + if err = f(); err == nil { + return + } + time.Sleep(100 * time.Millisecond) + } + t.Fatalf("did not complete before deadline, err: %v", err) +} + +// MakeTestPluginDir creates a temporary directory suitable for holding plugins. +// This helper also resolves symlinks to make tests happy on OS X. +func MakeTestPluginDir(t testing.T) (string, func(t testing.T)) { + if t != nil { + t.Helper() + } + + dir, err := os.MkdirTemp("", "") + if err != nil { + if t == nil { + panic(err) + } + t.Fatal(err) + } + + // OSX tempdir are /var, but actually symlinked to /private/var + dir, err = filepath.EvalSymlinks(dir) + if err != nil { + if t == nil { + panic(err) + } + t.Fatal(err) + } + + return dir, func(t testing.T) { + if err := os.RemoveAll(dir); err != nil { + if t == nil { + panic(err) + } + t.Fatal(err) + } + } +} + +func NewMockBuiltinRegistry() *mockBuiltinRegistry { + return &mockBuiltinRegistry{ + forTesting: map[string]mockBackend{ + "mysql-database-plugin": {PluginType: consts.PluginTypeDatabase}, + "postgresql-database-plugin": {PluginType: consts.PluginTypeDatabase}, + "approle": {PluginType: consts.PluginTypeCredential}, + "pending-removal-test-plugin": { + PluginType: consts.PluginTypeCredential, + DeprecationStatus: consts.PendingRemoval, + }, + "aws": {PluginType: consts.PluginTypeCredential}, + "consul": {PluginType: consts.PluginTypeSecrets}, + }, + } +} + +type mockBackend struct { + consts.PluginType + consts.DeprecationStatus +} + +type mockBuiltinRegistry struct { + forTesting map[string]mockBackend +} + +func toFunc(f logical.Factory) func() (interface{}, error) { + return func() (interface{}, error) { + return f, nil + } +} + +func (m *mockBuiltinRegistry) Get(name string, pluginType consts.PluginType) (func() (interface{}, error), bool) { + testBackend, ok := m.forTesting[name] + if !ok { + return nil, false + } + testPluginType := testBackend.PluginType + if pluginType != testPluginType { + return nil, false + } + + switch name { + case "approle", "pending-removal-test-plugin": + return toFunc(approle.Factory), true + case "aws": + return toFunc(func(ctx context.Context, config *logical.BackendConfig) (logical.Backend, error) { + b := new(framework.Backend) + b.Setup(ctx, config) + b.BackendType = logical.TypeCredential + return b, nil + }), true + case "postgresql-database-plugin": + return toFunc(func(ctx context.Context, config *logical.BackendConfig) (logical.Backend, error) { + b := new(framework.Backend) + b.Setup(ctx, config) + b.BackendType = logical.TypeLogical + return b, nil + }), true + case "mysql-database-plugin": + return mysql.New(mysql.DefaultUserNameTemplate), true + case "consul": + return toFunc(func(ctx context.Context, config *logical.BackendConfig) (logical.Backend, error) { + b := new(framework.Backend) + b.Setup(ctx, config) + b.BackendType = logical.TypeLogical + return b, nil + }), true + default: + return nil, false + } +} + +// Keys only supports getting a realistic list of the keys for database plugins, +// and approle +func (m *mockBuiltinRegistry) Keys(pluginType consts.PluginType) []string { + switch pluginType { + case consts.PluginTypeDatabase: + // This is a hard-coded reproduction of the db plugin keys in + // helper/builtinplugins/registry.go. The registry isn't directly used + // because it causes import cycles. + return []string{ + "mysql-database-plugin", + "mysql-aurora-database-plugin", + "mysql-rds-database-plugin", + "mysql-legacy-database-plugin", + + "cassandra-database-plugin", + "couchbase-database-plugin", + "elasticsearch-database-plugin", + "hana-database-plugin", + "influxdb-database-plugin", + "mongodb-database-plugin", + "mongodbatlas-database-plugin", + "mssql-database-plugin", + "postgresql-database-plugin", + "redis-elasticache-database-plugin", + "redshift-database-plugin", + "redis-database-plugin", + "snowflake-database-plugin", + } + case consts.PluginTypeCredential: + return []string{ + "pending-removal-test-plugin", + "approle", + } + } + return []string{} +} + +func (m *mockBuiltinRegistry) Contains(name string, pluginType consts.PluginType) bool { + for _, key := range m.Keys(pluginType) { + if key == name { + return true + } + } + return false +} + +func (m *mockBuiltinRegistry) DeprecationStatus(name string, pluginType consts.PluginType) (consts.DeprecationStatus, bool) { + if m.Contains(name, pluginType) { + return m.forTesting[name].DeprecationStatus, true + } + + return consts.Unknown, false +} + +func TestNoopAudit(t testing.T, config map[string]string) *NoopAudit { + n, err := NewNoopAudit(config) + if err != nil { + t.Fatal(err) + } + return n +} + +func NewNoopAudit(config map[string]string) (*NoopAudit, error) { + view := &logical.InmemStorage{} + err := view.Put(context.Background(), &logical.StorageEntry{ + Key: "salt", + Value: []byte("foo"), + }) + if err != nil { + return nil, err + } + + n := &NoopAudit{ + Config: &audit.BackendConfig{ + SaltView: view, + SaltConfig: &salt.Config{ + HMAC: sha256.New, + HMACType: "hmac-sha256", + }, + Config: config, + }, + } + n.formatter.AuditFormatWriter = &audit.JSONFormatWriter{ + SaltFunc: n.Salt, + } + return n, nil +} + +func NoopAuditFactory(records **[][]byte) audit.Factory { + return func(_ context.Context, config *audit.BackendConfig) (audit.Backend, error) { + n, err := NewNoopAudit(config.Config) + if err != nil { + return nil, err + } + if records != nil { + *records = &n.records + } + return n, nil + } +} + +type NoopAudit struct { + Config *audit.BackendConfig + ReqErr error + ReqAuth []*logical.Auth + Req []*logical.Request + ReqHeaders []map[string][]string + ReqNonHMACKeys []string + ReqErrs []error + + RespErr error + RespAuth []*logical.Auth + RespReq []*logical.Request + Resp []*logical.Response + RespNonHMACKeys [][]string + RespReqNonHMACKeys [][]string + RespErrs []error + + formatter audit.AuditFormatter + records [][]byte + l sync.RWMutex + salt *salt.Salt + saltMutex sync.RWMutex +} + +func (n *NoopAudit) LogRequest(ctx context.Context, in *logical.LogInput) error { + n.l.Lock() + defer n.l.Unlock() + if n.formatter.AuditFormatWriter != nil { + var w bytes.Buffer + err := n.formatter.FormatRequest(ctx, &w, audit.FormatterConfig{}, in) + if err != nil { + return err + } + n.records = append(n.records, w.Bytes()) + } + + n.ReqAuth = append(n.ReqAuth, in.Auth) + n.Req = append(n.Req, in.Request) + n.ReqHeaders = append(n.ReqHeaders, in.Request.Headers) + n.ReqNonHMACKeys = in.NonHMACReqDataKeys + n.ReqErrs = append(n.ReqErrs, in.OuterErr) + + return n.ReqErr +} + +func (n *NoopAudit) LogResponse(ctx context.Context, in *logical.LogInput) error { + n.l.Lock() + defer n.l.Unlock() + + if n.formatter.AuditFormatWriter != nil { + var w bytes.Buffer + err := n.formatter.FormatResponse(ctx, &w, audit.FormatterConfig{}, in) + if err != nil { + return err + } + n.records = append(n.records, w.Bytes()) + } + + n.RespAuth = append(n.RespAuth, in.Auth) + n.RespReq = append(n.RespReq, in.Request) + n.Resp = append(n.Resp, in.Response) + n.RespErrs = append(n.RespErrs, in.OuterErr) + + if in.Response != nil { + n.RespNonHMACKeys = append(n.RespNonHMACKeys, in.NonHMACRespDataKeys) + n.RespReqNonHMACKeys = append(n.RespReqNonHMACKeys, in.NonHMACReqDataKeys) + } + + return n.RespErr +} + +func (n *NoopAudit) LogTestMessage(ctx context.Context, in *logical.LogInput, config map[string]string) error { + n.l.Lock() + defer n.l.Unlock() + var w bytes.Buffer + tempFormatter := audit.NewTemporaryFormatter(config["format"], config["prefix"]) + err := tempFormatter.FormatResponse(ctx, &w, audit.FormatterConfig{}, in) + if err != nil { + return err + } + n.records = append(n.records, w.Bytes()) + return nil +} + +func (n *NoopAudit) Salt(ctx context.Context) (*salt.Salt, error) { + n.saltMutex.RLock() + if n.salt != nil { + defer n.saltMutex.RUnlock() + return n.salt, nil + } + n.saltMutex.RUnlock() + n.saltMutex.Lock() + defer n.saltMutex.Unlock() + if n.salt != nil { + return n.salt, nil + } + salt, err := salt.NewSalt(ctx, n.Config.SaltView, n.Config.SaltConfig) + if err != nil { + return nil, err + } + n.salt = salt + return salt, nil +} + +func (n *NoopAudit) GetHash(ctx context.Context, data string) (string, error) { + salt, err := n.Salt(ctx) + if err != nil { + return "", err + } + return salt.GetIdentifiedHMAC(data), nil +} + +func (n *NoopAudit) Reload(ctx context.Context) error { + return nil +} + +func (n *NoopAudit) Invalidate(ctx context.Context) { + n.saltMutex.Lock() + defer n.saltMutex.Unlock() + n.salt = nil +} + +type TestLogger struct { + hclog.Logger + Path string + File *os.File + sink hclog.SinkAdapter +} + +func NewTestLogger(t testing.T) *TestLogger { + var logFile *os.File + var logPath string + output := os.Stderr + + logDir := os.Getenv("VAULT_TEST_LOG_DIR") + if logDir != "" { + logPath = filepath.Join(logDir, t.Name()+".log") + // t.Name may include slashes. + dir, _ := filepath.Split(logPath) + err := os.MkdirAll(dir, 0o755) + if err != nil { + t.Fatal(err) + } + logFile, err = os.Create(logPath) + if err != nil { + t.Fatal(err) + } + output = logFile + } + + // We send nothing on the regular logger, that way we can later deregister + // the sink to stop logging during cluster cleanup. + logger := hclog.NewInterceptLogger(&hclog.LoggerOptions{ + Output: ioutil.Discard, + IndependentLevels: true, + }) + sink := hclog.NewSinkAdapter(&hclog.LoggerOptions{ + Output: output, + Level: hclog.Trace, + IndependentLevels: true, + }) + logger.RegisterSink(sink) + return &TestLogger{ + Path: logPath, + File: logFile, + Logger: logger, + sink: sink, + } +} + +func (tl *TestLogger) StopLogging() { + tl.Logger.(hclog.InterceptLogger).DeregisterSink(tl.sink) +} diff --git a/helper/testhelpers/logical/testing.go b/helper/testhelpers/logical/testing.go index 4740ff6be3..79be91f7a6 100644 --- a/helper/testhelpers/logical/testing.go +++ b/helper/testhelpers/logical/testing.go @@ -9,11 +9,11 @@ import ( "sort" "testing" - log "github.com/hashicorp/go-hclog" - "github.com/hashicorp/errwrap" + log "github.com/hashicorp/go-hclog" "github.com/hashicorp/vault/api" "github.com/hashicorp/vault/helper/namespace" + "github.com/hashicorp/vault/helper/testhelpers/corehelpers" "github.com/hashicorp/vault/http" "github.com/hashicorp/vault/sdk/helper/logging" "github.com/hashicorp/vault/sdk/logical" @@ -166,7 +166,7 @@ func Test(tt TestT, c TestCase) { config := &vault.CoreConfig{ Physical: phys, DisableMlock: true, - BuiltinRegistry: vault.NewMockBuiltinRegistry(), + BuiltinRegistry: corehelpers.NewMockBuiltinRegistry(), } if c.LogicalBackend != nil || c.LogicalFactory != nil { diff --git a/http/logical_test.go b/http/logical_test.go index fc6fc76581..52c77151ac 100644 --- a/http/logical_test.go +++ b/http/logical_test.go @@ -18,6 +18,7 @@ import ( "github.com/hashicorp/vault/api" auditFile "github.com/hashicorp/vault/builtin/audit/file" credUserpass "github.com/hashicorp/vault/builtin/credential/userpass" + "github.com/hashicorp/vault/helper/testhelpers/corehelpers" "github.com/hashicorp/vault/internalshared/configutil" "github.com/hashicorp/vault/sdk/helper/consts" "github.com/hashicorp/vault/sdk/helper/logging" @@ -474,13 +475,10 @@ func TestLogical_RespondWithStatusCode(t *testing.T) { func TestLogical_Audit_invalidWrappingToken(t *testing.T) { // Create a noop audit backend - var noop *vault.NoopAudit + noop := corehelpers.TestNoopAudit(t, nil) c, _, root := vault.TestCoreUnsealedWithConfig(t, &vault.CoreConfig{ AuditBackends: map[string]audit.Factory{ "noop": func(ctx context.Context, config *audit.BackendConfig) (audit.Backend, error) { - noop = &vault.NoopAudit{ - Config: config, - } return noop, nil }, }, @@ -636,7 +634,7 @@ func TestLogical_AuditPort(t *testing.T) { // workaround kv-v2 initialization upgrade errors numFailures := 0 - vault.RetryUntil(t, 10*time.Second, func() error { + corehelpers.RetryUntil(t, 10*time.Second, func() error { resp, err := c.Logical().Write("kv/data/foo", writeData) if err != nil { if strings.Contains(err.Error(), "Upgrading from non-versioned to versioned data") { diff --git a/http/sys_auth_test.go b/http/sys_auth_test.go index 2d1fdf8144..0071ab030c 100644 --- a/http/sys_auth_test.go +++ b/http/sys_auth_test.go @@ -8,6 +8,7 @@ import ( "time" "github.com/go-test/deep" + "github.com/hashicorp/vault/helper/testhelpers/corehelpers" "github.com/hashicorp/vault/helper/versions" "github.com/hashicorp/vault/sdk/helper/consts" "github.com/hashicorp/vault/vault" @@ -485,7 +486,7 @@ func TestSysRemountAuth(t *testing.T) { // Poll until the remount succeeds var remountResp map[string]interface{} testResponseBody(t, resp, &remountResp) - vault.RetryUntil(t, 5*time.Second, func() error { + corehelpers.RetryUntil(t, 5*time.Second, func() error { resp = testHttpGet(t, token, addr+"/v1/sys/remount/status/"+remountResp["migration_id"].(string)) testResponseStatus(t, resp, 200) diff --git a/http/sys_generate_root_test.go b/http/sys_generate_root_test.go index f226d0042b..36e25f8211 100644 --- a/http/sys_generate_root_test.go +++ b/http/sys_generate_root_test.go @@ -12,8 +12,10 @@ import ( "testing" "github.com/go-test/deep" + "github.com/hashicorp/vault/audit" "github.com/hashicorp/vault/helper/namespace" "github.com/hashicorp/vault/helper/pgpkeys" + "github.com/hashicorp/vault/helper/testhelpers/corehelpers" "github.com/hashicorp/vault/sdk/helper/xor" "github.com/hashicorp/vault/sdk/logical" "github.com/hashicorp/vault/vault" @@ -224,9 +226,11 @@ func enableNoopAudit(t *testing.T, token string, core *vault.Core) { func testCoreUnsealedWithAudit(t *testing.T, records **[][]byte) (*vault.Core, [][]byte, string) { conf := &vault.CoreConfig{ - BuiltinRegistry: vault.NewMockBuiltinRegistry(), + BuiltinRegistry: corehelpers.NewMockBuiltinRegistry(), + AuditBackends: map[string]audit.Factory{ + "noop": corehelpers.NoopAuditFactory(records), + }, } - vault.AddNoopAudit(conf, records) core, keys, token := vault.TestCoreUnsealedWithConfig(t, conf) return core, keys, token } diff --git a/http/sys_metrics_test.go b/http/sys_metrics_test.go index 241caac2db..e8770a1bfa 100644 --- a/http/sys_metrics_test.go +++ b/http/sys_metrics_test.go @@ -4,6 +4,8 @@ import ( "testing" "time" + "github.com/hashicorp/vault/helper/testhelpers/corehelpers" + "github.com/armon/go-metrics" "github.com/hashicorp/vault/helper/metricsutil" "github.com/hashicorp/vault/internalshared/configutil" @@ -14,7 +16,7 @@ func TestSysMetricsUnauthenticated(t *testing.T) { inm := metrics.NewInmemSink(10*time.Second, time.Minute) metrics.DefaultInmemSignal(inm) conf := &vault.CoreConfig{ - BuiltinRegistry: vault.NewMockBuiltinRegistry(), + BuiltinRegistry: corehelpers.NewMockBuiltinRegistry(), MetricsHelper: metricsutil.NewMetricsHelper(inm, true), } core, _, token := vault.TestCoreUnsealedWithConfig(t, conf) diff --git a/http/sys_mount_test.go b/http/sys_mount_test.go index 09ca8c8c35..ae33a25816 100644 --- a/http/sys_mount_test.go +++ b/http/sys_mount_test.go @@ -9,6 +9,7 @@ import ( "github.com/fatih/structs" "github.com/go-test/deep" + "github.com/hashicorp/vault/helper/testhelpers/corehelpers" "github.com/hashicorp/vault/helper/versions" "github.com/hashicorp/vault/sdk/helper/consts" "github.com/hashicorp/vault/vault" @@ -436,7 +437,7 @@ func TestSysRemount(t *testing.T) { // Poll until the remount succeeds var remountResp map[string]interface{} testResponseBody(t, resp, &remountResp) - vault.RetryUntil(t, 5*time.Second, func() error { + corehelpers.RetryUntil(t, 5*time.Second, func() error { resp = testHttpGet(t, token, addr+"/v1/sys/remount/status/"+remountResp["migration_id"].(string)) testResponseStatus(t, resp, 200) diff --git a/vault/audit_test.go b/vault/audit_test.go index ebd7de504d..de23b4cf45 100644 --- a/vault/audit_test.go +++ b/vault/audit_test.go @@ -9,6 +9,8 @@ import ( "testing" "time" + "github.com/hashicorp/vault/helper/testhelpers/corehelpers" + "github.com/hashicorp/errwrap" log "github.com/hashicorp/go-hclog" uuid "github.com/hashicorp/go-uuid" @@ -30,7 +32,8 @@ func TestAudit_ReadOnlyViewDuringMount(t *testing.T) { if err == nil || !strings.Contains(err.Error(), logical.ErrSetupReadOnly.Error()) { t.Fatalf("expected a read-only error") } - return &NoopAudit{}, nil + factory := corehelpers.NoopAuditFactory(nil) + return factory(ctx, config) } me := &MountEntry{ @@ -46,11 +49,7 @@ func TestAudit_ReadOnlyViewDuringMount(t *testing.T) { func TestCore_EnableAudit(t *testing.T) { c, keys, _ := TestCoreUnsealed(t) - c.auditBackends["noop"] = func(ctx context.Context, config *audit.BackendConfig) (audit.Backend, error) { - return &NoopAudit{ - Config: config, - }, nil - } + c.auditBackends["noop"] = corehelpers.NoopAuditFactory(nil) me := &MountEntry{ Table: auditTableType, @@ -71,11 +70,7 @@ func TestCore_EnableAudit(t *testing.T) { AuditBackends: make(map[string]audit.Factory), DisableMlock: true, } - conf.AuditBackends["noop"] = func(ctx context.Context, config *audit.BackendConfig) (audit.Backend, error) { - return &NoopAudit{ - Config: config, - }, nil - } + conf.AuditBackends["noop"] = corehelpers.NoopAuditFactory(nil) c2, err := NewCore(conf) if err != nil { t.Fatalf("err: %v", err) @@ -104,12 +99,7 @@ func TestCore_EnableAudit(t *testing.T) { func TestCore_EnableAudit_MixedFailures(t *testing.T) { c, _, _ := TestCoreUnsealed(t) - c.auditBackends["noop"] = func(ctx context.Context, config *audit.BackendConfig) (audit.Backend, error) { - return &NoopAudit{ - Config: config, - }, nil - } - + c.auditBackends["noop"] = corehelpers.NoopAuditFactory(nil) c.auditBackends["fail"] = func(ctx context.Context, config *audit.BackendConfig) (audit.Backend, error) { return nil, fmt.Errorf("failing enabling") } @@ -158,12 +148,7 @@ func TestCore_EnableAudit_MixedFailures(t *testing.T) { // correctly func TestCore_EnableAudit_Local(t *testing.T) { c, _, _ := TestCoreUnsealed(t) - c.auditBackends["noop"] = func(ctx context.Context, config *audit.BackendConfig) (audit.Backend, error) { - return &NoopAudit{ - Config: config, - }, nil - } - + c.auditBackends["noop"] = corehelpers.NoopAuditFactory(nil) c.auditBackends["fail"] = func(ctx context.Context, config *audit.BackendConfig) (audit.Backend, error) { return nil, fmt.Errorf("failing enabling") } @@ -249,11 +234,7 @@ func TestCore_EnableAudit_Local(t *testing.T) { func TestCore_DisableAudit(t *testing.T) { c, keys, _ := TestCoreUnsealed(t) - c.auditBackends["noop"] = func(ctx context.Context, config *audit.BackendConfig) (audit.Backend, error) { - return &NoopAudit{ - Config: config, - }, nil - } + c.auditBackends["noop"] = corehelpers.NoopAuditFactory(nil) existed, err := c.disableAudit(namespace.RootContext(nil), "foo", true) if existed && err != nil { @@ -357,8 +338,8 @@ func verifyDefaultAuditTable(t *testing.T, table *MountTable) { func TestAuditBroker_LogRequest(t *testing.T) { l := logging.NewVaultLogger(log.Trace) b := NewAuditBroker(l) - a1 := &NoopAudit{} - a2 := &NoopAudit{} + a1 := corehelpers.TestNoopAudit(t, nil) + a2 := corehelpers.TestNoopAudit(t, nil) b.Register("foo", a1, nil, false) b.Register("bar", a2, nil, false) @@ -406,12 +387,13 @@ func TestAuditBroker_LogRequest(t *testing.T) { Request: reqCopy, OuterErr: reqErrs, } - err = b.LogRequest(context.Background(), logInput, headersConf) + ctx := namespace.RootContext(context.Background()) + err = b.LogRequest(ctx, logInput, headersConf) if err != nil { t.Fatalf("err: %v", err) } - for _, a := range []*NoopAudit{a1, a2} { + for _, a := range []*corehelpers.NoopAudit{a1, a2} { if !reflect.DeepEqual(a.ReqAuth[0], auth) { t.Fatalf("Bad: %#v", a.ReqAuth[0]) } @@ -429,13 +411,13 @@ func TestAuditBroker_LogRequest(t *testing.T) { Auth: auth, Request: req, } - if err := b.LogRequest(context.Background(), logInput, headersConf); err != nil { + if err := b.LogRequest(ctx, logInput, headersConf); err != nil { t.Fatalf("err: %v", err) } // Should FAIL work with both failing backends a2.ReqErr = fmt.Errorf("failed") - if err := b.LogRequest(context.Background(), logInput, headersConf); !errwrap.Contains(err, "no audit backend succeeded in logging the request") { + if err := b.LogRequest(ctx, logInput, headersConf); !errwrap.Contains(err, "no audit backend succeeded in logging the request") { t.Fatalf("err: %v", err) } } @@ -443,8 +425,8 @@ func TestAuditBroker_LogRequest(t *testing.T) { func TestAuditBroker_LogResponse(t *testing.T) { l := logging.NewVaultLogger(log.Trace) b := NewAuditBroker(l) - a1 := &NoopAudit{} - a2 := &NoopAudit{} + a1 := corehelpers.TestNoopAudit(t, nil) + a2 := corehelpers.TestNoopAudit(t, nil) b.Register("foo", a1, nil, false) b.Register("bar", a2, nil, false) @@ -503,12 +485,13 @@ func TestAuditBroker_LogResponse(t *testing.T) { Response: respCopy, OuterErr: respErr, } - err = b.LogResponse(context.Background(), logInput, headersConf) + ctx := namespace.RootContext(context.Background()) + err = b.LogResponse(ctx, logInput, headersConf) if err != nil { t.Fatalf("err: %v", err) } - for _, a := range []*NoopAudit{a1, a2} { + for _, a := range []*corehelpers.NoopAudit{a1, a2} { if !reflect.DeepEqual(a.RespAuth[0], auth) { t.Fatalf("Bad: %#v", a.ReqAuth[0]) } @@ -531,14 +514,14 @@ func TestAuditBroker_LogResponse(t *testing.T) { Response: resp, OuterErr: respErr, } - err = b.LogResponse(context.Background(), logInput, headersConf) + err = b.LogResponse(ctx, logInput, headersConf) if err != nil { t.Fatalf("err: %v", err) } // Should FAIL work with both failing backends a2.RespErr = fmt.Errorf("failed") - err = b.LogResponse(context.Background(), logInput, headersConf) + err = b.LogResponse(ctx, logInput, headersConf) if !strings.Contains(err.Error(), "no audit backend succeeded in logging the response") { t.Fatalf("err: %v", err) } @@ -549,8 +532,8 @@ func TestAuditBroker_AuditHeaders(t *testing.T) { b := NewAuditBroker(logger) _, barrier, _ := mockBarrier(t) view := NewBarrierView(barrier, "headers/") - a1 := &NoopAudit{} - a2 := &NoopAudit{} + a1 := corehelpers.TestNoopAudit(t, nil) + a2 := corehelpers.TestNoopAudit(t, nil) b.Register("foo", a1, nil, false) b.Register("bar", a2, nil, false) @@ -591,7 +574,8 @@ func TestAuditBroker_AuditHeaders(t *testing.T) { Request: reqCopy, OuterErr: respErr, } - err = b.LogRequest(context.Background(), logInput, headersConf) + ctx := namespace.RootContext(context.Background()) + err = b.LogRequest(ctx, logInput, headersConf) if err != nil { t.Fatalf("err: %v", err) } @@ -601,7 +585,7 @@ func TestAuditBroker_AuditHeaders(t *testing.T) { "x-vault-header": {"bar"}, } - for _, a := range []*NoopAudit{a1, a2} { + for _, a := range []*corehelpers.NoopAudit{a1, a2} { if !reflect.DeepEqual(a.ReqHeaders[0], expected) { t.Fatalf("Bad audited headers: %#v", a.Req[0].Headers) } @@ -614,14 +598,14 @@ func TestAuditBroker_AuditHeaders(t *testing.T) { Request: req, OuterErr: respErr, } - err = b.LogRequest(context.Background(), logInput, headersConf) + err = b.LogRequest(ctx, logInput, headersConf) if err != nil { t.Fatalf("err: %v", err) } // Should FAIL work with both failing backends a2.ReqErr = fmt.Errorf("failed") - err = b.LogRequest(context.Background(), logInput, headersConf) + err = b.LogRequest(ctx, logInput, headersConf) if !errwrap.Contains(err, "no audit backend succeeded in logging the request") { t.Fatalf("err: %v", err) } diff --git a/vault/auth_test.go b/vault/auth_test.go index 408fe66cd7..c895fc987c 100644 --- a/vault/auth_test.go +++ b/vault/auth_test.go @@ -7,6 +7,8 @@ import ( "testing" "time" + "github.com/hashicorp/vault/helper/testhelpers/corehelpers" + "github.com/armon/go-metrics" "github.com/hashicorp/vault/helper/metricsutil" "github.com/hashicorp/vault/helper/namespace" @@ -118,7 +120,7 @@ func TestCore_DefaultAuthTable(t *testing.T) { conf := &CoreConfig{ Physical: c.physical, DisableMlock: true, - BuiltinRegistry: NewMockBuiltinRegistry(), + BuiltinRegistry: corehelpers.NewMockBuiltinRegistry(), MetricSink: metricsutil.NewClusterMetricSink("test-cluster", inmemSink), MetricsHelper: metricsutil.NewMetricsHelper(inmemSink, false), } @@ -150,7 +152,7 @@ func TestCore_BuiltinRegistry(t *testing.T) { PluginDirectory: "/Users/foo", DisableMlock: true, - BuiltinRegistry: NewMockBuiltinRegistry(), + BuiltinRegistry: corehelpers.NewMockBuiltinRegistry(), } c, _, _ := TestCoreUnsealedWithConfig(t, conf) @@ -201,7 +203,7 @@ func TestCore_EnableCredential(t *testing.T) { conf := &CoreConfig{ Physical: c.physical, DisableMlock: true, - BuiltinRegistry: NewMockBuiltinRegistry(), + BuiltinRegistry: corehelpers.NewMockBuiltinRegistry(), MetricSink: metricsutil.NewClusterMetricSink("test-cluster", inmemSink), MetricsHelper: metricsutil.NewMetricsHelper(inmemSink, false), } @@ -260,7 +262,7 @@ func TestCore_EnableCredential_aws_ec2(t *testing.T) { conf := &CoreConfig{ Physical: c.physical, DisableMlock: true, - BuiltinRegistry: NewMockBuiltinRegistry(), + BuiltinRegistry: corehelpers.NewMockBuiltinRegistry(), MetricSink: metricsutil.NewClusterMetricSink("test-cluster", inmemSink), MetricsHelper: metricsutil.NewMetricsHelper(inmemSink, false), } @@ -462,7 +464,7 @@ func TestCore_DisableCredential(t *testing.T) { conf := &CoreConfig{ Physical: c.physical, DisableMlock: true, - BuiltinRegistry: NewMockBuiltinRegistry(), + BuiltinRegistry: corehelpers.NewMockBuiltinRegistry(), MetricSink: metricsutil.NewClusterMetricSink("test-cluster", inmemSink), MetricsHelper: metricsutil.NewMetricsHelper(inmemSink, false), } diff --git a/vault/cluster_test.go b/vault/cluster_test.go index c98f70df94..845259063b 100644 --- a/vault/cluster_test.go +++ b/vault/cluster_test.go @@ -11,6 +11,7 @@ import ( "time" log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/helper/testhelpers/corehelpers" "github.com/hashicorp/vault/sdk/helper/consts" "github.com/hashicorp/vault/sdk/helper/logging" "github.com/hashicorp/vault/sdk/logical" @@ -320,7 +321,7 @@ func testCluster_ForwardRequests(t *testing.T, c *TestClusterCore, rootToken, re if isLeader { t.Fatal("core should not be leader") } - RetryUntil(t, 5*time.Second, func() error { + corehelpers.RetryUntil(t, 5*time.Second, func() error { state := c.ActiveNodeReplicationState() if state == 0 { return fmt.Errorf("heartbeats have not yet returned a valid active node replication state: %d", state) diff --git a/vault/core_test.go b/vault/core_test.go index 84e6300949..090f871c9b 100644 --- a/vault/core_test.go +++ b/vault/core_test.go @@ -13,9 +13,11 @@ import ( "github.com/go-test/deep" "github.com/hashicorp/errwrap" log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/go-secure-stdlib/strutil" "github.com/hashicorp/go-uuid" "github.com/hashicorp/vault/audit" "github.com/hashicorp/vault/helper/namespace" + "github.com/hashicorp/vault/helper/testhelpers/corehelpers" "github.com/hashicorp/vault/internalshared/configutil" "github.com/hashicorp/vault/sdk/helper/consts" "github.com/hashicorp/vault/sdk/helper/jsonutil" @@ -1130,10 +1132,10 @@ func TestCore_HandleLogin_Token(t *testing.T) { func TestCore_HandleRequest_AuditTrail(t *testing.T) { // Create a noop audit backend - noop := &NoopAudit{} + noop := &corehelpers.NoopAudit{} c, _, root := TestCoreUnsealed(t) c.auditBackends["noop"] = func(ctx context.Context, config *audit.BackendConfig) (audit.Backend, error) { - noop = &NoopAudit{ + noop = &corehelpers.NoopAudit{ Config: config, } return noop, nil @@ -1194,10 +1196,10 @@ func TestCore_HandleRequest_AuditTrail(t *testing.T) { func TestCore_HandleRequest_AuditTrail_noHMACKeys(t *testing.T) { // Create a noop audit backend - var noop *NoopAudit + var noop *corehelpers.NoopAudit c, _, root := TestCoreUnsealed(t) c.auditBackends["noop"] = func(ctx context.Context, config *audit.BackendConfig) (audit.Backend, error) { - noop = &NoopAudit{ + noop = &corehelpers.NoopAudit{ Config: config, } return noop, nil @@ -1288,17 +1290,17 @@ func TestCore_HandleRequest_AuditTrail_noHMACKeys(t *testing.T) { if _, err := c.HandleRequest(namespace.RootContext(nil), req); err != nil { t.Fatalf("err: %v", err) } - if len(noop.RespNonHMACKeys) != 1 || noop.RespNonHMACKeys[0] != "baz" { + if len(noop.RespNonHMACKeys) != 1 || !strutil.EquivalentSlices(noop.RespNonHMACKeys[0], []string{"baz"}) { t.Fatalf("Bad: %#v", noop.RespNonHMACKeys) } - if len(noop.RespReqNonHMACKeys) != 1 || noop.RespReqNonHMACKeys[0] != "foo" { + if len(noop.RespReqNonHMACKeys) != 1 || !strutil.EquivalentSlices(noop.RespReqNonHMACKeys[0], []string{"foo"}) { t.Fatalf("Bad: %#v", noop.RespReqNonHMACKeys) } } func TestCore_HandleLogin_AuditTrail(t *testing.T) { // Create a badass credential backend that always logs in as armon - noop := &NoopAudit{} + noop := &corehelpers.NoopAudit{} noopBack := &NoopBackend{ Login: []string{"login"}, Response: &logical.Response{ @@ -1319,7 +1321,7 @@ func TestCore_HandleLogin_AuditTrail(t *testing.T) { return noopBack, nil } c.auditBackends["noop"] = func(ctx context.Context, config *audit.BackendConfig) (audit.Backend, error) { - noop = &NoopAudit{ + noop = &corehelpers.NoopAudit{ Config: config, } return noop, nil @@ -2022,7 +2024,7 @@ func testCore_Standby_Common(t *testing.T, inm physical.Backend, inmha physical. HAPhysical: inmha, RedirectAddr: redirectOriginal, DisableMlock: true, - BuiltinRegistry: NewMockBuiltinRegistry(), + BuiltinRegistry: corehelpers.NewMockBuiltinRegistry(), }) if err != nil { t.Fatalf("err: %v", err) diff --git a/vault/external_plugin_test.go b/vault/external_plugin_test.go index a1e8b5316d..a604cd44d4 100644 --- a/vault/external_plugin_test.go +++ b/vault/external_plugin_test.go @@ -15,6 +15,7 @@ import ( "testing" "github.com/hashicorp/vault/helper/namespace" + "github.com/hashicorp/vault/helper/testhelpers/corehelpers" "github.com/hashicorp/vault/sdk/framework" "github.com/hashicorp/vault/sdk/helper/consts" "github.com/hashicorp/vault/sdk/helper/pluginutil" @@ -42,7 +43,7 @@ type testPlugin struct { // version is used to override the plugin's self-reported version func testCoreWithPlugins(t *testing.T, typ consts.PluginType, versions ...string) (*Core, []testPlugin) { t.Helper() - pluginDir, cleanup := MakeTestPluginDir(t) + pluginDir, cleanup := corehelpers.MakeTestPluginDir(t) t.Cleanup(func() { cleanup(t) }) var plugins []testPlugin @@ -50,7 +51,7 @@ func testCoreWithPlugins(t *testing.T, typ consts.PluginType, versions ...string plugins = append(plugins, compilePlugin(t, typ, version, pluginDir)) } conf := &CoreConfig{ - BuiltinRegistry: NewMockBuiltinRegistry(), + BuiltinRegistry: corehelpers.NewMockBuiltinRegistry(), PluginDirectory: pluginDir, } core := TestCoreWithSealAndUI(t, conf) @@ -280,7 +281,7 @@ func TestCore_EnableExternalPlugin_MultipleVersions(t *testing.T) { } func TestCore_EnableExternalPlugin_Deregister_SealUnseal(t *testing.T) { - pluginDir, cleanup := MakeTestPluginDir(t) + pluginDir, cleanup := corehelpers.MakeTestPluginDir(t) t.Cleanup(func() { cleanup(t) }) // create an external plugin to shadow the builtin "pending-removal-test-plugin" @@ -291,7 +292,7 @@ func TestCore_EnableExternalPlugin_Deregister_SealUnseal(t *testing.T) { t.Fatal(err) } conf := &CoreConfig{ - BuiltinRegistry: NewMockBuiltinRegistry(), + BuiltinRegistry: corehelpers.NewMockBuiltinRegistry(), PluginDirectory: pluginDir, } @@ -352,7 +353,7 @@ func TestCore_EnableExternalPlugin_Deregister_SealUnseal(t *testing.T) { // version store is cleared. Vault sees the next unseal as a major upgrade and // should immediately shut down. func TestCore_Unseal_isMajorVersionFirstMount_PendingRemoval_Plugin(t *testing.T) { - pluginDir, cleanup := MakeTestPluginDir(t) + pluginDir, cleanup := corehelpers.MakeTestPluginDir(t) t.Cleanup(func() { cleanup(t) }) // create an external plugin to shadow the builtin "pending-removal-test-plugin" @@ -363,7 +364,7 @@ func TestCore_Unseal_isMajorVersionFirstMount_PendingRemoval_Plugin(t *testing.T t.Fatal(err) } conf := &CoreConfig{ - BuiltinRegistry: NewMockBuiltinRegistry(), + BuiltinRegistry: corehelpers.NewMockBuiltinRegistry(), PluginDirectory: pluginDir, } c := TestCoreWithSealAndUI(t, conf) @@ -431,7 +432,7 @@ func TestCore_Unseal_isMajorVersionFirstMount_PendingRemoval_Plugin(t *testing.T } func TestCore_EnableExternalPlugin_PendingRemoval(t *testing.T) { - pluginDir, cleanup := MakeTestPluginDir(t) + pluginDir, cleanup := corehelpers.MakeTestPluginDir(t) t.Cleanup(func() { cleanup(t) }) // create an external plugin to shadow the builtin "pending-removal-test-plugin" @@ -442,7 +443,7 @@ func TestCore_EnableExternalPlugin_PendingRemoval(t *testing.T) { t.Fatal(err) } conf := &CoreConfig{ - BuiltinRegistry: NewMockBuiltinRegistry(), + BuiltinRegistry: corehelpers.NewMockBuiltinRegistry(), PluginDirectory: pluginDir, } @@ -466,7 +467,7 @@ func TestCore_EnableExternalPlugin_PendingRemoval(t *testing.T) { } func TestCore_EnableExternalPlugin_ShadowBuiltin(t *testing.T) { - pluginDir, cleanup := MakeTestPluginDir(t) + pluginDir, cleanup := corehelpers.MakeTestPluginDir(t) t.Cleanup(func() { cleanup(t) }) // create an external plugin to shadow the builtin "approle" @@ -477,7 +478,7 @@ func TestCore_EnableExternalPlugin_ShadowBuiltin(t *testing.T) { } pluginName := "approle" conf := &CoreConfig{ - BuiltinRegistry: NewMockBuiltinRegistry(), + BuiltinRegistry: corehelpers.NewMockBuiltinRegistry(), PluginDirectory: pluginDir, } c := TestCoreWithSealAndUI(t, conf) @@ -545,7 +546,7 @@ func TestCore_EnableExternalPlugin_ShadowBuiltin(t *testing.T) { } func TestCore_EnableExternalKv_MultipleVersions(t *testing.T) { - pluginDir, cleanup := MakeTestPluginDir(t) + pluginDir, cleanup := corehelpers.MakeTestPluginDir(t) t.Cleanup(func() { cleanup(t) }) // new kv plugin can be registered but not mounted @@ -556,7 +557,7 @@ func TestCore_EnableExternalKv_MultipleVersions(t *testing.T) { } pluginName := "kv" conf := &CoreConfig{ - BuiltinRegistry: NewMockBuiltinRegistry(), + BuiltinRegistry: corehelpers.NewMockBuiltinRegistry(), PluginDirectory: pluginDir, } c := TestCoreWithSealAndUI(t, conf) @@ -598,7 +599,7 @@ func TestCore_EnableExternalKv_MultipleVersions(t *testing.T) { } func TestCore_EnableExternalNoop_MultipleVersions(t *testing.T) { - pluginDir, cleanup := MakeTestPluginDir(t) + pluginDir, cleanup := corehelpers.MakeTestPluginDir(t) t.Cleanup(func() { cleanup(t) }) // new noop plugin can be registered but not mounted @@ -609,7 +610,7 @@ func TestCore_EnableExternalNoop_MultipleVersions(t *testing.T) { } pluginName := "noop" conf := &CoreConfig{ - BuiltinRegistry: NewMockBuiltinRegistry(), + BuiltinRegistry: corehelpers.NewMockBuiltinRegistry(), PluginDirectory: pluginDir, } c := TestCoreWithSealAndUI(t, conf) diff --git a/vault/external_tests/identity/login_mfa_totp_test.go b/vault/external_tests/identity/login_mfa_totp_test.go index bab6800743..9c2300589a 100644 --- a/vault/external_tests/identity/login_mfa_totp_test.go +++ b/vault/external_tests/identity/login_mfa_totp_test.go @@ -8,13 +8,13 @@ import ( "testing" "time" - upAuth "github.com/hashicorp/vault/api/auth/userpass" - "github.com/hashicorp/vault/helper/testhelpers" - "github.com/hashicorp/vault/api" + upAuth "github.com/hashicorp/vault/api/auth/userpass" "github.com/hashicorp/vault/audit" "github.com/hashicorp/vault/builtin/credential/userpass" "github.com/hashicorp/vault/builtin/logical/totp" + "github.com/hashicorp/vault/helper/testhelpers" + "github.com/hashicorp/vault/helper/testhelpers/corehelpers" vaulthttp "github.com/hashicorp/vault/http" "github.com/hashicorp/vault/sdk/logical" "github.com/hashicorp/vault/vault" @@ -48,7 +48,7 @@ func doTwoPhaseLogin(t *testing.T, client *api.Client, totpCodePath, methodID, u } func TestLoginMfaGenerateTOTPTestAuditIncluded(t *testing.T) { - var noop *vault.NoopAudit + noop := corehelpers.TestNoopAudit(t, nil) cluster := vault.NewTestCluster(t, &vault.CoreConfig{ CredentialBackends: map[string]logical.Factory{ @@ -59,9 +59,6 @@ func TestLoginMfaGenerateTOTPTestAuditIncluded(t *testing.T) { }, AuditBackends: map[string]audit.Factory{ "noop": func(ctx context.Context, config *audit.BackendConfig) (audit.Backend, error) { - noop = &vault.NoopAudit{ - Config: config, - } return noop, nil }, }, diff --git a/vault/external_tests/metrics/core_metrics_int_test.go b/vault/external_tests/metrics/core_metrics_int_test.go index cc19ae0a7b..ff0fd87c68 100644 --- a/vault/external_tests/metrics/core_metrics_int_test.go +++ b/vault/external_tests/metrics/core_metrics_int_test.go @@ -8,6 +8,8 @@ import ( "testing" "time" + "github.com/hashicorp/vault/helper/testhelpers/corehelpers" + "github.com/hashicorp/vault/api" "github.com/hashicorp/vault/helper/testhelpers" vaulthttp "github.com/hashicorp/vault/http" @@ -17,7 +19,7 @@ import ( func TestMountTableMetrics(t *testing.T) { clusterName := "mycluster" conf := &vault.CoreConfig{ - BuiltinRegistry: vault.NewMockBuiltinRegistry(), + BuiltinRegistry: corehelpers.NewMockBuiltinRegistry(), ClusterName: clusterName, } cluster := vault.NewTestCluster(t, conf, &vault.TestClusterOptions{ @@ -107,7 +109,7 @@ func gaugeConditionCheck(comparator string, compareVal int, compareToVal int) er func TestLeaderReElectionMetrics(t *testing.T) { clusterName := "mycluster" conf := &vault.CoreConfig{ - BuiltinRegistry: vault.NewMockBuiltinRegistry(), + BuiltinRegistry: corehelpers.NewMockBuiltinRegistry(), ClusterName: clusterName, } cluster := vault.NewTestCluster(t, conf, &vault.TestClusterOptions{ diff --git a/vault/external_tests/raft/raft_test.go b/vault/external_tests/raft/raft_test.go index 8b4e40e19f..f14604ee10 100644 --- a/vault/external_tests/raft/raft_test.go +++ b/vault/external_tests/raft/raft_test.go @@ -23,6 +23,7 @@ import ( "github.com/hashicorp/vault/helper/constants" "github.com/hashicorp/vault/helper/namespace" "github.com/hashicorp/vault/helper/testhelpers" + "github.com/hashicorp/vault/helper/testhelpers/corehelpers" "github.com/hashicorp/vault/helper/testhelpers/teststorage" vaulthttp "github.com/hashicorp/vault/http" "github.com/hashicorp/vault/internalshared/configutil" @@ -236,7 +237,7 @@ func TestRaft_Retry_Join(t *testing.T) { } // Handle potential racy behavior with unseals. Retry the unseal until it succeeds. - vault.RetryUntil(t, 10*time.Second, func() error { + corehelpers.RetryUntil(t, 10*time.Second, func() error { return cluster.AttemptUnsealCore(core) }) }(t, clusterCore) @@ -248,7 +249,7 @@ func TestRaft_Retry_Join(t *testing.T) { vault.TestWaitActive(t, leaderCore.Core) - vault.RetryUntil(t, 10*time.Second, func() error { + corehelpers.RetryUntil(t, 10*time.Second, func() error { return testhelpers.VerifyRaftPeers(t, cluster.Cores[0].Client, map[string]bool{ "core-0": true, "core-1": true, diff --git a/vault/logical_system_integ_test.go b/vault/logical_system_integ_test.go index db35987783..3287fdaf04 100644 --- a/vault/logical_system_integ_test.go +++ b/vault/logical_system_integ_test.go @@ -8,6 +8,7 @@ import ( "github.com/go-test/deep" "github.com/hashicorp/go-hclog" "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/helper/testhelpers/corehelpers" vaulthttp "github.com/hashicorp/vault/http" "github.com/hashicorp/vault/sdk/helper/logging" "github.com/hashicorp/vault/sdk/physical" @@ -169,7 +170,7 @@ func TestSystemBackend_HAStatus(t *testing.T) { cluster.Start() defer cluster.Cleanup() - vault.RetryUntil(t, 15*time.Second, func() error { + corehelpers.RetryUntil(t, 15*time.Second, func() error { // Use standby deliberately to make sure it forwards client := cluster.Cores[1].Client resp, err := client.Sys().HAStatus() diff --git a/vault/logical_system_test.go b/vault/logical_system_test.go index 2a0e3cf4fb..033beefdaf 100644 --- a/vault/logical_system_test.go +++ b/vault/logical_system_test.go @@ -2,7 +2,6 @@ package vault import ( "context" - "crypto/sha256" "encoding/base64" "encoding/hex" "fmt" @@ -19,20 +18,19 @@ import ( "github.com/go-test/deep" "github.com/hashicorp/go-hclog" semver "github.com/hashicorp/go-version" - "github.com/hashicorp/vault/audit" credUserpass "github.com/hashicorp/vault/builtin/credential/userpass" "github.com/hashicorp/vault/helper/builtinplugins" "github.com/hashicorp/vault/helper/experiments" "github.com/hashicorp/vault/helper/identity" "github.com/hashicorp/vault/helper/namespace" "github.com/hashicorp/vault/helper/random" + "github.com/hashicorp/vault/helper/testhelpers/corehelpers" "github.com/hashicorp/vault/helper/versions" "github.com/hashicorp/vault/sdk/framework" "github.com/hashicorp/vault/sdk/helper/compressutil" "github.com/hashicorp/vault/sdk/helper/consts" "github.com/hashicorp/vault/sdk/helper/jsonutil" "github.com/hashicorp/vault/sdk/helper/pluginutil" - "github.com/hashicorp/vault/sdk/helper/salt" "github.com/hashicorp/vault/sdk/helper/testhelpers/schema" "github.com/hashicorp/vault/sdk/logical" "github.com/hashicorp/vault/version" @@ -742,7 +740,7 @@ func TestSystemBackend_remount_auth(t *testing.T) { req.Data["config"] = structs.Map(MountConfig{}) resp, err := b.HandleRequest(namespace.RootContext(nil), req) - RetryUntil(t, 5*time.Second, func() error { + corehelpers.RetryUntil(t, 5*time.Second, func() error { req = logical.TestRequest(t, logical.ReadOperation, fmt.Sprintf("remount/status/%s", resp.Data["migration_id"])) resp, err = b.HandleRequest(namespace.RootContext(nil), req) if err != nil { @@ -894,7 +892,7 @@ func TestSystemBackend_remount(t *testing.T) { req.Data["to"] = "foo" req.Data["config"] = structs.Map(MountConfig{}) resp, err := b.HandleRequest(namespace.RootContext(nil), req) - RetryUntil(t, 5*time.Second, func() error { + corehelpers.RetryUntil(t, 5*time.Second, func() error { req = logical.TestRequest(t, logical.ReadOperation, fmt.Sprintf("remount/status/%s", resp.Data["migration_id"])) resp, err = b.HandleRequest(namespace.RootContext(nil), req) if err != nil { @@ -2175,11 +2173,7 @@ func TestSystemBackend_policyCRUD(t *testing.T) { func TestSystemBackend_enableAudit(t *testing.T) { c, b, _ := testCoreSystemBackend(t) - c.auditBackends["noop"] = func(ctx context.Context, config *audit.BackendConfig) (audit.Backend, error) { - return &NoopAudit{ - Config: config, - }, nil - } + c.auditBackends["noop"] = corehelpers.NoopAuditFactory(nil) req := logical.TestRequest(t, logical.UpdateOperation, "audit/foo") req.Data["type"] = "noop" @@ -2196,22 +2190,7 @@ func TestSystemBackend_enableAudit(t *testing.T) { func TestSystemBackend_auditHash(t *testing.T) { c, b, _ := testCoreSystemBackend(t) paths := b.(*SystemBackend).auditPaths() - c.auditBackends["noop"] = func(ctx context.Context, config *audit.BackendConfig) (audit.Backend, error) { - view := &logical.InmemStorage{} - view.Put(namespace.RootContext(nil), &logical.StorageEntry{ - Key: "salt", - Value: []byte("foo"), - }) - config.SaltView = view - config.SaltConfig = &salt.Config{ - HMAC: sha256.New, - HMACType: "hmac-sha256", - Location: salt.DefaultLocation, - } - return &NoopAudit{ - Config: config, - }, nil - } + c.auditBackends["noop"] = corehelpers.NoopAuditFactory(nil) req := logical.TestRequest(t, logical.UpdateOperation, "audit/foo") req.Data["type"] = "noop" @@ -2271,11 +2250,7 @@ func TestSystemBackend_enableAudit_invalid(t *testing.T) { func TestSystemBackend_auditTable(t *testing.T) { c, b, _ := testCoreSystemBackend(t) - c.auditBackends["noop"] = func(ctx context.Context, config *audit.BackendConfig) (audit.Backend, error) { - return &NoopAudit{ - Config: config, - }, nil - } + c.auditBackends["noop"] = corehelpers.NoopAuditFactory(nil) req := logical.TestRequest(t, logical.UpdateOperation, "audit/foo") req.Data["type"] = "noop" @@ -2310,11 +2285,7 @@ func TestSystemBackend_auditTable(t *testing.T) { func TestSystemBackend_disableAudit(t *testing.T) { c, b, _ := testCoreSystemBackend(t) - c.auditBackends["noop"] = func(ctx context.Context, config *audit.BackendConfig) (audit.Backend, error) { - return &NoopAudit{ - Config: config, - }, nil - } + c.auditBackends["noop"] = corehelpers.NoopAuditFactory(nil) req := logical.TestRequest(t, logical.UpdateOperation, "audit/foo") req.Data["type"] = "noop" diff --git a/vault/mount_test.go b/vault/mount_test.go index e217879cfe..7b45e788ed 100644 --- a/vault/mount_test.go +++ b/vault/mount_test.go @@ -8,6 +8,8 @@ import ( "testing" "time" + "github.com/hashicorp/vault/helper/testhelpers/corehelpers" + "github.com/armon/go-metrics" "github.com/go-test/deep" "github.com/hashicorp/vault/audit" @@ -118,7 +120,7 @@ func TestCore_DefaultMountTable(t *testing.T) { conf := &CoreConfig{ Physical: c.physical, DisableMlock: true, - BuiltinRegistry: NewMockBuiltinRegistry(), + BuiltinRegistry: corehelpers.NewMockBuiltinRegistry(), MetricSink: metricsutil.NewClusterMetricSink("test-cluster", inmemSink), MetricsHelper: metricsutil.NewMetricsHelper(inmemSink, false), } @@ -163,7 +165,7 @@ func TestCore_Mount(t *testing.T) { conf := &CoreConfig{ Physical: c.physical, DisableMlock: true, - BuiltinRegistry: NewMockBuiltinRegistry(), + BuiltinRegistry: corehelpers.NewMockBuiltinRegistry(), MetricSink: metricsutil.NewClusterMetricSink("test-cluster", inmemSink), MetricsHelper: metricsutil.NewMetricsHelper(inmemSink, false), } @@ -235,7 +237,7 @@ func TestCore_Mount_kv_generic(t *testing.T) { conf := &CoreConfig{ Physical: c.physical, DisableMlock: true, - BuiltinRegistry: NewMockBuiltinRegistry(), + BuiltinRegistry: corehelpers.NewMockBuiltinRegistry(), MetricSink: metricsutil.NewClusterMetricSink("test-cluster", inmemSink), MetricsHelper: metricsutil.NewMetricsHelper(inmemSink, false), } @@ -449,7 +451,7 @@ func TestCore_Unmount(t *testing.T) { conf := &CoreConfig{ Physical: c.physical, DisableMlock: true, - BuiltinRegistry: NewMockBuiltinRegistry(), + BuiltinRegistry: corehelpers.NewMockBuiltinRegistry(), MetricSink: metricsutil.NewClusterMetricSink("test-cluster", inmemSink), MetricsHelper: metricsutil.NewMetricsHelper(inmemSink, false), } @@ -720,7 +722,7 @@ func TestCore_MountTable_UpgradeToTyped(t *testing.T) { c, _, _ := TestCoreUnsealed(t) c.auditBackends["noop"] = func(ctx context.Context, config *audit.BackendConfig) (audit.Backend, error) { - return &NoopAudit{ + return &corehelpers.NoopAudit{ Config: config, }, nil } diff --git a/vault/testing.go b/vault/testing.go index 6f69598e47..4e2de9cfb8 100644 --- a/vault/testing.go +++ b/vault/testing.go @@ -35,19 +35,17 @@ import ( "github.com/hashicorp/vault/api" "github.com/hashicorp/vault/audit" auditFile "github.com/hashicorp/vault/builtin/audit/file" - "github.com/hashicorp/vault/builtin/credential/approle" "github.com/hashicorp/vault/command/server" "github.com/hashicorp/vault/helper/constants" "github.com/hashicorp/vault/helper/metricsutil" "github.com/hashicorp/vault/helper/namespace" + "github.com/hashicorp/vault/helper/testhelpers/corehelpers" "github.com/hashicorp/vault/internalshared/configutil" - dbMysql "github.com/hashicorp/vault/plugins/database/mysql" v5 "github.com/hashicorp/vault/sdk/database/dbplugin/v5" "github.com/hashicorp/vault/sdk/framework" "github.com/hashicorp/vault/sdk/helper/consts" "github.com/hashicorp/vault/sdk/helper/logging" "github.com/hashicorp/vault/sdk/helper/pluginutil" - "github.com/hashicorp/vault/sdk/helper/salt" "github.com/hashicorp/vault/sdk/logical" "github.com/hashicorp/vault/sdk/physical" physInmem "github.com/hashicorp/vault/sdk/physical/inmem" @@ -129,7 +127,7 @@ func TestCoreWithSeal(t testing.T, testSeal Seal, enableRaw bool) *Core { Seal: testSeal, EnableUI: false, EnableRaw: enableRaw, - BuiltinRegistry: NewMockBuiltinRegistry(), + BuiltinRegistry: corehelpers.NewMockBuiltinRegistry(), AuditBackends: map[string]audit.Factory{ "file": auditFile.Factory, }, @@ -154,7 +152,7 @@ func TestCoreWithCustomResponseHeaderAndUI(t testing.T, CustomResponseHeaders ma RawConfig: confRaw, EnableUI: enableUI, EnableRaw: true, - BuiltinRegistry: NewMockBuiltinRegistry(), + BuiltinRegistry: corehelpers.NewMockBuiltinRegistry(), } core := TestCoreWithSealAndUI(t, conf) return testCoreUnsealed(t, core) @@ -164,7 +162,7 @@ func TestCoreUI(t testing.T, enableUI bool) *Core { conf := &CoreConfig{ EnableUI: enableUI, EnableRaw: true, - BuiltinRegistry: NewMockBuiltinRegistry(), + BuiltinRegistry: corehelpers.NewMockBuiltinRegistry(), } return TestCoreWithSealAndUI(t, conf) } @@ -246,26 +244,7 @@ func TestCoreWithSealAndUINoCleanup(t testing.T, opts *CoreConfig) *Core { func testCoreConfig(t testing.T, physicalBackend physical.Backend, logger log.Logger) *CoreConfig { t.Helper() noopAudits := map[string]audit.Factory{ - "noop": func(_ context.Context, config *audit.BackendConfig) (audit.Backend, error) { - view := &logical.InmemStorage{} - view.Put(context.Background(), &logical.StorageEntry{ - Key: "salt", - Value: []byte("foo"), - }) - config.SaltConfig = &salt.Config{ - HMAC: sha256.New, - HMACType: "hmac-sha256", - } - config.SaltView = view - - n := &noopAudit{ - Config: config, - } - n.formatter.AuditFormatWriter = &audit.JSONFormatWriter{ - SaltFunc: n.Salt, - } - return n, nil - }, + "noop": corehelpers.NoopAuditFactory(nil), } noopBackends := make(map[string]logical.Factory) @@ -304,7 +283,7 @@ func testCoreConfig(t testing.T, physicalBackend physical.Backend, logger log.Lo CredentialBackends: credentialBackends, DisableMlock: true, Logger: logger, - BuiltinRegistry: NewMockBuiltinRegistry(), + BuiltinRegistry: corehelpers.NewMockBuiltinRegistry(), } return conf @@ -383,7 +362,7 @@ func SetupMetrics(conf *CoreConfig) *metrics.InmemSink { func TestCoreUnsealedWithMetrics(t testing.T) (*Core, [][]byte, string, *metrics.InmemSink) { t.Helper() conf := &CoreConfig{ - BuiltinRegistry: NewMockBuiltinRegistry(), + BuiltinRegistry: corehelpers.NewMockBuiltinRegistry(), } sink := SetupMetrics(conf) core, keys, root := testCoreUnsealed(t, TestCoreWithSealAndUI(t, conf)) @@ -668,112 +647,6 @@ func AddTestLogicalBackend(name string, factory logical.Factory) error { return nil } -type noopAudit struct { - Config *audit.BackendConfig - salt *salt.Salt - saltMutex sync.RWMutex - formatter audit.AuditFormatter - records [][]byte - l sync.RWMutex -} - -func (n *noopAudit) GetHash(ctx context.Context, data string) (string, error) { - salt, err := n.Salt(ctx) - if err != nil { - return "", err - } - return salt.GetIdentifiedHMAC(data), nil -} - -func (n *noopAudit) LogRequest(ctx context.Context, in *logical.LogInput) error { - n.l.Lock() - defer n.l.Unlock() - var w bytes.Buffer - err := n.formatter.FormatRequest(ctx, &w, audit.FormatterConfig{}, in) - if err != nil { - return err - } - n.records = append(n.records, w.Bytes()) - return nil -} - -func (n *noopAudit) LogResponse(ctx context.Context, in *logical.LogInput) error { - n.l.Lock() - defer n.l.Unlock() - var w bytes.Buffer - err := n.formatter.FormatResponse(ctx, &w, audit.FormatterConfig{}, in) - if err != nil { - return err - } - n.records = append(n.records, w.Bytes()) - return nil -} - -func (n *noopAudit) LogTestMessage(ctx context.Context, in *logical.LogInput, config map[string]string) error { - n.l.Lock() - defer n.l.Unlock() - var w bytes.Buffer - tempFormatter := audit.NewTemporaryFormatter(config["format"], config["prefix"]) - err := tempFormatter.FormatResponse(ctx, &w, audit.FormatterConfig{}, in) - if err != nil { - return err - } - n.records = append(n.records, w.Bytes()) - return nil -} - -func (n *noopAudit) Reload(_ context.Context) error { - return nil -} - -func (n *noopAudit) Invalidate(_ context.Context) { - n.saltMutex.Lock() - defer n.saltMutex.Unlock() - n.salt = nil -} - -func (n *noopAudit) Salt(ctx context.Context) (*salt.Salt, error) { - n.saltMutex.RLock() - if n.salt != nil { - defer n.saltMutex.RUnlock() - return n.salt, nil - } - n.saltMutex.RUnlock() - n.saltMutex.Lock() - defer n.saltMutex.Unlock() - if n.salt != nil { - return n.salt, nil - } - salt, err := salt.NewSalt(ctx, n.Config.SaltView, n.Config.SaltConfig) - if err != nil { - return nil, err - } - n.salt = salt - return salt, nil -} - -func AddNoopAudit(conf *CoreConfig, records **[][]byte) { - conf.AuditBackends = map[string]audit.Factory{ - "noop": func(_ context.Context, config *audit.BackendConfig) (audit.Backend, error) { - view := &logical.InmemStorage{} - view.Put(context.Background(), &logical.StorageEntry{ - Key: "salt", - Value: []byte("foo"), - }) - n := &noopAudit{ - Config: config, - } - n.formatter.AuditFormatWriter = &audit.JSONFormatWriter{ - SaltFunc: n.Salt, - } - if records != nil { - *records = &n.records - } - return n, nil - }, - } -} - type rawHTTP struct{} func (n *rawHTTP) HandleRequest(ctx context.Context, req *logical.Request) (*logical.Response, error) { @@ -1135,7 +1008,7 @@ func (c *TestClusterCore) TLSConfig() *tls.Config { func (c *TestCluster) Cleanup() { c.Logger.Info("cleaning up vault cluster") - if tl, ok := c.Logger.(*TestLogger); ok { + if tl, ok := c.Logger.(*corehelpers.TestLogger); ok { tl.StopLogging() } @@ -1319,58 +1192,6 @@ type certInfo struct { keyPEM []byte } -type TestLogger struct { - log.Logger - Path string - File *os.File - sink log.SinkAdapter -} - -func NewTestLogger(t testing.T) *TestLogger { - var logFile *os.File - var logPath string - output := os.Stderr - - logDir := os.Getenv("VAULT_TEST_LOG_DIR") - if logDir != "" { - logPath = filepath.Join(logDir, t.Name()+".log") - // t.Name may include slashes. - dir, _ := filepath.Split(logPath) - err := os.MkdirAll(dir, 0o755) - if err != nil { - t.Fatal(err) - } - logFile, err = os.Create(logPath) - if err != nil { - t.Fatal(err) - } - output = logFile - } - - // We send nothing on the regular logger, that way we can later deregister - // the sink to stop logging during cluster cleanup. - logger := log.NewInterceptLogger(&log.LoggerOptions{ - Output: ioutil.Discard, - IndependentLevels: true, - }) - sink := log.NewSinkAdapter(&log.LoggerOptions{ - Output: output, - Level: log.Trace, - IndependentLevels: true, - }) - logger.RegisterSink(sink) - return &TestLogger{ - Path: logPath, - File: logFile, - Logger: logger, - sink: sink, - } -} - -func (tl *TestLogger) StopLogging() { - tl.Logger.(log.InterceptLogger).DeregisterSink(tl.sink) -} - // NewTestCluster creates a new test cluster based on the provided core config // and test cluster options. // @@ -1420,7 +1241,7 @@ func NewTestCluster(t testing.T, base *CoreConfig, opts *TestClusterOptions) *Te case opts != nil && opts.Logger != nil: testCluster.Logger = opts.Logger default: - testCluster.Logger = NewTestLogger(t) + testCluster.Logger = corehelpers.NewTestLogger(t) } if opts != nil && opts.TempDir != "" { @@ -1649,7 +1470,7 @@ func NewTestCluster(t testing.T, base *CoreConfig, opts *TestClusterOptions) *Te DisableMlock: true, EnableUI: true, EnableRaw: true, - BuiltinRegistry: NewMockBuiltinRegistry(), + BuiltinRegistry: corehelpers.NewMockBuiltinRegistry(), } if base != nil { @@ -1755,7 +1576,7 @@ func NewTestCluster(t testing.T, base *CoreConfig, opts *TestClusterOptions) *Te addAuditBackend := len(coreConfig.AuditBackends) == 0 if addAuditBackend { - AddNoopAudit(coreConfig, nil) + coreConfig.AuditBackends["noop"] = corehelpers.NoopAuditFactory(nil) } if coreConfig.Physical == nil && (opts == nil || opts.PhysicalFactory == nil) { @@ -1868,7 +1689,7 @@ func NewTestCluster(t testing.T, base *CoreConfig, opts *TestClusterOptions) *Te for _, c := range testCluster.cleanupFuncs { c() } - if l, ok := testCluster.Logger.(*TestLogger); ok { + if l, ok := testCluster.Logger.(*corehelpers.TestLogger); ok { if t.Failed() { _ = l.File.Close() } else { @@ -2320,264 +2141,3 @@ func (testCluster *TestCluster) getAPIClient( } return apiClient } - -func toFunc(f logical.Factory) func() (interface{}, error) { - return func() (interface{}, error) { - return f, nil - } -} - -func NewMockBuiltinRegistry() *mockBuiltinRegistry { - return &mockBuiltinRegistry{ - forTesting: map[string]mockBackend{ - "mysql-database-plugin": {PluginType: consts.PluginTypeDatabase}, - "postgresql-database-plugin": {PluginType: consts.PluginTypeDatabase}, - "approle": {PluginType: consts.PluginTypeCredential}, - "pending-removal-test-plugin": { - PluginType: consts.PluginTypeCredential, - DeprecationStatus: consts.PendingRemoval, - }, - "aws": {PluginType: consts.PluginTypeCredential}, - "consul": {PluginType: consts.PluginTypeSecrets}, - }, - } -} - -type mockBackend struct { - consts.PluginType - consts.DeprecationStatus -} - -type mockBuiltinRegistry struct { - forTesting map[string]mockBackend -} - -func (m *mockBuiltinRegistry) Get(name string, pluginType consts.PluginType) (func() (interface{}, error), bool) { - testBackend, ok := m.forTesting[name] - if !ok { - return nil, false - } - testPluginType := testBackend.PluginType - if pluginType != testPluginType { - return nil, false - } - - switch name { - case "approle", "pending-removal-test-plugin": - return toFunc(approle.Factory), true - case "aws": - return toFunc(func(ctx context.Context, config *logical.BackendConfig) (logical.Backend, error) { - b := new(framework.Backend) - b.Setup(ctx, config) - b.BackendType = logical.TypeCredential - return b, nil - }), true - case "postgresql-database-plugin": - return toFunc(func(ctx context.Context, config *logical.BackendConfig) (logical.Backend, error) { - b := new(framework.Backend) - b.Setup(ctx, config) - b.BackendType = logical.TypeLogical - return b, nil - }), true - case "mysql-database-plugin": - return dbMysql.New(dbMysql.DefaultUserNameTemplate), true - case "consul": - return toFunc(func(ctx context.Context, config *logical.BackendConfig) (logical.Backend, error) { - b := new(framework.Backend) - b.Setup(ctx, config) - b.BackendType = logical.TypeLogical - return b, nil - }), true - default: - return nil, false - } -} - -// Keys only supports getting a realistic list of the keys for database plugins, -// and approle -func (m *mockBuiltinRegistry) Keys(pluginType consts.PluginType) []string { - switch pluginType { - case consts.PluginTypeDatabase: - // This is a hard-coded reproduction of the db plugin keys in - // helper/builtinplugins/registry.go. The registry isn't directly used - // because it causes import cycles. - return []string{ - "mysql-database-plugin", - "mysql-aurora-database-plugin", - "mysql-rds-database-plugin", - "mysql-legacy-database-plugin", - - "cassandra-database-plugin", - "couchbase-database-plugin", - "elasticsearch-database-plugin", - "hana-database-plugin", - "influxdb-database-plugin", - "mongodb-database-plugin", - "mongodbatlas-database-plugin", - "mssql-database-plugin", - "postgresql-database-plugin", - "redis-elasticache-database-plugin", - "redshift-database-plugin", - "redis-database-plugin", - "snowflake-database-plugin", - } - case consts.PluginTypeCredential: - return []string{ - "pending-removal-test-plugin", - "approle", - } - } - return []string{} -} - -func (m *mockBuiltinRegistry) Contains(name string, pluginType consts.PluginType) bool { - for _, key := range m.Keys(pluginType) { - if key == name { - return true - } - } - return false -} - -func (m *mockBuiltinRegistry) DeprecationStatus(name string, pluginType consts.PluginType) (consts.DeprecationStatus, bool) { - if m.Contains(name, pluginType) { - return m.forTesting[name].DeprecationStatus, true - } - - return consts.Unknown, false -} - -type NoopAudit struct { - Config *audit.BackendConfig - ReqErr error - ReqAuth []*logical.Auth - Req []*logical.Request - ReqHeaders []map[string][]string - ReqNonHMACKeys []string - ReqErrs []error - - RespErr error - RespAuth []*logical.Auth - RespReq []*logical.Request - Resp []*logical.Response - RespNonHMACKeys []string - RespReqNonHMACKeys []string - RespErrs []error - - salt *salt.Salt - saltMutex sync.RWMutex -} - -func (n *NoopAudit) LogRequest(ctx context.Context, in *logical.LogInput) error { - n.ReqAuth = append(n.ReqAuth, in.Auth) - n.Req = append(n.Req, in.Request) - n.ReqHeaders = append(n.ReqHeaders, in.Request.Headers) - n.ReqNonHMACKeys = in.NonHMACReqDataKeys - n.ReqErrs = append(n.ReqErrs, in.OuterErr) - return n.ReqErr -} - -func (n *NoopAudit) LogResponse(ctx context.Context, in *logical.LogInput) error { - n.RespAuth = append(n.RespAuth, in.Auth) - n.RespReq = append(n.RespReq, in.Request) - n.Resp = append(n.Resp, in.Response) - n.RespErrs = append(n.RespErrs, in.OuterErr) - - if in.Response != nil { - n.RespNonHMACKeys = in.NonHMACRespDataKeys - n.RespReqNonHMACKeys = in.NonHMACReqDataKeys - } - - return n.RespErr -} - -func (n *NoopAudit) LogTestMessage(ctx context.Context, in *logical.LogInput, options map[string]string) error { - return nil -} - -func (n *NoopAudit) Salt(ctx context.Context) (*salt.Salt, error) { - n.saltMutex.RLock() - if n.salt != nil { - defer n.saltMutex.RUnlock() - return n.salt, nil - } - n.saltMutex.RUnlock() - n.saltMutex.Lock() - defer n.saltMutex.Unlock() - if n.salt != nil { - return n.salt, nil - } - salt, err := salt.NewSalt(ctx, n.Config.SaltView, n.Config.SaltConfig) - if err != nil { - return nil, err - } - n.salt = salt - return salt, nil -} - -func (n *NoopAudit) GetHash(ctx context.Context, data string) (string, error) { - salt, err := n.Salt(ctx) - if err != nil { - return "", err - } - return salt.GetIdentifiedHMAC(data), nil -} - -func (n *NoopAudit) Reload(ctx context.Context) error { - return nil -} - -func (n *NoopAudit) Invalidate(ctx context.Context) { - n.saltMutex.Lock() - defer n.saltMutex.Unlock() - n.salt = nil -} - -// RetryUntil runs f until it returns a nil result or the timeout is reached. -// If a nil result hasn't been obtained by timeout, calls t.Fatal. -func RetryUntil(t testing.T, timeout time.Duration, f func() error) { - t.Helper() - deadline := time.Now().Add(timeout) - var err error - for time.Now().Before(deadline) { - if err = f(); err == nil { - return - } - time.Sleep(100 * time.Millisecond) - } - t.Fatalf("did not complete before deadline, err: %v", err) -} - -// MakeTestPluginDir creates a temporary directory suitable for holding plugins. -// This helper also resolves symlinks to make tests happy on OS X. -func MakeTestPluginDir(t testing.T) (string, func(t testing.T)) { - if t != nil { - t.Helper() - } - - dir, err := os.MkdirTemp("", "") - if err != nil { - if t == nil { - panic(err) - } - t.Fatal(err) - } - - // OSX tempdir are /var, but actually symlinked to /private/var - dir, err = filepath.EvalSymlinks(dir) - if err != nil { - if t == nil { - panic(err) - } - t.Fatal(err) - } - - return dir, func(t testing.T) { - if err := os.RemoveAll(dir); err != nil { - if t == nil { - panic(err) - } - t.Fatal(err) - } - } -}