github.com/true-sqn/fabric@v2.1.1+incompatible/msp/cache/cache_test.go (about)

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