github.com/zcqzcg/fabric-ca@v2.0.0-alpha.0.20200416163940-d878ee6db75a+incompatible/lib/server/idemix/nonce_test.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package idemix_test 8 9 import ( 10 "database/sql" 11 "testing" 12 "time" 13 14 . "github.com/hyperledger/fabric-ca/lib/server/idemix" 15 "github.com/hyperledger/fabric-ca/lib/server/idemix/mocks" 16 dmocks "github.com/hyperledger/fabric-ca/lib/server/idemix/mocks" 17 "github.com/hyperledger/fabric-ca/util" 18 "github.com/hyperledger/fabric/idemix" 19 "github.com/pkg/errors" 20 "github.com/stretchr/testify/assert" 21 ) 22 23 func TestNewNonceManager(t *testing.T) { 24 issuer := new(mocks.MyIssuer) 25 issuer.On("Name").Return("ca1") 26 opts := &Config{ 27 NonceExpiration: "15", 28 NonceSweepInterval: "15", 29 } 30 clock := new(mocks.Clock) 31 lib := new(mocks.Lib) 32 issuer.On("Config").Return(opts) 33 issuer.On("IdemixLib").Return(lib) 34 _, err := NewNonceManager(issuer, clock, 1) 35 assert.Error(t, err, "NewNonceManager should return error if the NonceExpiration config option is not in time.Duration string format") 36 assert.Contains(t, err.Error(), "Failed to parse idemix.nonceexpiration config option while initializing Nonce manager for Issuer 'ca1'") 37 38 opts.NonceExpiration = "15s" 39 _, err = NewNonceManager(issuer, clock, 1) 40 assert.Error(t, err, "NewNonceManager should return error if the NonceSweepInterval config option is not in time.Duration string format") 41 assert.Contains(t, err.Error(), "Failed to parse idemix.noncesweepinterval config option while initializing Nonce manager for Issuer 'ca1'") 42 43 opts.NonceSweepInterval = "15m" 44 _, err = NewNonceManager(issuer, clock, 1) 45 assert.NoError(t, err) 46 } 47 48 func TestGetNonce(t *testing.T) { 49 issuer := new(mocks.MyIssuer) 50 issuer.On("Name").Return("ca1") 51 52 lib := new(mocks.Lib) 53 rnd, err := idemix.GetRand() 54 if err != nil { 55 t.Fatalf("Error generating a random number") 56 } 57 rmo := idemix.RandModOrder(rnd) 58 lib.On("RandModOrder", rnd).Return(rmo, nil) 59 60 issuer.On("IdemixRand").Return(rnd) 61 62 noncestr := util.B64Encode(idemix.BigToBytes(rmo)) 63 now := time.Now() 64 nonceObj := &Nonce{ 65 Val: noncestr, 66 Expiry: now.UTC().Add(time.Second * 15), 67 Level: 1, 68 } 69 70 numResultForRowsAffectedCalls := 0 71 f1 := getResultForRowsAffectedFunc(&numResultForRowsAffectedCalls) 72 result := new(dmocks.Result) 73 result.On("RowsAffected").Return(f1, nil) 74 75 db := new(dmocks.FabricCADB) 76 numResultForInsertNonceCalls := 0 77 numErrorForInsertNonceCalls := 0 78 f2 := getResultForInsertNonceFunc(result, &numResultForInsertNonceCalls) 79 f3 := getErrorForInsertNonceFunc(result, &numErrorForInsertNonceCalls) 80 db.On("NamedExec", "InsertNonce", InsertNonce, nonceObj).Return(f2, f3) 81 issuer.On("DB").Return(db) 82 83 opts := &Config{ 84 NonceExpiration: "15s", 85 NonceSweepInterval: "15m", 86 } 87 clock := new(mocks.Clock) 88 clock.On("Now").Return(now) 89 issuer.On("Config").Return(opts) 90 issuer.On("IdemixLib").Return(lib) 91 nm, err := NewNonceManager(issuer, clock, 1) 92 93 _, err = nm.GetNonce() 94 assert.Error(t, err, "Executing insert SQL should return an error") 95 if err != nil { 96 assert.Contains(t, err.Error(), "Failed to add nonce to the datastore") 97 } 98 99 _, err = nm.GetNonce() 100 assert.Error(t, err, "Get rows affected from result should return an error") 101 if err != nil { 102 assert.Contains(t, err.Error(), "Failed to add nonce to the datastore; no rows affected") 103 } 104 105 _, err = nm.GetNonce() 106 assert.Error(t, err, "Get rows affected from result should return an error") 107 if err != nil { 108 assert.Contains(t, err.Error(), "Expected to affect 1 entry in revocation component info table but affected") 109 } 110 111 _, err = nm.GetNonce() 112 assert.NoError(t, err) 113 } 114 115 func TestCheckNonce(t *testing.T) { 116 issuer := new(mocks.MyIssuer) 117 issuer.On("Name").Return("ca1") 118 119 lib := new(mocks.Lib) 120 rnd, err := idemix.GetRand() 121 if err != nil { 122 t.Fatalf("Error generating a random number") 123 } 124 rmo := idemix.RandModOrder(rnd) 125 lib.On("RandModOrder", rnd).Return(rmo) 126 127 issuer.On("IdemixRand").Return(rnd) 128 issuer.On("GetIdemixLib").Return(lib) 129 noncestr := util.B64Encode(idemix.BigToBytes(rmo)) 130 131 db := new(dmocks.FabricCADB) 132 tx := new(dmocks.FabricCATx) 133 tx.On("Commit", "CheckNonce").Return(nil) 134 tx.On("Rollback", "CheckNonce").Return(nil) 135 nonces := []Nonce{} 136 tx.On("Rebind", SelectNonce).Return(SelectNonce) 137 db.On("BeginTx").Return(tx) 138 numTxSelectCalls := 0 139 f := getTxSelectNonceFunc(&nonces, noncestr, &numTxSelectCalls) 140 tx.On("Select", "GetNonce", &nonces, SelectNonce, noncestr).Return(f) 141 numTxRemoveResultCalls := 0 142 numTxRemoveErrorCalls := 0 143 tx.On("Rebind", RemoveNonce).Return(RemoveNonce) 144 f1 := getTxRemoveNonceResultFunc(noncestr, &numTxRemoveResultCalls) 145 f2 := getTxRemoveNonceErrorFunc(&numTxRemoveErrorCalls) 146 tx.On("Exec", "GetNonce", RemoveNonce, noncestr).Return(f1, f2) 147 issuer.On("DB").Return(db) 148 149 opts := &Config{ 150 NonceExpiration: "15s", 151 NonceSweepInterval: "15m", 152 } 153 issuer.On("Config").Return(opts) 154 now := time.Now() 155 clock := new(mocks.Clock) 156 clock.On("Now").Return(now) 157 nm, err := NewNonceManager(issuer, clock, 1) 158 if err != nil { 159 t.Fatalf("Failed to get new instance of Nonce Manager") 160 } 161 err = nm.CheckNonce(rmo) 162 assert.Error(t, err) 163 assert.Contains(t, err.Error(), "Failed to retrieve nonce from the datastore") 164 165 err = nm.CheckNonce(rmo) 166 assert.Error(t, err) 167 assert.Contains(t, err.Error(), "Nonce not found in the datastore") 168 169 err = nm.CheckNonce(rmo) 170 assert.Error(t, err) 171 assert.Contains(t, err.Error(), "Nonce is either unknown or has expired") 172 173 err = nm.CheckNonce(rmo) 174 assert.NoError(t, err) 175 176 err = nm.CheckNonce(rmo) 177 assert.NoError(t, err) 178 } 179 180 func TestSweepExpiredNonces(t *testing.T) { 181 issuer := new(mocks.MyIssuer) 182 issuer.On("Name").Return("ca1") 183 now := time.Now() 184 185 numRemoveExpiredNoncesErrorFuncCalls := 0 186 f := getRemoveExpiredNoncesErrorFunc(&numRemoveExpiredNoncesErrorFuncCalls) 187 db := new(dmocks.FabricCADB) 188 db.On("Rebind", RemoveExpiredNonces).Return(RemoveExpiredNonces) 189 db.On("Exec", "RemoveExpiredNonces", RemoveExpiredNonces, now.UTC()).Return(nil, f) // errors.New("error")) 190 issuer.On("DB").Return(db) 191 192 lib := new(mocks.Lib) 193 opts := &Config{ 194 NonceExpiration: "15s", 195 NonceSweepInterval: "15m", 196 } 197 issuer.On("Config").Return(opts) 198 issuer.On("IdemixLib").Return(lib) 199 clock := new(mocks.Clock) 200 clock.On("Now").Return(now) 201 nm, err := NewNonceManager(issuer, clock, 1) 202 if err != nil { 203 t.Fatalf("Failed to get new instance of Nonce Manager") 204 } 205 err = nm.SweepExpiredNonces() 206 assert.Error(t, err) 207 if err != nil { 208 assert.Contains(t, err.Error(), "Failed to remove expired nonces from DB") 209 } 210 211 err = nm.SweepExpiredNonces() 212 assert.NoError(t, err) 213 } 214 215 func getResultForInsertNonceFunc(result sql.Result, numResultForInsertNonceCalls *int) func(string, string, interface{}) sql.Result { 216 return func(funcName string, query string, args interface{}) sql.Result { 217 if *numResultForInsertNonceCalls == 0 { 218 *numResultForInsertNonceCalls = *numResultForInsertNonceCalls + 1 219 return nil 220 } 221 return result 222 223 } 224 } 225 func getErrorForInsertNonceFunc(result sql.Result, numErrorForInsertNonceCalls *int) func(string, string, interface{}) error { 226 return func(funcName string, query string, args interface{}) error { 227 if *numErrorForInsertNonceCalls == 0 { 228 *numErrorForInsertNonceCalls = *numErrorForInsertNonceCalls + 1 229 return errors.New("Error executing insert") 230 } 231 return nil 232 } 233 } 234 func getResultForRowsAffectedFunc(numResultForRowsAffectedCalls *int) func() int64 { 235 return func() int64 { 236 if *numResultForRowsAffectedCalls == 0 { 237 *numResultForRowsAffectedCalls = *numResultForRowsAffectedCalls + 1 238 return int64(0) 239 } 240 if *numResultForRowsAffectedCalls == 1 { 241 *numResultForRowsAffectedCalls = *numResultForRowsAffectedCalls + 1 242 return int64(2) 243 } 244 return int64(1) 245 } 246 } 247 248 func getTxSelectNonceFunc(nonces *[]Nonce, noncestr string, numTxSelectCalls *int) func(string, interface{}, string, ...interface{}) error { 249 return func(funcName string, dest interface{}, query string, args ...interface{}) error { 250 if *numTxSelectCalls == 0 { 251 *numTxSelectCalls = *numTxSelectCalls + 1 252 return errors.New("Getting a nonce from DB failed") 253 } 254 if *numTxSelectCalls == 1 { 255 *numTxSelectCalls = *numTxSelectCalls + 1 256 return nil 257 } 258 259 destNonces, _ := dest.(*[]Nonce) 260 if *numTxSelectCalls == 2 { 261 *destNonces = append(*destNonces, Nonce{ 262 Val: noncestr, 263 Expiry: time.Now().Add(-1 * time.Minute), 264 }) 265 } 266 *destNonces = append(*destNonces, Nonce{ 267 Val: noncestr, 268 Expiry: time.Now().Add(time.Minute), 269 }) 270 *numTxSelectCalls = *numTxSelectCalls + 1 271 return nil 272 } 273 } 274 275 func getTxRemoveNonceResultFunc(noncestr string, numTxRemoveResultCalls *int) func(string, string, ...interface{}) sql.Result { 276 return func(funcName, query string, args ...interface{}) sql.Result { 277 if *numTxRemoveResultCalls == 0 { 278 *numTxRemoveResultCalls = *numTxRemoveResultCalls + 1 279 return nil 280 } 281 result := new(dmocks.Result) 282 if *numTxRemoveResultCalls == 1 { 283 result.On("RowsAffected").Return(int64(2), nil) 284 *numTxRemoveResultCalls = *numTxRemoveResultCalls + 1 285 return result 286 } 287 result.On("RowsAffected").Return(int64(1), nil) 288 return result 289 } 290 } 291 292 func getTxRemoveNonceErrorFunc(numTxRemoveErrorCalls *int) func(string, string, ...interface{}) error { 293 return func(funcName, query string, args ...interface{}) error { 294 if *numTxRemoveErrorCalls == 0 { 295 *numTxRemoveErrorCalls = *numTxRemoveErrorCalls + 1 296 return errors.New("Removing nonce from DB failed") 297 } 298 return nil 299 } 300 } 301 302 func getRemoveExpiredNoncesErrorFunc(numRemoveExpiredNoncesErrorFuncCalls *int) func(string, string, ...interface{}) error { 303 return func(string, string, ...interface{}) error { 304 if *numRemoveExpiredNoncesErrorFuncCalls == 0 { 305 *numRemoveExpiredNoncesErrorFuncCalls = *numRemoveExpiredNoncesErrorFuncCalls + 1 306 return errors.New("Failed to remove expired nonces from DB") 307 } 308 return nil 309 } 310 }