mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-11-04 04:28:08 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			533 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			533 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright (c) HashiCorp, Inc.
 | 
						|
// SPDX-License-Identifier: MPL-2.0
 | 
						|
 | 
						|
package database
 | 
						|
 | 
						|
// This file contains all "large"/expensive tests. These are running requests against a running backend
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"fmt"
 | 
						|
	"os"
 | 
						|
	"regexp"
 | 
						|
	"strings"
 | 
						|
	"testing"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"github.com/hashicorp/vault/api"
 | 
						|
	"github.com/hashicorp/vault/sdk/helper/consts"
 | 
						|
	"github.com/hashicorp/vault/sdk/helper/pluginutil"
 | 
						|
	"github.com/hashicorp/vault/sdk/logical"
 | 
						|
	"github.com/hashicorp/vault/vault"
 | 
						|
)
 | 
						|
 | 
						|
func TestPlugin_lifecycle(t *testing.T) {
 | 
						|
	cluster, sys := getCluster(t)
 | 
						|
	defer cluster.Cleanup()
 | 
						|
 | 
						|
	vault.TestAddTestPlugin(t, cluster.Cores[0].Core, "mock-v4-database-plugin", consts.PluginTypeDatabase, "", "TestBackend_PluginMain_MockV4", []string{}, "")
 | 
						|
	vault.TestAddTestPlugin(t, cluster.Cores[0].Core, "mock-v5-database-plugin", consts.PluginTypeDatabase, "", "TestBackend_PluginMain_MockV5", []string{}, "")
 | 
						|
	vault.TestAddTestPlugin(t, cluster.Cores[0].Core, "mock-v6-database-plugin-muxed", consts.PluginTypeDatabase, "", "TestBackend_PluginMain_MockV6Multiplexed", []string{}, "")
 | 
						|
 | 
						|
	config := logical.TestBackendConfig()
 | 
						|
	config.StorageView = &logical.InmemStorage{}
 | 
						|
	config.System = sys
 | 
						|
	lb, err := Factory(context.Background(), config)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatal(err)
 | 
						|
	}
 | 
						|
	b, ok := lb.(*databaseBackend)
 | 
						|
	if !ok {
 | 
						|
		t.Fatal("could not convert to database backend")
 | 
						|
	}
 | 
						|
	defer b.Cleanup(context.Background())
 | 
						|
 | 
						|
	type testCase struct {
 | 
						|
		dbName                string
 | 
						|
		dbType                string
 | 
						|
		configData            map[string]interface{}
 | 
						|
		assertDynamicUsername stringAssertion
 | 
						|
		assertDynamicPassword stringAssertion
 | 
						|
	}
 | 
						|
 | 
						|
	tests := map[string]testCase{
 | 
						|
		"v4": {
 | 
						|
			dbName: "mockv4",
 | 
						|
			dbType: "mock-v4-database-plugin",
 | 
						|
			configData: map[string]interface{}{
 | 
						|
				"name":              "mockv4",
 | 
						|
				"plugin_name":       "mock-v4-database-plugin",
 | 
						|
				"connection_url":    "sample_connection_url",
 | 
						|
				"verify_connection": true,
 | 
						|
				"allowed_roles":     []string{"*"},
 | 
						|
				"username":          "mockv4-user",
 | 
						|
				"password":          "mysecurepassword",
 | 
						|
			},
 | 
						|
			assertDynamicUsername: assertStringPrefix("mockv4_user_"),
 | 
						|
			assertDynamicPassword: assertStringPrefix("mockv4_"),
 | 
						|
		},
 | 
						|
		"v5": {
 | 
						|
			dbName: "mockv5",
 | 
						|
			dbType: "mock-v5-database-plugin",
 | 
						|
			configData: map[string]interface{}{
 | 
						|
				"connection_url":    "sample_connection_url",
 | 
						|
				"plugin_name":       "mock-v5-database-plugin",
 | 
						|
				"verify_connection": true,
 | 
						|
				"allowed_roles":     []string{"*"},
 | 
						|
				"name":              "mockv5",
 | 
						|
				"username":          "mockv5-user",
 | 
						|
				"password":          "mysecurepassword",
 | 
						|
			},
 | 
						|
			assertDynamicUsername: assertStringPrefix("mockv5_user_"),
 | 
						|
			assertDynamicPassword: assertStringRegex("^[a-zA-Z0-9-]{20}"),
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for name, test := range tests {
 | 
						|
		t.Run(name, func(t *testing.T) {
 | 
						|
			var cleanupReqs []*logical.Request
 | 
						|
			defer func() {
 | 
						|
				// Do not defer cleanup directly so that we can populate the
 | 
						|
				// slice before the function gets executed.
 | 
						|
				cleanup(t, b, cleanupReqs)
 | 
						|
			}()
 | 
						|
 | 
						|
			// /////////////////////////////////////////////////////////////////
 | 
						|
			// Configure
 | 
						|
			req := &logical.Request{
 | 
						|
				Operation: logical.CreateOperation,
 | 
						|
				Path:      fmt.Sprintf("config/%s", test.dbName),
 | 
						|
				Storage:   config.StorageView,
 | 
						|
				Data:      test.configData,
 | 
						|
			}
 | 
						|
			ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
 | 
						|
			defer cancel()
 | 
						|
 | 
						|
			resp, err := b.HandleRequest(ctx, req)
 | 
						|
			assertErrIsNil(t, err)
 | 
						|
			assertRespHasNoErr(t, resp)
 | 
						|
			assertNoRespData(t, resp)
 | 
						|
 | 
						|
			cleanupReqs = append(cleanupReqs, &logical.Request{
 | 
						|
				Operation: logical.DeleteOperation,
 | 
						|
				Path:      fmt.Sprintf("config/%s", test.dbName),
 | 
						|
				Storage:   config.StorageView,
 | 
						|
			})
 | 
						|
 | 
						|
			// /////////////////////////////////////////////////////////////////
 | 
						|
			// Rotate root credentials
 | 
						|
			req = &logical.Request{
 | 
						|
				Operation: logical.UpdateOperation,
 | 
						|
				Path:      fmt.Sprintf("rotate-root/%s", test.dbName),
 | 
						|
				Storage:   config.StorageView,
 | 
						|
			}
 | 
						|
			ctx, cancel = context.WithTimeout(context.Background(), 5*time.Second)
 | 
						|
			defer cancel()
 | 
						|
 | 
						|
			resp, err = b.HandleRequest(ctx, req)
 | 
						|
			assertErrIsNil(t, err)
 | 
						|
			assertRespHasNoErr(t, resp)
 | 
						|
			assertNoRespData(t, resp)
 | 
						|
 | 
						|
			// /////////////////////////////////////////////////////////////////
 | 
						|
			// Dynamic credentials
 | 
						|
 | 
						|
			// Create role
 | 
						|
			dynamicRoleName := "dynamic-role"
 | 
						|
			req = &logical.Request{
 | 
						|
				Operation: logical.UpdateOperation,
 | 
						|
				Path:      fmt.Sprintf("roles/%s", dynamicRoleName),
 | 
						|
				Storage:   config.StorageView,
 | 
						|
				Data: map[string]interface{}{
 | 
						|
					"db_name":     test.dbName,
 | 
						|
					"default_ttl": "5s",
 | 
						|
					"max_ttl":     "1m",
 | 
						|
				},
 | 
						|
			}
 | 
						|
			ctx, cancel = context.WithTimeout(context.Background(), 5*time.Second)
 | 
						|
			defer cancel()
 | 
						|
 | 
						|
			resp, err = b.HandleRequest(ctx, req)
 | 
						|
			assertErrIsNil(t, err)
 | 
						|
			assertRespHasNoErr(t, resp)
 | 
						|
			assertNoRespData(t, resp)
 | 
						|
 | 
						|
			cleanupReqs = append(cleanupReqs, &logical.Request{
 | 
						|
				Operation: logical.DeleteOperation,
 | 
						|
				Path:      fmt.Sprintf("roles/%s", dynamicRoleName),
 | 
						|
				Storage:   config.StorageView,
 | 
						|
			})
 | 
						|
 | 
						|
			// Generate credentials
 | 
						|
			req = &logical.Request{
 | 
						|
				Operation: logical.ReadOperation,
 | 
						|
				Path:      fmt.Sprintf("creds/%s", dynamicRoleName),
 | 
						|
				Storage:   config.StorageView,
 | 
						|
			}
 | 
						|
			ctx, cancel = context.WithTimeout(context.Background(), 5*time.Second)
 | 
						|
			defer cancel()
 | 
						|
 | 
						|
			resp, err = b.HandleRequest(ctx, req)
 | 
						|
			assertErrIsNil(t, err)
 | 
						|
			assertRespHasNoErr(t, resp)
 | 
						|
			assertRespHasData(t, resp)
 | 
						|
 | 
						|
			// TODO: Figure out how to make a call to the cluster that gives back a lease ID
 | 
						|
			// And also rotates the secret out after its TTL
 | 
						|
 | 
						|
			// /////////////////////////////////////////////////////////////////
 | 
						|
			// Static credentials
 | 
						|
 | 
						|
			// Create static role
 | 
						|
			staticRoleName := "static-role"
 | 
						|
			req = &logical.Request{
 | 
						|
				Operation: logical.CreateOperation,
 | 
						|
				Path:      fmt.Sprintf("static-roles/%s", staticRoleName),
 | 
						|
				Storage:   config.StorageView,
 | 
						|
				Data: map[string]interface{}{
 | 
						|
					"db_name":         test.dbName,
 | 
						|
					"username":        "static-username",
 | 
						|
					"rotation_period": "5",
 | 
						|
				},
 | 
						|
			}
 | 
						|
			ctx, cancel = context.WithTimeout(context.Background(), 5*time.Second)
 | 
						|
			defer cancel()
 | 
						|
 | 
						|
			resp, err = b.HandleRequest(ctx, req)
 | 
						|
			assertErrIsNil(t, err)
 | 
						|
			assertRespHasNoErr(t, resp)
 | 
						|
			assertNoRespData(t, resp)
 | 
						|
 | 
						|
			cleanupReqs = append(cleanupReqs, &logical.Request{
 | 
						|
				Operation: logical.DeleteOperation,
 | 
						|
				Path:      fmt.Sprintf("static-roles/%s", staticRoleName),
 | 
						|
				Storage:   config.StorageView,
 | 
						|
			})
 | 
						|
 | 
						|
			// Get credentials
 | 
						|
			req = &logical.Request{
 | 
						|
				Operation: logical.ReadOperation,
 | 
						|
				Path:      fmt.Sprintf("static-creds/%s", staticRoleName),
 | 
						|
				Storage:   config.StorageView,
 | 
						|
			}
 | 
						|
			ctx, cancel = context.WithTimeout(context.Background(), 5*time.Second)
 | 
						|
			defer cancel()
 | 
						|
 | 
						|
			resp, err = b.HandleRequest(ctx, req)
 | 
						|
			assertErrIsNil(t, err)
 | 
						|
			assertRespHasNoErr(t, resp)
 | 
						|
			assertRespHasData(t, resp)
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestPlugin_VersionSelection(t *testing.T) {
 | 
						|
	cluster, sys := getCluster(t)
 | 
						|
	defer cluster.Cleanup()
 | 
						|
 | 
						|
	for _, version := range []string{"v11.0.0", "v11.0.1-rc1", "v2.0.0"} {
 | 
						|
		vault.TestAddTestPlugin(t, cluster.Cores[0].Core, "mock-v5-database-plugin", consts.PluginTypeDatabase, version, "TestBackend_PluginMain_MockV5", []string{}, "")
 | 
						|
	}
 | 
						|
 | 
						|
	config := logical.TestBackendConfig()
 | 
						|
	config.StorageView = &logical.InmemStorage{}
 | 
						|
	config.System = sys
 | 
						|
	lb, err := Factory(context.Background(), config)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatal(err)
 | 
						|
	}
 | 
						|
	b, ok := lb.(*databaseBackend)
 | 
						|
	if !ok {
 | 
						|
		t.Fatal("could not convert to database backend")
 | 
						|
	}
 | 
						|
	defer b.Cleanup(context.Background())
 | 
						|
 | 
						|
	test := func(t *testing.T, selectVersion, expectedVersion string) func(t *testing.T) {
 | 
						|
		return func(t *testing.T) {
 | 
						|
			req := &logical.Request{
 | 
						|
				Operation: logical.CreateOperation,
 | 
						|
				Path:      "config/db",
 | 
						|
				Storage:   config.StorageView,
 | 
						|
				Data: map[string]interface{}{
 | 
						|
					"connection_url":    "sample_connection_url",
 | 
						|
					"plugin_name":       "mock-v5-database-plugin",
 | 
						|
					"plugin_version":    selectVersion,
 | 
						|
					"verify_connection": true,
 | 
						|
					"allowed_roles":     []string{"*"},
 | 
						|
					"name":              "mockv5",
 | 
						|
					"username":          "mockv5-user",
 | 
						|
					"password":          "mysecurepassword",
 | 
						|
				},
 | 
						|
			}
 | 
						|
			ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
 | 
						|
			defer cancel()
 | 
						|
 | 
						|
			resp, err := b.HandleRequest(ctx, req)
 | 
						|
			assertErrIsNil(t, err)
 | 
						|
			assertRespHasNoErr(t, resp)
 | 
						|
			assertNoRespData(t, resp)
 | 
						|
 | 
						|
			defer func() {
 | 
						|
				_, err := b.HandleRequest(context.Background(), &logical.Request{
 | 
						|
					Operation: logical.DeleteOperation,
 | 
						|
					Path:      "config/db",
 | 
						|
					Storage:   config.StorageView,
 | 
						|
				})
 | 
						|
				if err != nil {
 | 
						|
					t.Fatal(err)
 | 
						|
				}
 | 
						|
			}()
 | 
						|
 | 
						|
			req = &logical.Request{
 | 
						|
				Operation: logical.ReadOperation,
 | 
						|
				Path:      "config/db",
 | 
						|
				Storage:   config.StorageView,
 | 
						|
			}
 | 
						|
			ctx, cancel = context.WithTimeout(context.Background(), 5*time.Second)
 | 
						|
			defer cancel()
 | 
						|
 | 
						|
			resp, err = b.HandleRequest(ctx, req)
 | 
						|
			assertErrIsNil(t, err)
 | 
						|
			assertRespHasNoErr(t, resp)
 | 
						|
			if resp.Data["plugin_version"].(string) != expectedVersion {
 | 
						|
				t.Fatalf("Expected version %q but got %q", expectedVersion, resp.Data["plugin_version"].(string))
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	for name, tc := range map[string]struct {
 | 
						|
		selectVersion   string
 | 
						|
		expectedVersion string
 | 
						|
	}{
 | 
						|
		"no version specified, selects latest in the absence of unversioned plugins": {
 | 
						|
			selectVersion:   "",
 | 
						|
			expectedVersion: "v11.0.1-rc1",
 | 
						|
		},
 | 
						|
		"specific version selected": {
 | 
						|
			selectVersion:   "11.0.0",
 | 
						|
			expectedVersion: "v11.0.0",
 | 
						|
		},
 | 
						|
	} {
 | 
						|
		t.Run(name, test(t, tc.selectVersion, tc.expectedVersion))
 | 
						|
	}
 | 
						|
 | 
						|
	// Register a newer version of the plugin, and ensure that's the new default version selected.
 | 
						|
	vault.TestAddTestPlugin(t, cluster.Cores[0].Core, "mock-v5-database-plugin", consts.PluginTypeDatabase, "v11.0.1", "TestBackend_PluginMain_MockV5", []string{}, "")
 | 
						|
	t.Run("no version specified, new latest version selected", test(t, "", "v11.0.1"))
 | 
						|
 | 
						|
	// Register an unversioned plugin and ensure that is now selected when no version is specified.
 | 
						|
	vault.TestAddTestPlugin(t, cluster.Cores[0].Core, "mock-v5-database-plugin", consts.PluginTypeDatabase, "", "TestBackend_PluginMain_MockV5", []string{}, "")
 | 
						|
	for name, tc := range map[string]struct {
 | 
						|
		selectVersion   string
 | 
						|
		expectedVersion string
 | 
						|
	}{
 | 
						|
		"no version specified, selects unversioned": {
 | 
						|
			selectVersion:   "",
 | 
						|
			expectedVersion: "",
 | 
						|
		},
 | 
						|
		"specific version selected": {
 | 
						|
			selectVersion:   "v2.0.0",
 | 
						|
			expectedVersion: "v2.0.0",
 | 
						|
		},
 | 
						|
	} {
 | 
						|
		t.Run(name, test(t, tc.selectVersion, tc.expectedVersion))
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestPlugin_VersionMustBeExplicitlyUpgraded(t *testing.T) {
 | 
						|
	cluster, sys := getCluster(t)
 | 
						|
	defer cluster.Cleanup()
 | 
						|
 | 
						|
	config := logical.TestBackendConfig()
 | 
						|
	config.StorageView = &logical.InmemStorage{}
 | 
						|
	config.System = sys
 | 
						|
	lb, err := Factory(context.Background(), config)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatal(err)
 | 
						|
	}
 | 
						|
	b, ok := lb.(*databaseBackend)
 | 
						|
	if !ok {
 | 
						|
		t.Fatal("could not convert to database backend")
 | 
						|
	}
 | 
						|
	defer b.Cleanup(context.Background())
 | 
						|
 | 
						|
	configData := func(extraData ...string) map[string]interface{} {
 | 
						|
		data := map[string]interface{}{
 | 
						|
			"connection_url":    "sample_connection_url",
 | 
						|
			"plugin_name":       "mysql-database-plugin",
 | 
						|
			"verify_connection": false,
 | 
						|
			"allowed_roles":     []string{"*"},
 | 
						|
			"username":          "mockv5-user",
 | 
						|
			"password":          "mysecurepassword",
 | 
						|
		}
 | 
						|
		if len(extraData)%2 != 0 {
 | 
						|
			t.Fatal("Expected an even number of args in extraData")
 | 
						|
		}
 | 
						|
		for i := 0; i < len(extraData); i += 2 {
 | 
						|
			data[extraData[i]] = extraData[i+1]
 | 
						|
		}
 | 
						|
		return data
 | 
						|
	}
 | 
						|
 | 
						|
	readVersion := func() string {
 | 
						|
		resp, err := b.HandleRequest(context.Background(), &logical.Request{
 | 
						|
			Operation: logical.ReadOperation,
 | 
						|
			Path:      "config/db",
 | 
						|
			Storage:   config.StorageView,
 | 
						|
		})
 | 
						|
		assertErrIsNil(t, err)
 | 
						|
		assertRespHasNoErr(t, resp)
 | 
						|
		return resp.Data["plugin_version"].(string)
 | 
						|
	}
 | 
						|
 | 
						|
	resp, err := b.HandleRequest(context.Background(), &logical.Request{
 | 
						|
		Operation: logical.CreateOperation,
 | 
						|
		Path:      "config/db",
 | 
						|
		Storage:   config.StorageView,
 | 
						|
		Data:      configData(),
 | 
						|
	})
 | 
						|
	assertErrIsNil(t, err)
 | 
						|
	assertRespHasNoErr(t, resp)
 | 
						|
	assertNoRespData(t, resp)
 | 
						|
 | 
						|
	version := readVersion()
 | 
						|
	expectedVersion := ""
 | 
						|
	if version != expectedVersion {
 | 
						|
		t.Fatalf("Expected version %q but got %q", expectedVersion, version)
 | 
						|
	}
 | 
						|
 | 
						|
	// Register versioned plugin, and check that a new write to existing config doesn't upgrade the plugin implicitly.
 | 
						|
	vault.TestAddTestPlugin(t, cluster.Cores[0].Core, "mysql-database-plugin", consts.PluginTypeDatabase, "v1.0.0", "TestBackend_PluginMain_MockV5", []string{}, "")
 | 
						|
	resp, err = b.HandleRequest(context.Background(), &logical.Request{
 | 
						|
		Operation: logical.UpdateOperation,
 | 
						|
		Path:      "config/db",
 | 
						|
		Storage:   config.StorageView,
 | 
						|
		Data:      configData(),
 | 
						|
	})
 | 
						|
	assertErrIsNil(t, err)
 | 
						|
	assertRespHasNoErr(t, resp)
 | 
						|
	assertNoRespData(t, resp)
 | 
						|
 | 
						|
	version = readVersion()
 | 
						|
	if version != expectedVersion {
 | 
						|
		t.Fatalf("Expected version %q but got %q", expectedVersion, version)
 | 
						|
	}
 | 
						|
 | 
						|
	// Now explicitly upgrade.
 | 
						|
	resp, err = b.HandleRequest(context.Background(), &logical.Request{
 | 
						|
		Operation: logical.UpdateOperation,
 | 
						|
		Path:      "config/db",
 | 
						|
		Storage:   config.StorageView,
 | 
						|
		Data:      configData("plugin_version", "1.0.0"),
 | 
						|
	})
 | 
						|
	assertErrIsNil(t, err)
 | 
						|
	assertRespHasNoErr(t, resp)
 | 
						|
	assertNoRespData(t, resp)
 | 
						|
 | 
						|
	version = readVersion()
 | 
						|
	expectedVersion = "v1.0.0"
 | 
						|
	if version != expectedVersion {
 | 
						|
		t.Fatalf("Expected version %q but got %q", expectedVersion, version)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func cleanup(t *testing.T, b *databaseBackend, reqs []*logical.Request) {
 | 
						|
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
 | 
						|
	defer cancel()
 | 
						|
 | 
						|
	// Go in stack order so it works similar to defer
 | 
						|
	for i := len(reqs) - 1; i >= 0; i-- {
 | 
						|
		req := reqs[i]
 | 
						|
		resp, err := b.HandleRequest(ctx, req)
 | 
						|
		if err != nil {
 | 
						|
			t.Fatalf("Error cleaning up: %s", err)
 | 
						|
		}
 | 
						|
		if resp != nil && resp.IsError() {
 | 
						|
			t.Fatalf("Error cleaning up: %s", resp.Error())
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestBackend_PluginMain_MockV4(t *testing.T) {
 | 
						|
	if os.Getenv(pluginutil.PluginUnwrapTokenEnv) == "" {
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	caPEM := os.Getenv(pluginutil.PluginCACertPEMEnv)
 | 
						|
	if caPEM == "" {
 | 
						|
		t.Fatal("CA cert not passed in")
 | 
						|
	}
 | 
						|
 | 
						|
	args := []string{"--ca-cert=" + caPEM}
 | 
						|
 | 
						|
	apiClientMeta := &api.PluginAPIClientMeta{}
 | 
						|
	flags := apiClientMeta.FlagSet()
 | 
						|
	flags.Parse(args)
 | 
						|
 | 
						|
	RunV4(apiClientMeta.GetTLSConfig())
 | 
						|
}
 | 
						|
 | 
						|
func TestBackend_PluginMain_MockV5(t *testing.T) {
 | 
						|
	if os.Getenv(pluginutil.PluginVaultVersionEnv) == "" {
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	RunV5()
 | 
						|
}
 | 
						|
 | 
						|
func TestBackend_PluginMain_MockV6Multiplexed(t *testing.T) {
 | 
						|
	if os.Getenv(pluginutil.PluginVaultVersionEnv) == "" {
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	RunV6Multiplexed()
 | 
						|
}
 | 
						|
 | 
						|
func assertNoRespData(t *testing.T, resp *logical.Response) {
 | 
						|
	t.Helper()
 | 
						|
	if resp != nil && len(resp.Data) > 0 {
 | 
						|
		t.Fatalf("Response had data when none was expected: %#v", resp.Data)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func assertRespHasData(t *testing.T, resp *logical.Response) {
 | 
						|
	t.Helper()
 | 
						|
	if resp == nil || len(resp.Data) == 0 {
 | 
						|
		t.Fatalf("Response didn't have any data when some was expected")
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
type stringAssertion func(t *testing.T, str string)
 | 
						|
 | 
						|
func assertStringPrefix(expectedPrefix string) stringAssertion {
 | 
						|
	return func(t *testing.T, str string) {
 | 
						|
		t.Helper()
 | 
						|
		if !strings.HasPrefix(str, expectedPrefix) {
 | 
						|
			t.Fatalf("Missing prefix %q: Actual: %q", expectedPrefix, str)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func assertStringRegex(expectedRegex string) stringAssertion {
 | 
						|
	re := regexp.MustCompile(expectedRegex)
 | 
						|
	return func(t *testing.T, str string) {
 | 
						|
		if !re.MatchString(str) {
 | 
						|
			t.Fatalf("Actual: %q did not match regexp %q", str, expectedRegex)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func assertRespHasNoErr(t *testing.T, resp *logical.Response) {
 | 
						|
	t.Helper()
 | 
						|
	if resp != nil && resp.IsError() {
 | 
						|
		t.Fatalf("response is error: %#v\n", resp)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func assertErrIsNil(t *testing.T, err error) {
 | 
						|
	t.Helper()
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("No error expected, got: %s", err)
 | 
						|
	}
 | 
						|
}
 |