code.vegaprotocol.io/vega@v0.79.0/wallet/api/admin_annotate_key_test.go (about)

     1  // Copyright (C) 2023 Gobalsky Labs Limited
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  package api_test
    17  
    18  import (
    19  	"context"
    20  	"fmt"
    21  	"testing"
    22  
    23  	"code.vegaprotocol.io/vega/libs/jsonrpc"
    24  	vgrand "code.vegaprotocol.io/vega/libs/rand"
    25  	"code.vegaprotocol.io/vega/wallet/api"
    26  	"code.vegaprotocol.io/vega/wallet/api/mocks"
    27  	"code.vegaprotocol.io/vega/wallet/wallet"
    28  
    29  	"github.com/golang/mock/gomock"
    30  	"github.com/stretchr/testify/assert"
    31  	"github.com/stretchr/testify/require"
    32  )
    33  
    34  func TestAdminAnnotateKey(t *testing.T) {
    35  	t.Run("Documentation matches the code", testAdminAnnotateKeySchemaCorrect)
    36  	t.Run("Annotating a key with invalid params fails", testAnnotatingKeyWithInvalidParamsFails)
    37  	t.Run("Annotating a key with valid params succeeds", testAnnotatingKeyWithValidParamsSucceeds)
    38  	t.Run("Annotating a key on unknown wallet fails", testAnnotatingKeyOnUnknownWalletFails)
    39  	t.Run("Annotating a key on unknown key fails", testAnnotatingKeyOnUnknownKeyFails)
    40  	t.Run("Getting internal error during wallet verification doesn't annotate the key", testGettingInternalErrorDuringWalletVerificationDoesNotAnnotateKey)
    41  	t.Run("Getting internal error during wallet retrieval doesn't annotate the key", testGettingInternalErrorDuringWalletRetrievalDoesNotAnnotateKey)
    42  	t.Run("Getting internal error during wallet saving doesn't annotate the key", testGettingInternalErrorDuringWalletSavingDoesNotAnnotateKey)
    43  }
    44  
    45  func testAdminAnnotateKeySchemaCorrect(t *testing.T) {
    46  	assertEqualSchema(t, "admin.annotate_key", api.AdminAnnotateKeyParams{}, api.AdminAnnotateKeyResult{})
    47  }
    48  
    49  func testAnnotatingKeyWithInvalidParamsFails(t *testing.T) {
    50  	tcs := []struct {
    51  		name          string
    52  		params        interface{}
    53  		expectedError error
    54  	}{
    55  		{
    56  			name:          "with nil params",
    57  			params:        nil,
    58  			expectedError: api.ErrParamsRequired,
    59  		}, {
    60  			name:          "with wrong type of params",
    61  			params:        "test",
    62  			expectedError: api.ErrParamsDoNotMatch,
    63  		}, {
    64  			name: "with empty name",
    65  			params: api.AdminAnnotateKeyParams{
    66  				Wallet:    "",
    67  				PublicKey: "b5fd9d3c4ad553cb3196303b6e6df7f484cf7f5331a572a45031239fd71ad8a0",
    68  				Metadata:  []wallet.Metadata{{Key: vgrand.RandomStr(5), Value: vgrand.RandomStr(5)}},
    69  			},
    70  			expectedError: api.ErrWalletIsRequired,
    71  		}, {
    72  			name: "with empty public key",
    73  			params: api.AdminAnnotateKeyParams{
    74  				PublicKey: "",
    75  				Metadata:  []wallet.Metadata{{Key: vgrand.RandomStr(5), Value: vgrand.RandomStr(5)}},
    76  				Wallet:    vgrand.RandomStr(5),
    77  			},
    78  			expectedError: api.ErrPublicKeyIsRequired,
    79  		},
    80  	}
    81  
    82  	for _, tc := range tcs {
    83  		t.Run(tc.name, func(tt *testing.T) {
    84  			// given
    85  			ctx := context.Background()
    86  
    87  			// setup
    88  			handler := newAnnotateKeyHandler(tt)
    89  
    90  			// when
    91  			result, errorDetails := handler.handle(t, ctx, tc.params)
    92  
    93  			// then
    94  			require.Empty(tt, result)
    95  			assertInvalidParams(tt, errorDetails, tc.expectedError)
    96  		})
    97  	}
    98  }
    99  
   100  func testAnnotatingKeyWithValidParamsSucceeds(t *testing.T) {
   101  	// given
   102  	ctx := context.Background()
   103  	expectedWallet, kp := walletWithKey(t)
   104  
   105  	// setup
   106  	handler := newAnnotateKeyHandler(t)
   107  	// -- expected calls
   108  	handler.walletStore.EXPECT().WalletExists(ctx, expectedWallet.Name()).Times(1).Return(true, nil)
   109  	handler.walletStore.EXPECT().IsWalletAlreadyUnlocked(ctx, expectedWallet.Name()).Times(1).Return(true, nil)
   110  	handler.walletStore.EXPECT().GetWallet(ctx, expectedWallet.Name()).Times(1).Return(expectedWallet, nil)
   111  	handler.walletStore.EXPECT().UpdateWallet(ctx, expectedWallet).Times(1).Return(nil)
   112  
   113  	// when
   114  	result, errorDetails := handler.handle(t, ctx, api.AdminAnnotateKeyParams{
   115  		Wallet:    expectedWallet.Name(),
   116  		PublicKey: kp.PublicKey(),
   117  		Metadata:  []wallet.Metadata{{Key: "mode", Value: "test"}},
   118  	})
   119  
   120  	// then
   121  	require.Nil(t, errorDetails)
   122  	expectedMeta := []wallet.Metadata{{Key: "mode", Value: "test"}, {Key: "name", Value: "Key 1"}}
   123  	assert.Equal(t, expectedMeta, result.Metadata)
   124  	assert.Equal(t, expectedMeta, expectedWallet.ListKeyPairs()[0].Metadata())
   125  }
   126  
   127  func testAnnotatingKeyOnUnknownWalletFails(t *testing.T) {
   128  	// given
   129  	ctx := context.Background()
   130  	name := vgrand.RandomStr(5)
   131  
   132  	// setup
   133  	handler := newAnnotateKeyHandler(t)
   134  	// -- expected calls
   135  	handler.walletStore.EXPECT().WalletExists(ctx, name).Times(1).Return(false, nil)
   136  
   137  	// when
   138  	result, errorDetails := handler.handle(t, ctx, api.AdminAnnotateKeyParams{
   139  		Wallet:    name,
   140  		PublicKey: vgrand.RandomStr(5),
   141  		Metadata:  []wallet.Metadata{{Key: "mode", Value: "test"}},
   142  	})
   143  
   144  	// then
   145  	require.NotNil(t, errorDetails)
   146  	assert.Empty(t, result)
   147  	assertInvalidParams(t, errorDetails, api.ErrWalletDoesNotExist)
   148  }
   149  
   150  func testAnnotatingKeyOnUnknownKeyFails(t *testing.T) {
   151  	// given
   152  	ctx := context.Background()
   153  	expectedWallet, _ := walletWithKey(t)
   154  
   155  	// setup
   156  	handler := newAnnotateKeyHandler(t)
   157  	// -- expected calls
   158  	handler.walletStore.EXPECT().WalletExists(ctx, expectedWallet.Name()).Times(1).Return(true, nil)
   159  	handler.walletStore.EXPECT().IsWalletAlreadyUnlocked(ctx, expectedWallet.Name()).Times(1).Return(true, nil)
   160  	handler.walletStore.EXPECT().GetWallet(ctx, expectedWallet.Name()).Times(1).Return(expectedWallet, nil)
   161  
   162  	// when
   163  	result, errorDetails := handler.handle(t, ctx, api.AdminAnnotateKeyParams{
   164  		Wallet:    expectedWallet.Name(),
   165  		PublicKey: vgrand.RandomStr(5),
   166  		Metadata:  []wallet.Metadata{{Key: "mode", Value: "test"}},
   167  	})
   168  
   169  	// then
   170  	require.NotNil(t, errorDetails)
   171  	assert.Empty(t, result)
   172  	assertInvalidParams(t, errorDetails, api.ErrPublicKeyDoesNotExist)
   173  }
   174  
   175  func testGettingInternalErrorDuringWalletVerificationDoesNotAnnotateKey(t *testing.T) {
   176  	// given
   177  	ctx := context.Background()
   178  	expectedWallet, kp := walletWithKey(t)
   179  
   180  	// setup
   181  	handler := newAnnotateKeyHandler(t)
   182  	// -- expected calls
   183  	handler.walletStore.EXPECT().WalletExists(ctx, expectedWallet.Name()).Times(1).Return(false, assert.AnError)
   184  
   185  	// when
   186  	result, errorDetails := handler.handle(t, ctx, api.AdminAnnotateKeyParams{
   187  		Wallet:    expectedWallet.Name(),
   188  		PublicKey: kp.PublicKey(),
   189  		Metadata:  []wallet.Metadata{{Key: "mode", Value: "test"}},
   190  	})
   191  
   192  	// then
   193  	require.NotNil(t, errorDetails)
   194  	assert.Empty(t, result)
   195  	assertInternalError(t, errorDetails, fmt.Errorf("could not verify the wallet exists: %w", assert.AnError))
   196  }
   197  
   198  func testGettingInternalErrorDuringWalletRetrievalDoesNotAnnotateKey(t *testing.T) {
   199  	// given
   200  	ctx := context.Background()
   201  	expectedWallet, kp := walletWithKey(t)
   202  
   203  	// setup
   204  	handler := newAnnotateKeyHandler(t)
   205  	// -- expected calls
   206  	handler.walletStore.EXPECT().WalletExists(ctx, expectedWallet.Name()).Times(1).Return(true, nil)
   207  	handler.walletStore.EXPECT().IsWalletAlreadyUnlocked(ctx, expectedWallet.Name()).Times(1).Return(true, nil)
   208  	handler.walletStore.EXPECT().GetWallet(ctx, expectedWallet.Name()).Times(1).Return(nil, assert.AnError)
   209  
   210  	// when
   211  	result, errorDetails := handler.handle(t, ctx, api.AdminAnnotateKeyParams{
   212  		Wallet:    expectedWallet.Name(),
   213  		PublicKey: kp.PublicKey(),
   214  		Metadata:  []wallet.Metadata{{Key: "mode", Value: "test"}},
   215  	})
   216  
   217  	// then
   218  	require.NotNil(t, errorDetails)
   219  	assert.Empty(t, result)
   220  	assertInternalError(t, errorDetails, fmt.Errorf("could not retrieve the wallet: %w", assert.AnError))
   221  }
   222  
   223  func testGettingInternalErrorDuringWalletSavingDoesNotAnnotateKey(t *testing.T) {
   224  	// given
   225  	ctx := context.Background()
   226  	expectedWallet, kp := walletWithKey(t)
   227  
   228  	// setup
   229  	handler := newAnnotateKeyHandler(t)
   230  	// -- expected calls
   231  	handler.walletStore.EXPECT().WalletExists(ctx, expectedWallet.Name()).Times(1).Return(true, nil)
   232  	handler.walletStore.EXPECT().IsWalletAlreadyUnlocked(ctx, expectedWallet.Name()).Times(1).Return(true, nil)
   233  	handler.walletStore.EXPECT().GetWallet(ctx, expectedWallet.Name()).Times(1).Return(expectedWallet, nil)
   234  	handler.walletStore.EXPECT().UpdateWallet(ctx, gomock.Any()).Times(1).Return(assert.AnError)
   235  
   236  	// when
   237  	result, errorDetails := handler.handle(t, ctx, api.AdminAnnotateKeyParams{
   238  		Wallet:    expectedWallet.Name(),
   239  		PublicKey: kp.PublicKey(),
   240  		Metadata:  []wallet.Metadata{{Key: "mode", Value: "test"}},
   241  	})
   242  
   243  	// then
   244  	require.NotNil(t, errorDetails)
   245  	assert.Empty(t, result)
   246  	assertInternalError(t, errorDetails, fmt.Errorf("could not save the wallet: %w", assert.AnError))
   247  }
   248  
   249  type annotateKeyHandler struct {
   250  	*api.AdminAnnotateKey
   251  	ctrl        *gomock.Controller
   252  	walletStore *mocks.MockWalletStore
   253  }
   254  
   255  func (h *annotateKeyHandler) handle(t *testing.T, ctx context.Context, params jsonrpc.Params) (api.AdminAnnotateKeyResult, *jsonrpc.ErrorDetails) {
   256  	t.Helper()
   257  
   258  	rawResult, err := h.Handle(ctx, params)
   259  	if rawResult != nil {
   260  		result, ok := rawResult.(api.AdminAnnotateKeyResult)
   261  		if !ok {
   262  			t.Fatal("AdminAnnotateKey handler result is not a AdminAnnotateKeyResult")
   263  		}
   264  		return result, err
   265  	}
   266  	return api.AdminAnnotateKeyResult{}, err
   267  }
   268  
   269  func newAnnotateKeyHandler(t *testing.T) *annotateKeyHandler {
   270  	t.Helper()
   271  
   272  	ctrl := gomock.NewController(t)
   273  	walletStore := mocks.NewMockWalletStore(ctrl)
   274  
   275  	return &annotateKeyHandler{
   276  		AdminAnnotateKey: api.NewAdminAnnotateKey(walletStore),
   277  		ctrl:             ctrl,
   278  		walletStore:      walletStore,
   279  	}
   280  }