github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/msp/cache/cache_test.go (about)

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package cache
     8  
     9  import (
    10  	"sync"
    11  	"testing"
    12  
    13  	"github.com/hechain20/hechain/msp"
    14  	"github.com/hechain20/hechain/msp/mocks"
    15  	msp2 "github.com/hyperledger/fabric-protos-go/msp"
    16  	"github.com/pkg/errors"
    17  	"github.com/stretchr/testify/mock"
    18  	"github.com/stretchr/testify/require"
    19  )
    20  
    21  func TestNewCacheMsp(t *testing.T) {
    22  	i, err := New(nil)
    23  	require.Error(t, err)
    24  	require.Nil(t, i)
    25  	require.Contains(t, err.Error(), "Invalid passed MSP. It must be different from nil.")
    26  
    27  	i, err = New(&mocks.MockMSP{})
    28  	require.NoError(t, err)
    29  	require.NotNil(t, i)
    30  }
    31  
    32  func TestSetup(t *testing.T) {
    33  	mockMSP := &mocks.MockMSP{}
    34  	i, err := New(mockMSP)
    35  	require.NoError(t, err)
    36  
    37  	mockMSP.On("Setup", (*msp2.MSPConfig)(nil)).Return(nil)
    38  	err = i.Setup(nil)
    39  	require.NoError(t, err)
    40  	mockMSP.AssertExpectations(t)
    41  	require.Equal(t, 0, i.(*cachedMSP).deserializeIdentityCache.len())
    42  	require.Equal(t, 0, i.(*cachedMSP).satisfiesPrincipalCache.len())
    43  	require.Equal(t, 0, i.(*cachedMSP).validateIdentityCache.len())
    44  }
    45  
    46  func TestGetType(t *testing.T) {
    47  	mockMSP := &mocks.MockMSP{}
    48  	i, err := New(mockMSP)
    49  	require.NoError(t, err)
    50  
    51  	mockMSP.On("GetType").Return(msp.FABRIC)
    52  	require.Equal(t, msp.FABRIC, i.GetType())
    53  	mockMSP.AssertExpectations(t)
    54  }
    55  
    56  func TestGetIdentifier(t *testing.T) {
    57  	mockMSP := &mocks.MockMSP{}
    58  	i, err := New(mockMSP)
    59  	require.NoError(t, err)
    60  
    61  	mockMSP.On("GetIdentifier").Return("MSP", nil)
    62  	id, err := i.GetIdentifier()
    63  	require.NoError(t, err)
    64  	require.Equal(t, "MSP", id)
    65  	mockMSP.AssertExpectations(t)
    66  }
    67  
    68  func TestGetDefaultSigningIdentity(t *testing.T) {
    69  	mockMSP := &mocks.MockMSP{}
    70  	i, err := New(mockMSP)
    71  	require.NoError(t, err)
    72  
    73  	mockIdentity := &mocks.MockSigningIdentity{Mock: mock.Mock{}, MockIdentity: &mocks.MockIdentity{ID: "Alice"}}
    74  	mockMSP.On("GetDefaultSigningIdentity").Return(mockIdentity, nil)
    75  	id, err := i.GetDefaultSigningIdentity()
    76  	require.NoError(t, err)
    77  	require.Equal(t, mockIdentity, id)
    78  	mockMSP.AssertExpectations(t)
    79  }
    80  
    81  func TestGetTLSRootCerts(t *testing.T) {
    82  	mockMSP := &mocks.MockMSP{}
    83  	i, err := New(mockMSP)
    84  	require.NoError(t, err)
    85  
    86  	expected := [][]byte{{1}, {2}}
    87  	mockMSP.On("GetTLSRootCerts").Return(expected)
    88  	certs := i.GetTLSRootCerts()
    89  	require.Equal(t, expected, certs)
    90  }
    91  
    92  func TestGetTLSIntermediateCerts(t *testing.T) {
    93  	mockMSP := &mocks.MockMSP{}
    94  	i, err := New(mockMSP)
    95  	require.NoError(t, err)
    96  
    97  	expected := [][]byte{{1}, {2}}
    98  	mockMSP.On("GetTLSIntermediateCerts").Return(expected)
    99  	certs := i.GetTLSIntermediateCerts()
   100  	require.Equal(t, expected, certs)
   101  }
   102  
   103  func TestDeserializeIdentity(t *testing.T) {
   104  	mockMSP := &mocks.MockMSP{}
   105  	wrappedMSP, err := New(mockMSP)
   106  	require.NoError(t, err)
   107  
   108  	// Check id is cached
   109  	mockIdentity := &mocks.MockIdentity{ID: "Alice"}
   110  	mockIdentity2 := &mocks.MockIdentity{ID: "Bob"}
   111  	serializedIdentity := []byte{1, 2, 3}
   112  	serializedIdentity2 := []byte{4, 5, 6}
   113  	mockMSP.On("DeserializeIdentity", serializedIdentity).Return(mockIdentity, nil)
   114  	mockMSP.On("DeserializeIdentity", serializedIdentity2).Return(mockIdentity2, nil)
   115  	// Prime the cache
   116  	wrappedMSP.DeserializeIdentity(serializedIdentity)
   117  	wrappedMSP.DeserializeIdentity(serializedIdentity2)
   118  
   119  	// Stress the cache and ensure concurrent operations
   120  	// do not result in a failure
   121  	var wg sync.WaitGroup
   122  	wg.Add(100)
   123  	for i := 0; i < 100; i++ {
   124  		go func(m msp.MSP, i int) {
   125  			sIdentity := serializedIdentity
   126  			expectedIdentity := mockIdentity
   127  			defer wg.Done()
   128  			if i%2 == 0 {
   129  				sIdentity = serializedIdentity2
   130  				expectedIdentity = mockIdentity2
   131  			}
   132  			id, err := wrappedMSP.DeserializeIdentity(sIdentity)
   133  			require.NoError(t, err)
   134  			require.Equal(t, expectedIdentity, id.(*cachedIdentity).Identity)
   135  		}(wrappedMSP, i)
   136  	}
   137  	wg.Wait()
   138  
   139  	mockMSP.AssertExpectations(t)
   140  	// Check the cache
   141  	_, ok := wrappedMSP.(*cachedMSP).deserializeIdentityCache.get(string(serializedIdentity))
   142  	require.True(t, ok)
   143  
   144  	// Check the same object is returned
   145  	id, err := wrappedMSP.DeserializeIdentity(serializedIdentity)
   146  	require.NoError(t, err)
   147  	require.True(t, mockIdentity == id.(*cachedIdentity).Identity)
   148  	mockMSP.AssertExpectations(t)
   149  
   150  	// Check id is not cached
   151  	mockIdentity = &mocks.MockIdentity{ID: "Bob"}
   152  	serializedIdentity = []byte{1, 2, 3, 4}
   153  	mockMSP.On("DeserializeIdentity", serializedIdentity).Return(mockIdentity, errors.New("Invalid identity"))
   154  	_, err = wrappedMSP.DeserializeIdentity(serializedIdentity)
   155  	require.Error(t, err)
   156  	require.Contains(t, err.Error(), "Invalid identity")
   157  	mockMSP.AssertExpectations(t)
   158  
   159  	_, ok = wrappedMSP.(*cachedMSP).deserializeIdentityCache.get(string(serializedIdentity))
   160  	require.False(t, ok)
   161  }
   162  
   163  func TestValidate(t *testing.T) {
   164  	mockMSP := &mocks.MockMSP{}
   165  	i, err := New(mockMSP)
   166  	require.NoError(t, err)
   167  
   168  	// Check validation is cached
   169  	mockIdentity := &mocks.MockIdentity{ID: "Alice"}
   170  	mockIdentity.On("GetIdentifier").Return(&msp.IdentityIdentifier{Mspid: "MSP", Id: "Alice"})
   171  	mockMSP.On("Validate", mockIdentity).Return(nil)
   172  	err = i.Validate(mockIdentity)
   173  	require.NoError(t, err)
   174  	mockIdentity.AssertExpectations(t)
   175  	mockMSP.AssertExpectations(t)
   176  	// Check the cache
   177  	identifier := mockIdentity.GetIdentifier()
   178  	key := string(identifier.Mspid + ":" + identifier.Id)
   179  	v, ok := i.(*cachedMSP).validateIdentityCache.get(string(key))
   180  	require.True(t, ok)
   181  	require.True(t, v.(bool))
   182  
   183  	// Recheck
   184  	err = i.Validate(mockIdentity)
   185  	require.NoError(t, err)
   186  
   187  	// Check validation is not cached
   188  	mockIdentity = &mocks.MockIdentity{ID: "Bob"}
   189  	mockIdentity.On("GetIdentifier").Return(&msp.IdentityIdentifier{Mspid: "MSP", Id: "Bob"})
   190  	mockMSP.On("Validate", mockIdentity).Return(errors.New("Invalid identity"))
   191  	err = i.Validate(mockIdentity)
   192  	require.Error(t, err)
   193  	mockIdentity.AssertExpectations(t)
   194  	mockMSP.AssertExpectations(t)
   195  	// Check the cache
   196  	identifier = mockIdentity.GetIdentifier()
   197  	key = string(identifier.Mspid + ":" + identifier.Id)
   198  	_, ok = i.(*cachedMSP).validateIdentityCache.get(string(key))
   199  	require.False(t, ok)
   200  }
   201  
   202  func TestSatisfiesValidateIndirectCall(t *testing.T) {
   203  	mockMSP := &mocks.MockMSP{}
   204  
   205  	mockIdentity := &mocks.MockIdentity{ID: "Alice"}
   206  	mockIdentity.On("Validate").Run(func(_ mock.Arguments) {
   207  		panic("shouldn't have invoked the identity method")
   208  	})
   209  	mockMSP.On("DeserializeIdentity", mock.Anything).Return(mockIdentity, nil).Once()
   210  	mockIdentity.On("GetIdentifier").Return(&msp.IdentityIdentifier{Mspid: "MSP", Id: "Alice"})
   211  
   212  	cache, err := New(mockMSP)
   213  	require.NoError(t, err)
   214  
   215  	mockMSP.On("Validate", mockIdentity).Return(nil)
   216  
   217  	// Test that cache returns the correct value, and also use this to prime the cache
   218  	err = cache.Validate(mockIdentity)
   219  	mockMSP.AssertNumberOfCalls(t, "Validate", 1)
   220  	require.NoError(t, err)
   221  	// Get the identity we test the caching on
   222  	identity, err := cache.DeserializeIdentity([]byte{1, 2, 3})
   223  	require.NoError(t, err)
   224  	// Ensure the identity returned answers what the cached MSP answers.
   225  	err = identity.Validate()
   226  	require.NoError(t, err)
   227  	// Ensure that although a call to Validate was called, the calls weren't passed on to the backing MSP
   228  	mockMSP.AssertNumberOfCalls(t, "Validate", 1)
   229  }
   230  
   231  func TestSatisfiesPrincipalIndirectCall(t *testing.T) {
   232  	mockMSP := &mocks.MockMSP{}
   233  	mockMSPPrincipal := &msp2.MSPPrincipal{PrincipalClassification: msp2.MSPPrincipal_IDENTITY, Principal: []byte{1, 2, 3}}
   234  
   235  	mockIdentity := &mocks.MockIdentity{ID: "Alice"}
   236  	mockIdentity.On("SatisfiesPrincipal", mockMSPPrincipal).Run(func(_ mock.Arguments) {
   237  		panic("shouldn't have invoked the identity method")
   238  	})
   239  	mockMSP.On("DeserializeIdentity", mock.Anything).Return(mockIdentity, nil).Once()
   240  	mockIdentity.On("GetIdentifier").Return(&msp.IdentityIdentifier{Mspid: "MSP", Id: "Alice"})
   241  
   242  	cache, err := New(mockMSP)
   243  	require.NoError(t, err)
   244  
   245  	// First invocation of the SatisfiesPrincipal returns an error
   246  	mockMSP.On("SatisfiesPrincipal", mockIdentity, mockMSPPrincipal).Return(errors.New("error: foo")).Once()
   247  	// Second invocation returns nil
   248  	mockMSP.On("SatisfiesPrincipal", mockIdentity, mockMSPPrincipal).Return(nil).Once()
   249  
   250  	// Test that cache returns the correct value
   251  	err = cache.SatisfiesPrincipal(mockIdentity, mockMSPPrincipal)
   252  	require.Equal(t, "error: foo", err.Error())
   253  	// Get the identity we test the caching on
   254  	identity, err := cache.DeserializeIdentity([]byte{1, 2, 3})
   255  	require.NoError(t, err)
   256  	// Ensure the identity returned answers what the cached MSP answers.
   257  	// If the invocation doesn't hit the cache, it will return nil instead of an error.
   258  	err = identity.SatisfiesPrincipal(mockMSPPrincipal)
   259  	require.Equal(t, "error: foo", err.Error())
   260  }
   261  
   262  func TestSatisfiesPrincipal(t *testing.T) {
   263  	mockMSP := &mocks.MockMSP{}
   264  	i, err := New(mockMSP)
   265  	require.NoError(t, err)
   266  
   267  	// Check validation is cached
   268  	mockIdentity := &mocks.MockIdentity{ID: "Alice"}
   269  	mockIdentity.On("GetIdentifier").Return(&msp.IdentityIdentifier{Mspid: "MSP", Id: "Alice"})
   270  	mockMSPPrincipal := &msp2.MSPPrincipal{PrincipalClassification: msp2.MSPPrincipal_IDENTITY, Principal: []byte{1, 2, 3}}
   271  	mockMSP.On("SatisfiesPrincipal", mockIdentity, mockMSPPrincipal).Return(nil)
   272  	mockMSP.SatisfiesPrincipal(mockIdentity, mockMSPPrincipal)
   273  	err = i.SatisfiesPrincipal(mockIdentity, mockMSPPrincipal)
   274  	require.NoError(t, err)
   275  	mockIdentity.AssertExpectations(t)
   276  	mockMSP.AssertExpectations(t)
   277  	// Check the cache
   278  	identifier := mockIdentity.GetIdentifier()
   279  	identityKey := string(identifier.Mspid + ":" + identifier.Id)
   280  	principalKey := string(mockMSPPrincipal.PrincipalClassification) + string(mockMSPPrincipal.Principal)
   281  	key := identityKey + principalKey
   282  	v, ok := i.(*cachedMSP).satisfiesPrincipalCache.get(key)
   283  	require.True(t, ok)
   284  	require.Nil(t, v)
   285  
   286  	// Recheck
   287  	err = i.SatisfiesPrincipal(mockIdentity, mockMSPPrincipal)
   288  	require.NoError(t, err)
   289  
   290  	// Check validation is not cached
   291  	mockIdentity = &mocks.MockIdentity{ID: "Bob"}
   292  	mockIdentity.On("GetIdentifier").Return(&msp.IdentityIdentifier{Mspid: "MSP", Id: "Bob"})
   293  	mockMSPPrincipal = &msp2.MSPPrincipal{PrincipalClassification: msp2.MSPPrincipal_IDENTITY, Principal: []byte{1, 2, 3, 4}}
   294  	mockMSP.On("SatisfiesPrincipal", mockIdentity, mockMSPPrincipal).Return(errors.New("Invalid"))
   295  	mockMSP.SatisfiesPrincipal(mockIdentity, mockMSPPrincipal)
   296  	err = i.SatisfiesPrincipal(mockIdentity, mockMSPPrincipal)
   297  	require.Error(t, err)
   298  	mockIdentity.AssertExpectations(t)
   299  	mockMSP.AssertExpectations(t)
   300  	// Check the cache
   301  	identifier = mockIdentity.GetIdentifier()
   302  	identityKey = string(identifier.Mspid + ":" + identifier.Id)
   303  	principalKey = string(mockMSPPrincipal.PrincipalClassification) + string(mockMSPPrincipal.Principal)
   304  	key = identityKey + principalKey
   305  	v, ok = i.(*cachedMSP).satisfiesPrincipalCache.get(key)
   306  	require.True(t, ok)
   307  	require.NotNil(t, v)
   308  	require.Contains(t, "Invalid", v.(error).Error())
   309  }