github.com/kaituanwang/hyperledger@v2.0.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 }