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 }