github.com/hashicorp/vault/sdk@v0.13.0/database/dbplugin/v5/grpc_server_test.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package dbplugin
     5  
     6  import (
     7  	"context"
     8  	"errors"
     9  	"fmt"
    10  	"reflect"
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/golang/protobuf/ptypes"
    15  	"github.com/golang/protobuf/ptypes/timestamp"
    16  	"github.com/hashicorp/vault/sdk/database/dbplugin/v5/proto"
    17  	"github.com/hashicorp/vault/sdk/helper/pluginutil"
    18  	"github.com/hashicorp/vault/sdk/logical"
    19  	"google.golang.org/grpc/codes"
    20  	"google.golang.org/grpc/metadata"
    21  	"google.golang.org/grpc/status"
    22  	"google.golang.org/protobuf/types/known/structpb"
    23  )
    24  
    25  // Before minValidSeconds in ptypes package
    26  var invalidExpiration = time.Date(0, 1, 1, 0, 0, 0, 0, time.UTC)
    27  
    28  func TestGRPCServer_Initialize(t *testing.T) {
    29  	type testCase struct {
    30  		db            Database
    31  		req           *proto.InitializeRequest
    32  		expectedResp  *proto.InitializeResponse
    33  		expectErr     bool
    34  		expectCode    codes.Code
    35  		grpcSetupFunc func(*testing.T, Database) (context.Context, gRPCServer)
    36  	}
    37  
    38  	tests := map[string]testCase{
    39  		"database errored": {
    40  			db: fakeDatabase{
    41  				initErr: errors.New("initialization error"),
    42  			},
    43  			req:           &proto.InitializeRequest{},
    44  			expectedResp:  &proto.InitializeResponse{},
    45  			expectErr:     true,
    46  			expectCode:    codes.Internal,
    47  			grpcSetupFunc: testGrpcServer,
    48  		},
    49  		"newConfig can't marshal to JSON": {
    50  			db: fakeDatabase{
    51  				initResp: InitializeResponse{
    52  					Config: map[string]interface{}{
    53  						"bad-data": badJSONValue{},
    54  					},
    55  				},
    56  			},
    57  			req:           &proto.InitializeRequest{},
    58  			expectedResp:  &proto.InitializeResponse{},
    59  			expectErr:     true,
    60  			expectCode:    codes.Internal,
    61  			grpcSetupFunc: testGrpcServer,
    62  		},
    63  		"happy path with config data for multiplexed plugin": {
    64  			db: fakeDatabase{
    65  				initResp: InitializeResponse{
    66  					Config: map[string]interface{}{
    67  						"foo": "bar",
    68  					},
    69  				},
    70  			},
    71  			req: &proto.InitializeRequest{
    72  				ConfigData: marshal(t, map[string]interface{}{
    73  					"foo": "bar",
    74  				}),
    75  			},
    76  			expectedResp: &proto.InitializeResponse{
    77  				ConfigData: marshal(t, map[string]interface{}{
    78  					"foo": "bar",
    79  				}),
    80  			},
    81  			expectErr:     false,
    82  			expectCode:    codes.OK,
    83  			grpcSetupFunc: testGrpcServer,
    84  		},
    85  		"happy path with config data for non-multiplexed plugin": {
    86  			db: fakeDatabase{
    87  				initResp: InitializeResponse{
    88  					Config: map[string]interface{}{
    89  						"foo": "bar",
    90  					},
    91  				},
    92  			},
    93  			req: &proto.InitializeRequest{
    94  				ConfigData: marshal(t, map[string]interface{}{
    95  					"foo": "bar",
    96  				}),
    97  			},
    98  			expectedResp: &proto.InitializeResponse{
    99  				ConfigData: marshal(t, map[string]interface{}{
   100  					"foo": "bar",
   101  				}),
   102  			},
   103  			expectErr:     false,
   104  			expectCode:    codes.OK,
   105  			grpcSetupFunc: testGrpcServerSingleImpl,
   106  		},
   107  	}
   108  
   109  	for name, test := range tests {
   110  		t.Run(name, func(t *testing.T) {
   111  			idCtx, g := test.grpcSetupFunc(t, test.db)
   112  			resp, err := g.Initialize(idCtx, test.req)
   113  
   114  			if test.expectErr && err == nil {
   115  				t.Fatalf("err expected, got nil")
   116  			}
   117  			if !test.expectErr && err != nil {
   118  				t.Fatalf("no error expected, got: %s", err)
   119  			}
   120  
   121  			actualCode := status.Code(err)
   122  			if actualCode != test.expectCode {
   123  				t.Fatalf("Actual code: %s Expected code: %s", actualCode, test.expectCode)
   124  			}
   125  
   126  			if !reflect.DeepEqual(resp, test.expectedResp) {
   127  				t.Fatalf("Actual response: %#v\nExpected response: %#v", resp, test.expectedResp)
   128  			}
   129  		})
   130  	}
   131  }
   132  
   133  func TestCoerceFloatsToInt(t *testing.T) {
   134  	type testCase struct {
   135  		input    map[string]interface{}
   136  		expected map[string]interface{}
   137  	}
   138  
   139  	tests := map[string]testCase{
   140  		"no numbers": {
   141  			input: map[string]interface{}{
   142  				"foo": "bar",
   143  			},
   144  			expected: map[string]interface{}{
   145  				"foo": "bar",
   146  			},
   147  		},
   148  		"raw integers": {
   149  			input: map[string]interface{}{
   150  				"foo": 42,
   151  			},
   152  			expected: map[string]interface{}{
   153  				"foo": 42,
   154  			},
   155  		},
   156  		"floats ": {
   157  			input: map[string]interface{}{
   158  				"foo": 42.2,
   159  			},
   160  			expected: map[string]interface{}{
   161  				"foo": 42.2,
   162  			},
   163  		},
   164  		"floats coerced to ints": {
   165  			input: map[string]interface{}{
   166  				"foo": float64(42),
   167  			},
   168  			expected: map[string]interface{}{
   169  				"foo": int64(42),
   170  			},
   171  		},
   172  	}
   173  
   174  	for name, test := range tests {
   175  		t.Run(name, func(t *testing.T) {
   176  			actual := copyMap(test.input)
   177  			coerceFloatsToInt(actual)
   178  			if !reflect.DeepEqual(actual, test.expected) {
   179  				t.Fatalf("Actual: %#v\nExpected: %#v", actual, test.expected)
   180  			}
   181  		})
   182  	}
   183  }
   184  
   185  func copyMap(m map[string]interface{}) map[string]interface{} {
   186  	newMap := map[string]interface{}{}
   187  	for k, v := range m {
   188  		newMap[k] = v
   189  	}
   190  	return newMap
   191  }
   192  
   193  func TestGRPCServer_NewUser(t *testing.T) {
   194  	type testCase struct {
   195  		db           Database
   196  		req          *proto.NewUserRequest
   197  		expectedResp *proto.NewUserResponse
   198  		expectErr    bool
   199  		expectCode   codes.Code
   200  	}
   201  
   202  	tests := map[string]testCase{
   203  		"missing username config": {
   204  			db:           fakeDatabase{},
   205  			req:          &proto.NewUserRequest{},
   206  			expectedResp: &proto.NewUserResponse{},
   207  			expectErr:    true,
   208  			expectCode:   codes.InvalidArgument,
   209  		},
   210  		"bad expiration": {
   211  			db: fakeDatabase{},
   212  			req: &proto.NewUserRequest{
   213  				UsernameConfig: &proto.UsernameConfig{
   214  					DisplayName: "dispname",
   215  					RoleName:    "rolename",
   216  				},
   217  				Expiration: &timestamp.Timestamp{
   218  					Seconds: invalidExpiration.Unix(),
   219  				},
   220  			},
   221  			expectedResp: &proto.NewUserResponse{},
   222  			expectErr:    true,
   223  			expectCode:   codes.InvalidArgument,
   224  		},
   225  		"database error": {
   226  			db: fakeDatabase{
   227  				newUserErr: errors.New("new user error"),
   228  			},
   229  			req: &proto.NewUserRequest{
   230  				UsernameConfig: &proto.UsernameConfig{
   231  					DisplayName: "dispname",
   232  					RoleName:    "rolename",
   233  				},
   234  				Expiration: ptypes.TimestampNow(),
   235  			},
   236  			expectedResp: &proto.NewUserResponse{},
   237  			expectErr:    true,
   238  			expectCode:   codes.Internal,
   239  		},
   240  		"happy path with expiration": {
   241  			db: fakeDatabase{
   242  				newUserResp: NewUserResponse{
   243  					Username: "someuser_foo",
   244  				},
   245  			},
   246  			req: &proto.NewUserRequest{
   247  				UsernameConfig: &proto.UsernameConfig{
   248  					DisplayName: "dispname",
   249  					RoleName:    "rolename",
   250  				},
   251  				Expiration: ptypes.TimestampNow(),
   252  			},
   253  			expectedResp: &proto.NewUserResponse{
   254  				Username: "someuser_foo",
   255  			},
   256  			expectErr:  false,
   257  			expectCode: codes.OK,
   258  		},
   259  		"happy path without expiration": {
   260  			db: fakeDatabase{
   261  				newUserResp: NewUserResponse{
   262  					Username: "someuser_foo",
   263  				},
   264  			},
   265  			req: &proto.NewUserRequest{
   266  				UsernameConfig: &proto.UsernameConfig{
   267  					DisplayName: "dispname",
   268  					RoleName:    "rolename",
   269  				},
   270  			},
   271  			expectedResp: &proto.NewUserResponse{
   272  				Username: "someuser_foo",
   273  			},
   274  			expectErr:  false,
   275  			expectCode: codes.OK,
   276  		},
   277  	}
   278  
   279  	for name, test := range tests {
   280  		t.Run(name, func(t *testing.T) {
   281  			idCtx, g := testGrpcServer(t, test.db)
   282  			resp, err := g.NewUser(idCtx, test.req)
   283  
   284  			if test.expectErr && err == nil {
   285  				t.Fatalf("err expected, got nil")
   286  			}
   287  			if !test.expectErr && err != nil {
   288  				t.Fatalf("no error expected, got: %s", err)
   289  			}
   290  
   291  			actualCode := status.Code(err)
   292  			if actualCode != test.expectCode {
   293  				t.Fatalf("Actual code: %s Expected code: %s", actualCode, test.expectCode)
   294  			}
   295  
   296  			if !reflect.DeepEqual(resp, test.expectedResp) {
   297  				t.Fatalf("Actual response: %#v\nExpected response: %#v", resp, test.expectedResp)
   298  			}
   299  		})
   300  	}
   301  }
   302  
   303  func TestGRPCServer_UpdateUser(t *testing.T) {
   304  	type testCase struct {
   305  		db           Database
   306  		req          *proto.UpdateUserRequest
   307  		expectedResp *proto.UpdateUserResponse
   308  		expectErr    bool
   309  		expectCode   codes.Code
   310  	}
   311  
   312  	tests := map[string]testCase{
   313  		"missing username": {
   314  			db:           fakeDatabase{},
   315  			req:          &proto.UpdateUserRequest{},
   316  			expectedResp: &proto.UpdateUserResponse{},
   317  			expectErr:    true,
   318  			expectCode:   codes.InvalidArgument,
   319  		},
   320  		"missing changes": {
   321  			db: fakeDatabase{},
   322  			req: &proto.UpdateUserRequest{
   323  				Username: "someuser",
   324  			},
   325  			expectedResp: &proto.UpdateUserResponse{},
   326  			expectErr:    true,
   327  			expectCode:   codes.InvalidArgument,
   328  		},
   329  		"database error": {
   330  			db: fakeDatabase{
   331  				updateUserErr: errors.New("update user error"),
   332  			},
   333  			req: &proto.UpdateUserRequest{
   334  				Username: "someuser",
   335  				Password: &proto.ChangePassword{
   336  					NewPassword: "90ughaino",
   337  				},
   338  			},
   339  			expectedResp: &proto.UpdateUserResponse{},
   340  			expectErr:    true,
   341  			expectCode:   codes.Internal,
   342  		},
   343  		"bad expiration date": {
   344  			db: fakeDatabase{},
   345  			req: &proto.UpdateUserRequest{
   346  				Username: "someuser",
   347  				Expiration: &proto.ChangeExpiration{
   348  					NewExpiration: &timestamp.Timestamp{
   349  						// Before minValidSeconds in ptypes package
   350  						Seconds: invalidExpiration.Unix(),
   351  					},
   352  				},
   353  			},
   354  			expectedResp: &proto.UpdateUserResponse{},
   355  			expectErr:    true,
   356  			expectCode:   codes.InvalidArgument,
   357  		},
   358  		"change password happy path": {
   359  			db: fakeDatabase{},
   360  			req: &proto.UpdateUserRequest{
   361  				Username: "someuser",
   362  				Password: &proto.ChangePassword{
   363  					NewPassword: "90ughaino",
   364  				},
   365  			},
   366  			expectedResp: &proto.UpdateUserResponse{},
   367  			expectErr:    false,
   368  			expectCode:   codes.OK,
   369  		},
   370  		"change expiration happy path": {
   371  			db: fakeDatabase{},
   372  			req: &proto.UpdateUserRequest{
   373  				Username: "someuser",
   374  				Expiration: &proto.ChangeExpiration{
   375  					NewExpiration: ptypes.TimestampNow(),
   376  				},
   377  			},
   378  			expectedResp: &proto.UpdateUserResponse{},
   379  			expectErr:    false,
   380  			expectCode:   codes.OK,
   381  		},
   382  	}
   383  
   384  	for name, test := range tests {
   385  		t.Run(name, func(t *testing.T) {
   386  			idCtx, g := testGrpcServer(t, test.db)
   387  			resp, err := g.UpdateUser(idCtx, test.req)
   388  
   389  			if test.expectErr && err == nil {
   390  				t.Fatalf("err expected, got nil")
   391  			}
   392  			if !test.expectErr && err != nil {
   393  				t.Fatalf("no error expected, got: %s", err)
   394  			}
   395  
   396  			actualCode := status.Code(err)
   397  			if actualCode != test.expectCode {
   398  				t.Fatalf("Actual code: %s Expected code: %s", actualCode, test.expectCode)
   399  			}
   400  
   401  			if !reflect.DeepEqual(resp, test.expectedResp) {
   402  				t.Fatalf("Actual response: %#v\nExpected response: %#v", resp, test.expectedResp)
   403  			}
   404  		})
   405  	}
   406  }
   407  
   408  func TestGRPCServer_DeleteUser(t *testing.T) {
   409  	type testCase struct {
   410  		db           Database
   411  		req          *proto.DeleteUserRequest
   412  		expectedResp *proto.DeleteUserResponse
   413  		expectErr    bool
   414  		expectCode   codes.Code
   415  	}
   416  
   417  	tests := map[string]testCase{
   418  		"missing username": {
   419  			db:           fakeDatabase{},
   420  			req:          &proto.DeleteUserRequest{},
   421  			expectedResp: &proto.DeleteUserResponse{},
   422  			expectErr:    true,
   423  			expectCode:   codes.InvalidArgument,
   424  		},
   425  		"database error": {
   426  			db: fakeDatabase{
   427  				deleteUserErr: errors.New("delete user error"),
   428  			},
   429  			req: &proto.DeleteUserRequest{
   430  				Username: "someuser",
   431  			},
   432  			expectedResp: &proto.DeleteUserResponse{},
   433  			expectErr:    true,
   434  			expectCode:   codes.Internal,
   435  		},
   436  		"happy path": {
   437  			db: fakeDatabase{},
   438  			req: &proto.DeleteUserRequest{
   439  				Username: "someuser",
   440  			},
   441  			expectedResp: &proto.DeleteUserResponse{},
   442  			expectErr:    false,
   443  			expectCode:   codes.OK,
   444  		},
   445  	}
   446  
   447  	for name, test := range tests {
   448  		t.Run(name, func(t *testing.T) {
   449  			idCtx, g := testGrpcServer(t, test.db)
   450  			resp, err := g.DeleteUser(idCtx, test.req)
   451  
   452  			if test.expectErr && err == nil {
   453  				t.Fatalf("err expected, got nil")
   454  			}
   455  			if !test.expectErr && err != nil {
   456  				t.Fatalf("no error expected, got: %s", err)
   457  			}
   458  
   459  			actualCode := status.Code(err)
   460  			if actualCode != test.expectCode {
   461  				t.Fatalf("Actual code: %s Expected code: %s", actualCode, test.expectCode)
   462  			}
   463  
   464  			if !reflect.DeepEqual(resp, test.expectedResp) {
   465  				t.Fatalf("Actual response: %#v\nExpected response: %#v", resp, test.expectedResp)
   466  			}
   467  		})
   468  	}
   469  }
   470  
   471  func TestGRPCServer_Type(t *testing.T) {
   472  	type testCase struct {
   473  		db           Database
   474  		expectedResp *proto.TypeResponse
   475  		expectErr    bool
   476  		expectCode   codes.Code
   477  	}
   478  
   479  	tests := map[string]testCase{
   480  		"database error": {
   481  			db: fakeDatabase{
   482  				typeErr: errors.New("type error"),
   483  			},
   484  			expectedResp: &proto.TypeResponse{},
   485  			expectErr:    true,
   486  			expectCode:   codes.Internal,
   487  		},
   488  		"happy path": {
   489  			db: fakeDatabase{
   490  				typeResp: "fake database",
   491  			},
   492  			expectedResp: &proto.TypeResponse{
   493  				Type: "fake database",
   494  			},
   495  			expectErr:  false,
   496  			expectCode: codes.OK,
   497  		},
   498  	}
   499  
   500  	for name, test := range tests {
   501  		t.Run(name, func(t *testing.T) {
   502  			idCtx, g := testGrpcServer(t, test.db)
   503  			resp, err := g.Type(idCtx, &proto.Empty{})
   504  
   505  			if test.expectErr && err == nil {
   506  				t.Fatalf("err expected, got nil")
   507  			}
   508  			if !test.expectErr && err != nil {
   509  				t.Fatalf("no error expected, got: %s", err)
   510  			}
   511  
   512  			actualCode := status.Code(err)
   513  			if actualCode != test.expectCode {
   514  				t.Fatalf("Actual code: %s Expected code: %s", actualCode, test.expectCode)
   515  			}
   516  
   517  			if !reflect.DeepEqual(resp, test.expectedResp) {
   518  				t.Fatalf("Actual response: %#v\nExpected response: %#v", resp, test.expectedResp)
   519  			}
   520  		})
   521  	}
   522  }
   523  
   524  func TestGRPCServer_Close(t *testing.T) {
   525  	type testCase struct {
   526  		db            Database
   527  		expectErr     bool
   528  		expectCode    codes.Code
   529  		grpcSetupFunc func(*testing.T, Database) (context.Context, gRPCServer)
   530  		assertFunc    func(t *testing.T, g gRPCServer)
   531  	}
   532  
   533  	tests := map[string]testCase{
   534  		"database error": {
   535  			db: fakeDatabase{
   536  				closeErr: errors.New("close error"),
   537  			},
   538  			expectErr:     true,
   539  			expectCode:    codes.Internal,
   540  			grpcSetupFunc: testGrpcServer,
   541  			assertFunc:    nil,
   542  		},
   543  		"happy path for multiplexed plugin": {
   544  			db:            fakeDatabase{},
   545  			expectErr:     false,
   546  			expectCode:    codes.OK,
   547  			grpcSetupFunc: testGrpcServer,
   548  			assertFunc: func(t *testing.T, g gRPCServer) {
   549  				if len(g.instances) != 0 {
   550  					t.Fatalf("err expected instances map to be empty")
   551  				}
   552  			},
   553  		},
   554  		"happy path for non-multiplexed plugin": {
   555  			db:            fakeDatabase{},
   556  			expectErr:     false,
   557  			expectCode:    codes.OK,
   558  			grpcSetupFunc: testGrpcServerSingleImpl,
   559  			assertFunc:    nil,
   560  		},
   561  	}
   562  
   563  	for name, test := range tests {
   564  		t.Run(name, func(t *testing.T) {
   565  			idCtx, g := test.grpcSetupFunc(t, test.db)
   566  			_, err := g.Close(idCtx, &proto.Empty{})
   567  
   568  			if test.expectErr && err == nil {
   569  				t.Fatalf("err expected, got nil")
   570  			}
   571  			if !test.expectErr && err != nil {
   572  				t.Fatalf("no error expected, got: %s", err)
   573  			}
   574  
   575  			actualCode := status.Code(err)
   576  			if actualCode != test.expectCode {
   577  				t.Fatalf("Actual code: %s Expected code: %s", actualCode, test.expectCode)
   578  			}
   579  
   580  			if test.assertFunc != nil {
   581  				test.assertFunc(t, g)
   582  			}
   583  		})
   584  	}
   585  }
   586  
   587  func TestGRPCServer_Version(t *testing.T) {
   588  	type testCase struct {
   589  		db           Database
   590  		expectedResp string
   591  		expectErr    bool
   592  		expectCode   codes.Code
   593  	}
   594  
   595  	tests := map[string]testCase{
   596  		"backend that does not implement version": {
   597  			db:           fakeDatabase{},
   598  			expectedResp: "",
   599  			expectErr:    false,
   600  			expectCode:   codes.OK,
   601  		},
   602  		"backend with version": {
   603  			db: fakeDatabaseWithVersion{
   604  				version: "v123",
   605  			},
   606  			expectedResp: "v123",
   607  			expectErr:    false,
   608  			expectCode:   codes.OK,
   609  		},
   610  	}
   611  
   612  	for name, test := range tests {
   613  		t.Run(name, func(t *testing.T) {
   614  			idCtx, g := testGrpcServer(t, test.db)
   615  			resp, err := g.Version(idCtx, &logical.Empty{})
   616  
   617  			if test.expectErr && err == nil {
   618  				t.Fatalf("err expected, got nil")
   619  			}
   620  			if !test.expectErr && err != nil {
   621  				t.Fatalf("no error expected, got: %s", err)
   622  			}
   623  
   624  			actualCode := status.Code(err)
   625  			if actualCode != test.expectCode {
   626  				t.Fatalf("Actual code: %s Expected code: %s", actualCode, test.expectCode)
   627  			}
   628  
   629  			if !reflect.DeepEqual(resp.PluginVersion, test.expectedResp) {
   630  				t.Fatalf("Actual response: %#v\nExpected response: %#v", resp, test.expectedResp)
   631  			}
   632  		})
   633  	}
   634  }
   635  
   636  // testGrpcServer is a test helper that returns a context with an ID set in its
   637  // metadata and a gRPCServer instance for a multiplexed plugin
   638  func testGrpcServer(t *testing.T, db Database) (context.Context, gRPCServer) {
   639  	t.Helper()
   640  	g := gRPCServer{
   641  		factoryFunc: func() (interface{}, error) {
   642  			return db, nil
   643  		},
   644  		instances: make(map[string]Database),
   645  	}
   646  
   647  	id := "12345"
   648  	idCtx := idCtx(t, id)
   649  	g.instances[id] = db
   650  
   651  	return idCtx, g
   652  }
   653  
   654  // testGrpcServerSingleImpl is a test helper that returns a context and a
   655  // gRPCServer instance for a non-multiplexed plugin
   656  func testGrpcServerSingleImpl(t *testing.T, db Database) (context.Context, gRPCServer) {
   657  	t.Helper()
   658  	return context.Background(), gRPCServer{
   659  		singleImpl: db,
   660  	}
   661  }
   662  
   663  // idCtx is a test helper that will return a context with the IDs set in its
   664  // metadata
   665  func idCtx(t *testing.T, ids ...string) context.Context {
   666  	t.Helper()
   667  	// Context doesn't need to timeout since this is just passed through
   668  	ctx := context.Background()
   669  	md := metadata.MD{}
   670  	for _, id := range ids {
   671  		md.Append(pluginutil.MultiplexingCtxKey, id)
   672  	}
   673  	return metadata.NewIncomingContext(ctx, md)
   674  }
   675  
   676  func marshal(t *testing.T, m map[string]interface{}) *structpb.Struct {
   677  	t.Helper()
   678  
   679  	strct, err := mapToStruct(m)
   680  	if err != nil {
   681  		t.Fatalf("unable to marshal to protobuf: %s", err)
   682  	}
   683  	return strct
   684  }
   685  
   686  type badJSONValue struct{}
   687  
   688  func (badJSONValue) MarshalJSON() ([]byte, error) {
   689  	return nil, fmt.Errorf("this cannot be marshalled to JSON")
   690  }
   691  
   692  func (badJSONValue) UnmarshalJSON([]byte) error {
   693  	return fmt.Errorf("this cannot be unmarshalled from JSON")
   694  }
   695  
   696  var _ Database = fakeDatabase{}
   697  
   698  type fakeDatabase struct {
   699  	initResp InitializeResponse
   700  	initErr  error
   701  
   702  	newUserResp NewUserResponse
   703  	newUserErr  error
   704  
   705  	updateUserResp UpdateUserResponse
   706  	updateUserErr  error
   707  
   708  	deleteUserResp DeleteUserResponse
   709  	deleteUserErr  error
   710  
   711  	typeResp string
   712  	typeErr  error
   713  
   714  	closeErr error
   715  }
   716  
   717  func (e fakeDatabase) Initialize(ctx context.Context, req InitializeRequest) (InitializeResponse, error) {
   718  	return e.initResp, e.initErr
   719  }
   720  
   721  func (e fakeDatabase) NewUser(ctx context.Context, req NewUserRequest) (NewUserResponse, error) {
   722  	return e.newUserResp, e.newUserErr
   723  }
   724  
   725  func (e fakeDatabase) UpdateUser(ctx context.Context, req UpdateUserRequest) (UpdateUserResponse, error) {
   726  	return e.updateUserResp, e.updateUserErr
   727  }
   728  
   729  func (e fakeDatabase) DeleteUser(ctx context.Context, req DeleteUserRequest) (DeleteUserResponse, error) {
   730  	return e.deleteUserResp, e.deleteUserErr
   731  }
   732  
   733  func (e fakeDatabase) Type() (string, error) {
   734  	return e.typeResp, e.typeErr
   735  }
   736  
   737  func (e fakeDatabase) Close() error {
   738  	return e.closeErr
   739  }
   740  
   741  var _ Database = &recordingDatabase{}
   742  
   743  type recordingDatabase struct {
   744  	initializeCalls int
   745  	newUserCalls    int
   746  	updateUserCalls int
   747  	deleteUserCalls int
   748  	typeCalls       int
   749  	closeCalls      int
   750  
   751  	// recordingDatabase can act as middleware so we can record the calls to other test Database implementations
   752  	next Database
   753  }
   754  
   755  func (f *recordingDatabase) Initialize(ctx context.Context, req InitializeRequest) (InitializeResponse, error) {
   756  	f.initializeCalls++
   757  	if f.next == nil {
   758  		return InitializeResponse{}, nil
   759  	}
   760  	return f.next.Initialize(ctx, req)
   761  }
   762  
   763  func (f *recordingDatabase) NewUser(ctx context.Context, req NewUserRequest) (NewUserResponse, error) {
   764  	f.newUserCalls++
   765  	if f.next == nil {
   766  		return NewUserResponse{}, nil
   767  	}
   768  	return f.next.NewUser(ctx, req)
   769  }
   770  
   771  func (f *recordingDatabase) UpdateUser(ctx context.Context, req UpdateUserRequest) (UpdateUserResponse, error) {
   772  	f.updateUserCalls++
   773  	if f.next == nil {
   774  		return UpdateUserResponse{}, nil
   775  	}
   776  	return f.next.UpdateUser(ctx, req)
   777  }
   778  
   779  func (f *recordingDatabase) DeleteUser(ctx context.Context, req DeleteUserRequest) (DeleteUserResponse, error) {
   780  	f.deleteUserCalls++
   781  	if f.next == nil {
   782  		return DeleteUserResponse{}, nil
   783  	}
   784  	return f.next.DeleteUser(ctx, req)
   785  }
   786  
   787  func (f *recordingDatabase) Type() (string, error) {
   788  	f.typeCalls++
   789  	if f.next == nil {
   790  		return "recordingDatabase", nil
   791  	}
   792  	return f.next.Type()
   793  }
   794  
   795  func (f *recordingDatabase) Close() error {
   796  	f.closeCalls++
   797  	if f.next == nil {
   798  		return nil
   799  	}
   800  	return f.next.Close()
   801  }
   802  
   803  type fakeDatabaseWithVersion struct {
   804  	version string
   805  }
   806  
   807  func (e fakeDatabaseWithVersion) PluginVersion() logical.PluginVersion {
   808  	return logical.PluginVersion{Version: e.version}
   809  }
   810  
   811  func (e fakeDatabaseWithVersion) Initialize(_ context.Context, _ InitializeRequest) (InitializeResponse, error) {
   812  	return InitializeResponse{}, nil
   813  }
   814  
   815  func (e fakeDatabaseWithVersion) NewUser(_ context.Context, _ NewUserRequest) (NewUserResponse, error) {
   816  	return NewUserResponse{}, nil
   817  }
   818  
   819  func (e fakeDatabaseWithVersion) UpdateUser(_ context.Context, _ UpdateUserRequest) (UpdateUserResponse, error) {
   820  	return UpdateUserResponse{}, nil
   821  }
   822  
   823  func (e fakeDatabaseWithVersion) DeleteUser(_ context.Context, _ DeleteUserRequest) (DeleteUserResponse, error) {
   824  	return DeleteUserResponse{}, nil
   825  }
   826  
   827  func (e fakeDatabaseWithVersion) Type() (string, error) {
   828  	return "", nil
   829  }
   830  
   831  func (e fakeDatabaseWithVersion) Close() error {
   832  	return nil
   833  }
   834  
   835  var (
   836  	_ Database                = (*fakeDatabaseWithVersion)(nil)
   837  	_ logical.PluginVersioner = (*fakeDatabaseWithVersion)(nil)
   838  )