github.com/hashicorp/vault/sdk@v0.13.0/framework/backend_test.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package framework
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"net/http"
    10  	"reflect"
    11  	"strings"
    12  	"sync/atomic"
    13  	"testing"
    14  	"time"
    15  
    16  	"github.com/hashicorp/go-secure-stdlib/strutil"
    17  	"github.com/hashicorp/vault/sdk/helper/consts"
    18  	"github.com/hashicorp/vault/sdk/logical"
    19  	"github.com/stretchr/testify/require"
    20  )
    21  
    22  func BenchmarkBackendRoute(b *testing.B) {
    23  	patterns := []string{
    24  		"foo",
    25  		"bar/(?P<name>.+?)",
    26  		"baz/(?P<name>what)",
    27  		`aws/policy/(?P<policy>\w)`,
    28  		`aws/(?P<policy>\w)`,
    29  	}
    30  
    31  	backend := &Backend{Paths: make([]*Path, 0, len(patterns))}
    32  	for _, p := range patterns {
    33  		backend.Paths = append(backend.Paths, &Path{Pattern: p})
    34  	}
    35  
    36  	// Warm any caches
    37  	backend.Route("aws/policy/foo")
    38  
    39  	// Reset the timer since we did a lot above
    40  	b.ResetTimer()
    41  
    42  	// Run through and route. We do a sanity check of the return value
    43  	for i := 0; i < b.N; i++ {
    44  		if p := backend.Route("aws/policy/foo"); p == nil {
    45  			b.Fatal("p should not be nil")
    46  		}
    47  	}
    48  }
    49  
    50  func TestBackend_impl(t *testing.T) {
    51  	var _ logical.Backend = new(Backend)
    52  }
    53  
    54  func TestBackendHandleRequestFieldWarnings(t *testing.T) {
    55  	handler := func(ctx context.Context, req *logical.Request, data *FieldData) (*logical.Response, error) {
    56  		return &logical.Response{
    57  			Data: map[string]interface{}{
    58  				"an_int":   data.Get("an_int"),
    59  				"a_string": data.Get("a_string"),
    60  				"name":     data.Get("name"),
    61  			},
    62  		}, nil
    63  	}
    64  
    65  	backend := &Backend{
    66  		Paths: []*Path{
    67  			{
    68  				Pattern: "foo/bar/(?P<name>.+)",
    69  				Fields: map[string]*FieldSchema{
    70  					"an_int":   {Type: TypeInt},
    71  					"a_string": {Type: TypeString},
    72  					"name":     {Type: TypeString},
    73  				},
    74  				Operations: map[logical.Operation]OperationHandler{
    75  					logical.UpdateOperation: &PathOperation{Callback: handler},
    76  				},
    77  			},
    78  		},
    79  	}
    80  	ctx := context.Background()
    81  	resp, err := backend.HandleRequest(ctx, &logical.Request{
    82  		Operation: logical.UpdateOperation,
    83  		Path:      "foo/bar/baz",
    84  		Data: map[string]interface{}{
    85  			"an_int":        10,
    86  			"a_string":      "accepted",
    87  			"unrecognized1": "unrecognized",
    88  			"unrecognized2": 20.2,
    89  			"name":          "noop",
    90  		},
    91  	})
    92  	require.NoError(t, err)
    93  	require.NotNil(t, resp)
    94  	t.Log(resp.Warnings)
    95  	require.Len(t, resp.Warnings, 2)
    96  	require.True(t, strutil.StrListContains(resp.Warnings, "Endpoint ignored these unrecognized parameters: [unrecognized1 unrecognized2]"))
    97  	require.True(t, strutil.StrListContains(resp.Warnings, "Endpoint replaced the value of these parameters with the values captured from the endpoint's path: [name]"))
    98  }
    99  
   100  func TestBackendHandleRequest(t *testing.T) {
   101  	callback := func(ctx context.Context, req *logical.Request, data *FieldData) (*logical.Response, error) {
   102  		return &logical.Response{
   103  			Data: map[string]interface{}{
   104  				"value": data.Get("value"),
   105  			},
   106  		}, nil
   107  	}
   108  	handler := func(ctx context.Context, req *logical.Request, data *FieldData) (*logical.Response, error) {
   109  		return &logical.Response{
   110  			Data: map[string]interface{}{
   111  				"amount": data.Get("amount"),
   112  			},
   113  		}, nil
   114  	}
   115  
   116  	b := &Backend{
   117  		Paths: []*Path{
   118  			{
   119  				Pattern: "foo/bar",
   120  				Fields: map[string]*FieldSchema{
   121  					"value": {Type: TypeInt},
   122  				},
   123  				Callbacks: map[logical.Operation]OperationFunc{
   124  					logical.ReadOperation: callback,
   125  				},
   126  			},
   127  			{
   128  				Pattern: "foo/baz/handler",
   129  				Fields: map[string]*FieldSchema{
   130  					"amount": {Type: TypeInt},
   131  				},
   132  				Operations: map[logical.Operation]OperationHandler{
   133  					logical.ReadOperation: &PathOperation{Callback: handler},
   134  				},
   135  			},
   136  			{
   137  				Pattern: "foo/both/handler",
   138  				Fields: map[string]*FieldSchema{
   139  					"amount": {Type: TypeInt},
   140  				},
   141  				Callbacks: map[logical.Operation]OperationFunc{
   142  					logical.ReadOperation: callback,
   143  				},
   144  				Operations: map[logical.Operation]OperationHandler{
   145  					logical.ReadOperation: &PathOperation{Callback: handler},
   146  				},
   147  			},
   148  		},
   149  		system: &logical.StaticSystemView{},
   150  	}
   151  
   152  	for _, path := range []string{"foo/bar", "foo/baz/handler", "foo/both/handler"} {
   153  		key := "value"
   154  		if strings.Contains(path, "handler") {
   155  			key = "amount"
   156  		}
   157  		resp, err := b.HandleRequest(context.Background(), &logical.Request{
   158  			Operation: logical.ReadOperation,
   159  			Path:      path,
   160  			Data:      map[string]interface{}{key: "42"},
   161  		})
   162  		if err != nil {
   163  			t.Fatalf("err: %s", err)
   164  		}
   165  		if resp.Data[key] != 42 {
   166  			t.Fatalf("bad: %#v", resp)
   167  		}
   168  	}
   169  }
   170  
   171  func TestBackendHandleRequest_Forwarding(t *testing.T) {
   172  	tests := map[string]struct {
   173  		fwdStandby   bool
   174  		fwdSecondary bool
   175  		isLocal      bool
   176  		isStandby    bool
   177  		isSecondary  bool
   178  		expectFwd    bool
   179  		nilSysView   bool
   180  	}{
   181  		"no forward": {
   182  			expectFwd: false,
   183  		},
   184  		"no forward, local restricted": {
   185  			isSecondary:  true,
   186  			fwdSecondary: true,
   187  			isLocal:      true,
   188  			expectFwd:    false,
   189  		},
   190  		"no forward, forwarding not requested": {
   191  			isSecondary: true,
   192  			isStandby:   true,
   193  			expectFwd:   false,
   194  		},
   195  		"forward, secondary": {
   196  			fwdSecondary: true,
   197  			isSecondary:  true,
   198  			expectFwd:    true,
   199  		},
   200  		"forward, standby": {
   201  			fwdStandby: true,
   202  			isStandby:  true,
   203  			expectFwd:  true,
   204  		},
   205  		"no forward, only secondary": {
   206  			fwdSecondary: true,
   207  			isStandby:    true,
   208  			expectFwd:    false,
   209  		},
   210  		"no forward, only standby": {
   211  			fwdStandby:  true,
   212  			isSecondary: true,
   213  			expectFwd:   false,
   214  		},
   215  		"nil system view": {
   216  			nilSysView: true,
   217  			expectFwd:  false,
   218  		},
   219  	}
   220  
   221  	for name, test := range tests {
   222  		t.Run(name, func(t *testing.T) {
   223  			var replState consts.ReplicationState
   224  			if test.isStandby {
   225  				replState.AddState(consts.ReplicationPerformanceStandby)
   226  			}
   227  			if test.isSecondary {
   228  				replState.AddState(consts.ReplicationPerformanceSecondary)
   229  			}
   230  
   231  			b := &Backend{
   232  				Paths: []*Path{
   233  					{
   234  						Pattern: "foo",
   235  						Operations: map[logical.Operation]OperationHandler{
   236  							logical.ReadOperation: &PathOperation{
   237  								Callback: func(ctx context.Context, req *logical.Request, data *FieldData) (*logical.Response, error) {
   238  									return nil, nil
   239  								},
   240  								ForwardPerformanceSecondary: test.fwdSecondary,
   241  								ForwardPerformanceStandby:   test.fwdStandby,
   242  							},
   243  						},
   244  					},
   245  				},
   246  
   247  				system: &logical.StaticSystemView{
   248  					LocalMountVal:       test.isLocal,
   249  					ReplicationStateVal: replState,
   250  				},
   251  			}
   252  
   253  			if test.nilSysView {
   254  				b.system = nil
   255  			}
   256  
   257  			_, err := b.HandleRequest(context.Background(), &logical.Request{
   258  				Operation: logical.ReadOperation,
   259  				Path:      "foo",
   260  			})
   261  
   262  			if !test.expectFwd && err != nil {
   263  				t.Fatalf("unexpected err: %v", err)
   264  			}
   265  			if test.expectFwd && err != logical.ErrReadOnly {
   266  				t.Fatalf("expected ErrReadOnly, got: %v", err)
   267  			}
   268  		})
   269  	}
   270  }
   271  
   272  func TestBackendHandleRequest_badwrite(t *testing.T) {
   273  	callback := func(ctx context.Context, req *logical.Request, data *FieldData) (*logical.Response, error) {
   274  		return &logical.Response{
   275  			Data: map[string]interface{}{
   276  				"value": data.Get("value").(bool),
   277  			},
   278  		}, nil
   279  	}
   280  
   281  	b := &Backend{
   282  		Paths: []*Path{
   283  			{
   284  				Pattern: "foo/bar",
   285  				Fields: map[string]*FieldSchema{
   286  					"value": {Type: TypeBool},
   287  				},
   288  				Callbacks: map[logical.Operation]OperationFunc{
   289  					logical.UpdateOperation: callback,
   290  				},
   291  			},
   292  		},
   293  	}
   294  
   295  	resp, err := b.HandleRequest(context.Background(), &logical.Request{
   296  		Operation: logical.UpdateOperation,
   297  		Path:      "foo/bar",
   298  		Data:      map[string]interface{}{"value": "3false3"},
   299  	})
   300  	if err != nil {
   301  		t.Fatalf("err: %s", err)
   302  	}
   303  
   304  	if !strings.Contains(resp.Data["error"].(string), "Field validation failed") {
   305  		t.Fatalf("bad: %#v", resp)
   306  	}
   307  }
   308  
   309  func TestBackendHandleRequest_404(t *testing.T) {
   310  	callback := func(ctx context.Context, req *logical.Request, data *FieldData) (*logical.Response, error) {
   311  		return &logical.Response{
   312  			Data: map[string]interface{}{
   313  				"value": data.Get("value"),
   314  			},
   315  		}, nil
   316  	}
   317  
   318  	b := &Backend{
   319  		Paths: []*Path{
   320  			{
   321  				Pattern: `foo/bar`,
   322  				Fields: map[string]*FieldSchema{
   323  					"value": {Type: TypeInt},
   324  				},
   325  				Callbacks: map[logical.Operation]OperationFunc{
   326  					logical.ReadOperation: callback,
   327  				},
   328  			},
   329  		},
   330  	}
   331  
   332  	_, err := b.HandleRequest(context.Background(), &logical.Request{
   333  		Operation: logical.ReadOperation,
   334  		Path:      "foo/baz",
   335  		Data:      map[string]interface{}{"value": "84"},
   336  	})
   337  	if err != logical.ErrUnsupportedPath {
   338  		t.Fatalf("err: %s", err)
   339  	}
   340  }
   341  
   342  func TestBackendHandleRequest_help(t *testing.T) {
   343  	b := &Backend{
   344  		Paths: []*Path{
   345  			{
   346  				Pattern: "foo/bar",
   347  				Fields: map[string]*FieldSchema{
   348  					"value": {Type: TypeInt},
   349  				},
   350  				HelpSynopsis:    "foo",
   351  				HelpDescription: "bar",
   352  			},
   353  		},
   354  	}
   355  
   356  	resp, err := b.HandleRequest(context.Background(), &logical.Request{
   357  		Operation: logical.HelpOperation,
   358  		Path:      "foo/bar",
   359  		Data:      map[string]interface{}{"value": "42"},
   360  	})
   361  	if err != nil {
   362  		t.Fatalf("err: %s", err)
   363  	}
   364  	if resp.Data["help"] == nil {
   365  		t.Fatalf("bad: %#v", resp)
   366  	}
   367  }
   368  
   369  func TestBackendHandleRequest_helpRoot(t *testing.T) {
   370  	b := &Backend{
   371  		Help: "42",
   372  	}
   373  
   374  	resp, err := b.HandleRequest(context.Background(), &logical.Request{
   375  		Operation: logical.HelpOperation,
   376  		Path:      "",
   377  	})
   378  	if err != nil {
   379  		t.Fatalf("err: %s", err)
   380  	}
   381  	if resp.Data["help"] == nil {
   382  		t.Fatalf("bad: %#v", resp)
   383  	}
   384  }
   385  
   386  func TestBackendHandleRequest_renewAuth(t *testing.T) {
   387  	b := &Backend{}
   388  
   389  	resp, err := b.HandleRequest(context.Background(), logical.RenewAuthRequest("/foo", &logical.Auth{}, nil))
   390  	if err != nil {
   391  		t.Fatalf("err: %s", err)
   392  	}
   393  	if !resp.IsError() {
   394  		t.Fatalf("bad: %#v", resp)
   395  	}
   396  }
   397  
   398  func TestBackendHandleRequest_renewAuthCallback(t *testing.T) {
   399  	called := new(uint32)
   400  	callback := func(context.Context, *logical.Request, *FieldData) (*logical.Response, error) {
   401  		atomic.AddUint32(called, 1)
   402  		return nil, nil
   403  	}
   404  
   405  	b := &Backend{
   406  		AuthRenew: callback,
   407  	}
   408  
   409  	_, err := b.HandleRequest(context.Background(), logical.RenewAuthRequest("/foo", &logical.Auth{}, nil))
   410  	if err != nil {
   411  		t.Fatalf("err: %s", err)
   412  	}
   413  	if v := atomic.LoadUint32(called); v != 1 {
   414  		t.Fatalf("bad: %#v", v)
   415  	}
   416  }
   417  
   418  func TestBackendHandleRequest_renew(t *testing.T) {
   419  	called := new(uint32)
   420  	callback := func(context.Context, *logical.Request, *FieldData) (*logical.Response, error) {
   421  		atomic.AddUint32(called, 1)
   422  		return nil, nil
   423  	}
   424  
   425  	secret := &Secret{
   426  		Type:  "foo",
   427  		Renew: callback,
   428  	}
   429  	b := &Backend{
   430  		Secrets: []*Secret{secret},
   431  	}
   432  
   433  	_, err := b.HandleRequest(context.Background(), logical.RenewRequest("/foo", secret.Response(nil, nil).Secret, nil))
   434  	if err != nil {
   435  		t.Fatalf("err: %s", err)
   436  	}
   437  	if v := atomic.LoadUint32(called); v != 1 {
   438  		t.Fatalf("bad: %#v", v)
   439  	}
   440  }
   441  
   442  func TestBackendHandleRequest_revoke(t *testing.T) {
   443  	called := new(uint32)
   444  	callback := func(context.Context, *logical.Request, *FieldData) (*logical.Response, error) {
   445  		atomic.AddUint32(called, 1)
   446  		return nil, nil
   447  	}
   448  
   449  	secret := &Secret{
   450  		Type:   "foo",
   451  		Revoke: callback,
   452  	}
   453  	b := &Backend{
   454  		Secrets: []*Secret{secret},
   455  	}
   456  
   457  	_, err := b.HandleRequest(context.Background(), logical.RevokeRequest("/foo", secret.Response(nil, nil).Secret, nil))
   458  	if err != nil {
   459  		t.Fatalf("err: %s", err)
   460  	}
   461  	if v := atomic.LoadUint32(called); v != 1 {
   462  		t.Fatalf("bad: %#v", v)
   463  	}
   464  }
   465  
   466  func TestBackendHandleRequest_rollback(t *testing.T) {
   467  	called := new(uint32)
   468  	callback := func(_ context.Context, req *logical.Request, kind string, data interface{}) error {
   469  		if data == "foo" {
   470  			atomic.AddUint32(called, 1)
   471  		}
   472  		return nil
   473  	}
   474  
   475  	b := &Backend{
   476  		WALRollback:       callback,
   477  		WALRollbackMinAge: 1 * time.Millisecond,
   478  	}
   479  
   480  	storage := new(logical.InmemStorage)
   481  	if _, err := PutWAL(context.Background(), storage, "kind", "foo"); err != nil {
   482  		t.Fatalf("err: %s", err)
   483  	}
   484  
   485  	time.Sleep(10 * time.Millisecond)
   486  
   487  	_, err := b.HandleRequest(context.Background(), &logical.Request{
   488  		Operation: logical.RollbackOperation,
   489  		Path:      "",
   490  		Storage:   storage,
   491  	})
   492  	if err != nil {
   493  		t.Fatalf("err: %s", err)
   494  	}
   495  	if v := atomic.LoadUint32(called); v != 1 {
   496  		t.Fatalf("bad: %#v", v)
   497  	}
   498  }
   499  
   500  func TestBackendHandleRequest_rollbackMinAge(t *testing.T) {
   501  	called := new(uint32)
   502  	callback := func(_ context.Context, req *logical.Request, kind string, data interface{}) error {
   503  		if data == "foo" {
   504  			atomic.AddUint32(called, 1)
   505  		}
   506  		return nil
   507  	}
   508  
   509  	b := &Backend{
   510  		WALRollback:       callback,
   511  		WALRollbackMinAge: 5 * time.Second,
   512  	}
   513  
   514  	storage := new(logical.InmemStorage)
   515  	if _, err := PutWAL(context.Background(), storage, "kind", "foo"); err != nil {
   516  		t.Fatalf("err: %s", err)
   517  	}
   518  
   519  	_, err := b.HandleRequest(context.Background(), &logical.Request{
   520  		Operation: logical.RollbackOperation,
   521  		Path:      "",
   522  		Storage:   storage,
   523  	})
   524  	if err != nil {
   525  		t.Fatalf("err: %s", err)
   526  	}
   527  	if v := atomic.LoadUint32(called); v != 0 {
   528  		t.Fatalf("bad: %#v", v)
   529  	}
   530  }
   531  
   532  func TestBackendHandleRequest_unsupportedOperation(t *testing.T) {
   533  	callback := func(ctx context.Context, req *logical.Request, data *FieldData) (*logical.Response, error) {
   534  		return &logical.Response{
   535  			Data: map[string]interface{}{
   536  				"value": data.Get("value"),
   537  			},
   538  		}, nil
   539  	}
   540  
   541  	b := &Backend{
   542  		Paths: []*Path{
   543  			{
   544  				Pattern: `foo/bar`,
   545  				Fields: map[string]*FieldSchema{
   546  					"value": {Type: TypeInt},
   547  				},
   548  				Callbacks: map[logical.Operation]OperationFunc{
   549  					logical.ReadOperation: callback,
   550  				},
   551  			},
   552  		},
   553  	}
   554  
   555  	_, err := b.HandleRequest(context.Background(), &logical.Request{
   556  		Operation: logical.UpdateOperation,
   557  		Path:      "foo/bar",
   558  		Data:      map[string]interface{}{"value": "84"},
   559  	})
   560  	if err != logical.ErrUnsupportedOperation {
   561  		t.Fatalf("err: %s", err)
   562  	}
   563  }
   564  
   565  func TestBackendHandleRequest_urlPriority(t *testing.T) {
   566  	callback := func(ctx context.Context, req *logical.Request, data *FieldData) (*logical.Response, error) {
   567  		return &logical.Response{
   568  			Data: map[string]interface{}{
   569  				"value": data.Get("value"),
   570  			},
   571  		}, nil
   572  	}
   573  
   574  	b := &Backend{
   575  		Paths: []*Path{
   576  			{
   577  				Pattern: `foo/(?P<value>\d+)`,
   578  				Fields: map[string]*FieldSchema{
   579  					"value": {Type: TypeInt},
   580  				},
   581  				Callbacks: map[logical.Operation]OperationFunc{
   582  					logical.ReadOperation: callback,
   583  				},
   584  			},
   585  		},
   586  	}
   587  
   588  	resp, err := b.HandleRequest(context.Background(), &logical.Request{
   589  		Operation: logical.ReadOperation,
   590  		Path:      "foo/42",
   591  		Data:      map[string]interface{}{"value": "84"},
   592  	})
   593  	if err != nil {
   594  		t.Fatalf("err: %s", err)
   595  	}
   596  	if resp.Data["value"] != 42 {
   597  		t.Fatalf("bad: %#v", resp)
   598  	}
   599  }
   600  
   601  func TestBackendRoute(t *testing.T) {
   602  	cases := map[string]struct {
   603  		Patterns []string
   604  		Path     string
   605  		Match    string
   606  	}{
   607  		"no match": {
   608  			[]string{"foo"},
   609  			"bar",
   610  			"",
   611  		},
   612  
   613  		"exact": {
   614  			[]string{"foo"},
   615  			"foo",
   616  			"^foo$",
   617  		},
   618  
   619  		"regexp": {
   620  			[]string{"fo+"},
   621  			"foo",
   622  			"^fo+$",
   623  		},
   624  
   625  		"anchor-start": {
   626  			[]string{"bar"},
   627  			"foobar",
   628  			"",
   629  		},
   630  
   631  		"anchor-end": {
   632  			[]string{"bar"},
   633  			"barfoo",
   634  			"",
   635  		},
   636  
   637  		"anchor-ambiguous": {
   638  			[]string{"mounts", "sys/mounts"},
   639  			"sys/mounts",
   640  			"^sys/mounts$",
   641  		},
   642  	}
   643  
   644  	for n, tc := range cases {
   645  		paths := make([]*Path, len(tc.Patterns))
   646  		for i, pattern := range tc.Patterns {
   647  			paths[i] = &Path{Pattern: pattern}
   648  		}
   649  
   650  		b := &Backend{Paths: paths}
   651  		result := b.Route(tc.Path)
   652  		match := ""
   653  		if result != nil {
   654  			match = result.Pattern
   655  		}
   656  
   657  		if match != tc.Match {
   658  			t.Fatalf("bad: %s\n\nExpected: %s\nGot: %s",
   659  				n, tc.Match, match)
   660  		}
   661  	}
   662  }
   663  
   664  func TestBackendSecret(t *testing.T) {
   665  	cases := map[string]struct {
   666  		Secrets []*Secret
   667  		Search  string
   668  		Match   bool
   669  	}{
   670  		"no match": {
   671  			[]*Secret{{Type: "foo"}},
   672  			"bar",
   673  			false,
   674  		},
   675  
   676  		"match": {
   677  			[]*Secret{{Type: "foo"}},
   678  			"foo",
   679  			true,
   680  		},
   681  	}
   682  
   683  	for n, tc := range cases {
   684  		b := &Backend{Secrets: tc.Secrets}
   685  		result := b.Secret(tc.Search)
   686  		if tc.Match != (result != nil) {
   687  			t.Fatalf("bad: %s\n\nExpected match: %v", n, tc.Match)
   688  		}
   689  		if result != nil && result.Type != tc.Search {
   690  			t.Fatalf("bad: %s\n\nExpected matching type: %#v", n, result)
   691  		}
   692  	}
   693  }
   694  
   695  func TestFieldSchemaDefaultOrZero(t *testing.T) {
   696  	cases := map[string]struct {
   697  		Schema *FieldSchema
   698  		Value  interface{}
   699  	}{
   700  		"default set": {
   701  			&FieldSchema{Type: TypeString, Default: "foo"},
   702  			"foo",
   703  		},
   704  
   705  		"default not set": {
   706  			&FieldSchema{Type: TypeString},
   707  			"",
   708  		},
   709  
   710  		"default duration set": {
   711  			&FieldSchema{Type: TypeDurationSecond, Default: 60},
   712  			60,
   713  		},
   714  
   715  		"default duration int64": {
   716  			&FieldSchema{Type: TypeDurationSecond, Default: int64(60)},
   717  			60,
   718  		},
   719  
   720  		"default duration string": {
   721  			&FieldSchema{Type: TypeDurationSecond, Default: "60s"},
   722  			60,
   723  		},
   724  
   725  		"illegal default duration string": {
   726  			&FieldSchema{Type: TypeDurationSecond, Default: "h1"},
   727  			0,
   728  		},
   729  
   730  		"default duration time.Duration": {
   731  			&FieldSchema{Type: TypeDurationSecond, Default: 60 * time.Second},
   732  			60,
   733  		},
   734  
   735  		"default duration not set": {
   736  			&FieldSchema{Type: TypeDurationSecond},
   737  			0,
   738  		},
   739  
   740  		"default signed positive duration set": {
   741  			&FieldSchema{Type: TypeSignedDurationSecond, Default: 60},
   742  			60,
   743  		},
   744  
   745  		"default signed positive duration int64": {
   746  			&FieldSchema{Type: TypeSignedDurationSecond, Default: int64(60)},
   747  			60,
   748  		},
   749  
   750  		"default signed positive duration string": {
   751  			&FieldSchema{Type: TypeSignedDurationSecond, Default: "60s"},
   752  			60,
   753  		},
   754  
   755  		"illegal default signed duration string": {
   756  			&FieldSchema{Type: TypeDurationSecond, Default: "-h1"},
   757  			0,
   758  		},
   759  
   760  		"default signed positive duration time.Duration": {
   761  			&FieldSchema{Type: TypeSignedDurationSecond, Default: 60 * time.Second},
   762  			60,
   763  		},
   764  
   765  		"default signed negative duration set": {
   766  			&FieldSchema{Type: TypeSignedDurationSecond, Default: -60},
   767  			-60,
   768  		},
   769  
   770  		"default signed negative duration int64": {
   771  			&FieldSchema{Type: TypeSignedDurationSecond, Default: int64(-60)},
   772  			-60,
   773  		},
   774  
   775  		"default signed negative duration string": {
   776  			&FieldSchema{Type: TypeSignedDurationSecond, Default: "-60s"},
   777  			-60,
   778  		},
   779  
   780  		"default signed negative duration time.Duration": {
   781  			&FieldSchema{Type: TypeSignedDurationSecond, Default: -60 * time.Second},
   782  			-60,
   783  		},
   784  
   785  		"default signed negative duration not set": {
   786  			&FieldSchema{Type: TypeSignedDurationSecond},
   787  			0,
   788  		},
   789  		"default header not set": {
   790  			&FieldSchema{Type: TypeHeader},
   791  			http.Header{},
   792  		},
   793  	}
   794  
   795  	for name, tc := range cases {
   796  		actual := tc.Schema.DefaultOrZero()
   797  		if !reflect.DeepEqual(actual, tc.Value) {
   798  			t.Errorf("bad: %s\n\nExpected: %#v\nGot: %#v",
   799  				name, tc.Value, actual)
   800  		}
   801  	}
   802  }
   803  
   804  func TestInitializeBackend(t *testing.T) {
   805  	var inited bool
   806  	backend := &Backend{InitializeFunc: func(context.Context, *logical.InitializationRequest) error {
   807  		inited = true
   808  		return nil
   809  	}}
   810  
   811  	backend.Initialize(nil, &logical.InitializationRequest{Storage: nil})
   812  
   813  	if !inited {
   814  		t.Fatal("backend should be open")
   815  	}
   816  }
   817  
   818  // TestFieldTypeMethods tries to ensure our switch-case statements for the
   819  // FieldType "enum" are complete.
   820  func TestFieldTypeMethods(t *testing.T) {
   821  	unknownFormat := convertType(TypeInvalid).format
   822  
   823  	for i := TypeInvalid + 1; i < typeInvalidMax; i++ {
   824  		t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
   825  			if i.String() == TypeInvalid.String() {
   826  				t.Errorf("unknown type string for %d", i)
   827  			}
   828  
   829  			if convertType(i).format == unknownFormat {
   830  				t.Errorf("unknown schema for %d", i)
   831  			}
   832  
   833  			_ = i.Zero()
   834  		})
   835  	}
   836  }