github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/common/configtx/manager_test.go (about) 1 /* 2 Copyright IBM Corp. 2016 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package configtx 18 19 import ( 20 "fmt" 21 "testing" 22 23 "github.com/hyperledger/fabric/common/configtx/api" 24 mockconfigtx "github.com/hyperledger/fabric/common/mocks/configtx" 25 mockpolicies "github.com/hyperledger/fabric/common/mocks/policies" 26 "github.com/hyperledger/fabric/common/policies" 27 cb "github.com/hyperledger/fabric/protos/common" 28 "github.com/hyperledger/fabric/protos/utils" 29 30 "github.com/stretchr/testify/assert" 31 ) 32 33 var defaultChain = "DefaultChainID" 34 35 func defaultInitializer() *mockconfigtx.Initializer { 36 return &mockconfigtx.Initializer{ 37 Resources: mockconfigtx.Resources{ 38 PolicyManagerVal: &mockpolicies.Manager{ 39 Policy: &mockpolicies.Policy{}, 40 }, 41 }, 42 PolicyProposerVal: &mockconfigtx.PolicyProposer{ 43 Transactional: mockconfigtx.Transactional{}, 44 }, 45 ValueProposerVal: &mockconfigtx.ValueProposer{ 46 Transactional: mockconfigtx.Transactional{}, 47 }, 48 } 49 } 50 51 type configPair struct { 52 key string 53 value *cb.ConfigValue 54 } 55 56 func makeConfigPair(id, modificationPolicy string, lastModified uint64, data []byte) *configPair { 57 return &configPair{ 58 key: id, 59 value: &cb.ConfigValue{ 60 ModPolicy: modificationPolicy, 61 Version: lastModified, 62 Value: data, 63 }, 64 } 65 } 66 67 func makeEnvelopeConfig(channelID string, configPairs ...*configPair) *cb.Envelope { 68 channelGroup := cb.NewConfigGroup() 69 for _, pair := range configPairs { 70 channelGroup.Values[pair.key] = pair.value 71 } 72 73 return &cb.Envelope{ 74 Payload: utils.MarshalOrPanic(&cb.Payload{ 75 Header: &cb.Header{ 76 ChannelHeader: utils.MarshalOrPanic(&cb.ChannelHeader{ 77 Type: int32(cb.HeaderType_CONFIG), 78 ChannelId: channelID, 79 }), 80 }, 81 Data: utils.MarshalOrPanic(&cb.ConfigEnvelope{ 82 Config: &cb.Config{ 83 ChannelGroup: channelGroup, 84 }, 85 }), 86 }), 87 } 88 } 89 90 func makeConfigSet(configPairs ...*configPair) *cb.ConfigGroup { 91 result := cb.NewConfigGroup() 92 for _, pair := range configPairs { 93 result.Values[pair.key] = pair.value 94 } 95 return result 96 } 97 98 func makeConfigUpdateEnvelope(chainID string, readSet, writeSet *cb.ConfigGroup) *cb.Envelope { 99 return &cb.Envelope{ 100 Payload: utils.MarshalOrPanic(&cb.Payload{ 101 Header: &cb.Header{ 102 ChannelHeader: utils.MarshalOrPanic(&cb.ChannelHeader{ 103 Type: int32(cb.HeaderType_CONFIG_UPDATE), 104 }), 105 }, 106 Data: utils.MarshalOrPanic(&cb.ConfigUpdateEnvelope{ 107 ConfigUpdate: utils.MarshalOrPanic(&cb.ConfigUpdate{ 108 ChannelId: chainID, 109 ReadSet: readSet, 110 WriteSet: writeSet, 111 }), 112 }), 113 }), 114 } 115 } 116 117 func TestCallback(t *testing.T) { 118 var calledBack api.Manager 119 callback := func(m api.Manager) { 120 calledBack = m 121 } 122 123 cm, err := NewManagerImpl( 124 makeEnvelopeConfig(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))), 125 defaultInitializer(), []func(api.Manager){callback}) 126 127 if err != nil { 128 t.Fatalf("Error constructing config manager: %s", err) 129 } 130 131 if calledBack != cm { 132 t.Fatalf("Should have called back with the correct manager") 133 } 134 } 135 136 // TestDifferentChainID tests that a config update for a different chain ID fails 137 func TestDifferentChainID(t *testing.T) { 138 cm, err := NewManagerImpl( 139 makeEnvelopeConfig(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))), 140 defaultInitializer(), nil) 141 142 if err != nil { 143 t.Fatalf("Error constructing config manager: %s", err) 144 } 145 146 newConfig := makeConfigUpdateEnvelope("wrongChain", makeConfigSet(), makeConfigSet(makeConfigPair("foo", "foo", 1, []byte("foo")))) 147 148 _, err = cm.ProposeConfigUpdate(newConfig) 149 if err == nil { 150 t.Error("Should have errored when proposing a new config set the wrong chain ID") 151 } 152 } 153 154 // TestOldConfigReplay tests that resubmitting a config for a sequence number which is not newer is ignored 155 func TestOldConfigReplay(t *testing.T) { 156 cm, err := NewManagerImpl( 157 makeEnvelopeConfig(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))), 158 defaultInitializer(), nil) 159 160 if err != nil { 161 t.Fatalf("Error constructing config manager: %s", err) 162 } 163 164 newConfig := makeConfigUpdateEnvelope(defaultChain, makeConfigSet(), makeConfigSet(makeConfigPair("foo", "foo", 0, []byte("foo")))) 165 166 _, err = cm.ProposeConfigUpdate(newConfig) 167 if err == nil { 168 t.Error("Should have errored when proposing a config that is not a newer sequence number") 169 } 170 } 171 172 // TestValidConfigChange tests the happy path of updating a config value with no defaultModificationPolicy 173 func TestValidConfigChange(t *testing.T) { 174 cm, err := NewManagerImpl( 175 makeEnvelopeConfig(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))), 176 defaultInitializer(), nil) 177 178 if err != nil { 179 t.Fatalf("Error constructing config manager: %s", err) 180 } 181 182 newConfig := makeConfigUpdateEnvelope(defaultChain, makeConfigSet(), makeConfigSet(makeConfigPair("foo", "foo", 1, []byte("foo")))) 183 184 configEnv, err := cm.ProposeConfigUpdate(newConfig) 185 if err != nil { 186 t.Errorf("Should not have errored proposing config: %s", err) 187 } 188 189 err = cm.Validate(configEnv) 190 if err != nil { 191 t.Errorf("Should not have errored validating config: %s", err) 192 } 193 194 err = cm.Apply(configEnv) 195 if err != nil { 196 t.Errorf("Should not have errored applying config: %s", err) 197 } 198 } 199 200 // TestConfigChangeRegressedSequence tests to make sure that a new config cannot roll back one of the 201 // config values while advancing another 202 func TestConfigChangeRegressedSequence(t *testing.T) { 203 cm, err := NewManagerImpl( 204 makeEnvelopeConfig(defaultChain, makeConfigPair("foo", "foo", 1, []byte("foo"))), 205 defaultInitializer(), nil) 206 207 if err != nil { 208 t.Fatalf("Error constructing config manager: %s", err) 209 } 210 211 newConfig := makeConfigUpdateEnvelope( 212 defaultChain, 213 makeConfigSet(makeConfigPair("foo", "foo", 0, []byte("foo"))), 214 makeConfigSet(makeConfigPair("bar", "bar", 2, []byte("bar"))), 215 ) 216 217 _, err = cm.ProposeConfigUpdate(newConfig) 218 if err == nil { 219 t.Error("Should have errored proposing config because foo's sequence number regressed") 220 } 221 } 222 223 // TestConfigChangeOldSequence tests to make sure that a new config cannot roll back one of the 224 // config values while advancing another 225 func TestConfigChangeOldSequence(t *testing.T) { 226 cm, err := NewManagerImpl( 227 makeEnvelopeConfig(defaultChain, makeConfigPair("foo", "foo", 1, []byte("foo"))), 228 defaultInitializer(), nil) 229 230 if err != nil { 231 t.Fatalf("Error constructing config manager: %s", err) 232 } 233 234 newConfig := makeConfigUpdateEnvelope( 235 defaultChain, 236 makeConfigSet(), 237 makeConfigSet( 238 makeConfigPair("foo", "foo", 2, []byte("foo")), 239 makeConfigPair("bar", "bar", 1, []byte("bar")), 240 ), 241 ) 242 243 _, err = cm.ProposeConfigUpdate(newConfig) 244 if err == nil { 245 t.Error("Should have errored proposing config because bar was new but its sequence number was old") 246 } 247 } 248 249 // TestConfigPartialUpdate tests to make sure that a new config can set only part 250 // of the config and still be accepted 251 func TestConfigPartialUpdate(t *testing.T) { 252 cm, err := NewManagerImpl( 253 makeEnvelopeConfig( 254 defaultChain, 255 makeConfigPair("foo", "foo", 0, []byte("foo")), 256 makeConfigPair("bar", "bar", 0, []byte("bar")), 257 ), 258 defaultInitializer(), nil) 259 260 if err != nil { 261 t.Fatalf("Error constructing config manager: %s", err) 262 } 263 264 newConfig := makeConfigUpdateEnvelope( 265 defaultChain, 266 makeConfigSet(), 267 makeConfigSet(makeConfigPair("bar", "bar", 1, []byte("bar"))), 268 ) 269 270 _, err = cm.ProposeConfigUpdate(newConfig) 271 assert.NoError(t, err, "Should have allowed partial update") 272 } 273 274 // TestEmptyConfigUpdate tests to make sure that an empty config is rejected as an update 275 func TestEmptyConfigUpdate(t *testing.T) { 276 cm, err := NewManagerImpl( 277 makeEnvelopeConfig(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))), 278 defaultInitializer(), nil) 279 280 if err != nil { 281 t.Fatalf("Error constructing config manager: %s", err) 282 } 283 284 newConfig := &cb.Envelope{} 285 286 _, err = cm.ProposeConfigUpdate(newConfig) 287 if err == nil { 288 t.Error("Should not errored proposing config because new config is empty") 289 } 290 } 291 292 // TestSilentConfigModification tests to make sure that even if a validly signed new config for an existing sequence number 293 // is substituted into an otherwise valid new config, that the new config is rejected for attempting a modification without 294 // increasing the config item's LastModified 295 func TestSilentConfigModification(t *testing.T) { 296 cm, err := NewManagerImpl( 297 makeEnvelopeConfig( 298 defaultChain, 299 makeConfigPair("foo", "foo", 0, []byte("foo")), 300 makeConfigPair("bar", "bar", 0, []byte("bar")), 301 ), 302 defaultInitializer(), nil) 303 304 if err != nil { 305 t.Fatalf("Error constructing config manager: %s", err) 306 } 307 308 newConfig := makeConfigUpdateEnvelope( 309 defaultChain, 310 makeConfigSet(), 311 makeConfigSet( 312 makeConfigPair("foo", "foo", 0, []byte("different")), 313 makeConfigPair("bar", "bar", 1, []byte("bar")), 314 ), 315 ) 316 317 _, err = cm.ProposeConfigUpdate(newConfig) 318 if err == nil { 319 t.Error("Should have errored proposing config because foo was silently modified (despite modification allowed by policy)") 320 } 321 } 322 323 // TestConfigChangeViolatesPolicy checks to make sure that if policy rejects the validation of a config item that 324 // it is rejected in a config update 325 func TestConfigChangeViolatesPolicy(t *testing.T) { 326 initializer := defaultInitializer() 327 cm, err := NewManagerImpl( 328 makeEnvelopeConfig(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))), 329 initializer, nil) 330 331 if err != nil { 332 t.Fatalf("Error constructing config manager: %s", err) 333 } 334 // Set the mock policy to error 335 initializer.Resources.PolicyManagerVal.Policy.Err = fmt.Errorf("err") 336 337 newConfig := makeConfigUpdateEnvelope(defaultChain, makeConfigSet(), makeConfigSet(makeConfigPair("foo", "foo", 1, []byte("foo")))) 338 339 _, err = cm.ProposeConfigUpdate(newConfig) 340 if err == nil { 341 t.Error("Should have errored proposing config because policy rejected modification") 342 } 343 } 344 345 // TestUnchangedConfigViolatesPolicy checks to make sure that existing config items are not revalidated against their modification policies 346 // as the policy may have changed, certs revoked, etc. since the config was adopted. 347 func TestUnchangedConfigViolatesPolicy(t *testing.T) { 348 initializer := defaultInitializer() 349 cm, err := NewManagerImpl( 350 makeEnvelopeConfig(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))), 351 initializer, nil) 352 353 if err != nil { 354 t.Fatalf("Error constructing config manager: %s", err) 355 } 356 357 // Set the mock policy to error 358 initializer.Resources.PolicyManagerVal.PolicyMap = make(map[string]policies.Policy) 359 initializer.Resources.PolicyManagerVal.PolicyMap["foo"] = &mockpolicies.Policy{Err: fmt.Errorf("err")} 360 361 newConfig := makeConfigUpdateEnvelope( 362 defaultChain, 363 makeConfigSet(makeConfigPair("foo", "foo", 0, []byte("foo"))), 364 makeConfigSet(makeConfigPair("bar", "bar", 0, []byte("foo"))), 365 ) 366 367 configEnv, err := cm.ProposeConfigUpdate(newConfig) 368 if err != nil { 369 t.Errorf("Should not have errored proposing config, but got %s", err) 370 } 371 372 err = cm.Validate(configEnv) 373 if err != nil { 374 t.Errorf("Should not have errored validating config, but got %s", err) 375 } 376 377 err = cm.Apply(configEnv) 378 if err != nil { 379 t.Errorf("Should not have errored applying config, but got %s", err) 380 } 381 } 382 383 // TestInvalidProposal checks that even if the policy allows the transaction and the sequence etc. is well formed, 384 // that if the handler does not accept the config, it is rejected 385 func TestInvalidProposal(t *testing.T) { 386 initializer := defaultInitializer() 387 cm, err := NewManagerImpl( 388 makeEnvelopeConfig(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))), 389 initializer, nil) 390 391 if err != nil { 392 t.Fatalf("Error constructing config manager: %s", err) 393 } 394 395 initializer.ValueProposerVal = &mockconfigtx.ValueProposer{DeserializeError: fmt.Errorf("err")} 396 397 newConfig := makeConfigUpdateEnvelope(defaultChain, makeConfigSet(), makeConfigSet(makeConfigPair("foo", "foo", 1, []byte("foo")))) 398 399 _, err = cm.ProposeConfigUpdate(newConfig) 400 if err == nil { 401 t.Error("Should have errored proposing config because the handler rejected it") 402 } 403 } 404 405 // TestMissingHeader checks that a config envelope with a missing header causes the config to be rejected 406 func TestMissingHeader(t *testing.T) { 407 group := cb.NewConfigGroup() 408 group.Values["foo"] = &cb.ConfigValue{} 409 _, err := NewManagerImpl( 410 &cb.Envelope{Payload: utils.MarshalOrPanic(&cb.Payload{Data: utils.MarshalOrPanic(&cb.ConfigEnvelope{Config: &cb.Config{ChannelGroup: group}})})}, 411 defaultInitializer(), nil) 412 413 if err == nil { 414 t.Error("Should have errored creating the config manager because of the missing header") 415 } 416 } 417 418 // TestMissingChainID checks that a config item with a missing chainID causes the config to be rejected 419 func TestMissingChainID(t *testing.T) { 420 _, err := NewManagerImpl( 421 makeEnvelopeConfig("", makeConfigPair("foo", "foo", 0, []byte("foo"))), 422 defaultInitializer(), nil) 423 424 if err == nil { 425 t.Error("Should have errored creating the config manager because of the missing header") 426 } 427 }