github.com/myafeier/fabric@v1.0.1-0.20170722181825-3a4b1f2bce86/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 = "default.chain.id" 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 func TestEmptyChannel(t *testing.T) { 137 _, err := NewManagerImpl(&cb.Envelope{ 138 Payload: utils.MarshalOrPanic(&cb.Payload{ 139 Header: &cb.Header{ 140 ChannelHeader: utils.MarshalOrPanic(&cb.ChannelHeader{ 141 Type: int32(cb.HeaderType_CONFIG), 142 ChannelId: "foo", 143 }), 144 }, 145 Data: utils.MarshalOrPanic(&cb.ConfigEnvelope{ 146 Config: &cb.Config{}, 147 }), 148 }), 149 }, defaultInitializer(), nil) 150 assert.Error(t, err) 151 } 152 153 // TestDifferentChainID tests that a config update for a different chain ID fails 154 func TestDifferentChainID(t *testing.T) { 155 cm, err := NewManagerImpl( 156 makeEnvelopeConfig(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))), 157 defaultInitializer(), nil) 158 159 if err != nil { 160 t.Fatalf("Error constructing config manager: %s", err) 161 } 162 163 newConfig := makeConfigUpdateEnvelope("wrongChain", makeConfigSet(), makeConfigSet(makeConfigPair("foo", "foo", 1, []byte("foo")))) 164 165 _, err = cm.ProposeConfigUpdate(newConfig) 166 if err == nil { 167 t.Error("Should have errored when proposing a new config set the wrong chain ID") 168 } 169 } 170 171 // TestOldConfigReplay tests that resubmitting a config for a sequence number which is not newer is ignored 172 func TestOldConfigReplay(t *testing.T) { 173 cm, err := NewManagerImpl( 174 makeEnvelopeConfig(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))), 175 defaultInitializer(), nil) 176 177 if err != nil { 178 t.Fatalf("Error constructing config manager: %s", err) 179 } 180 181 newConfig := makeConfigUpdateEnvelope(defaultChain, makeConfigSet(), makeConfigSet(makeConfigPair("foo", "foo", 0, []byte("foo")))) 182 183 _, err = cm.ProposeConfigUpdate(newConfig) 184 if err == nil { 185 t.Error("Should have errored when proposing a config that is not a newer sequence number") 186 } 187 } 188 189 // TestValidConfigChange tests the happy path of updating a config value with no defaultModificationPolicy 190 func TestValidConfigChange(t *testing.T) { 191 cm, err := NewManagerImpl( 192 makeEnvelopeConfig(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))), 193 defaultInitializer(), nil) 194 195 if err != nil { 196 t.Fatalf("Error constructing config manager: %s", err) 197 } 198 199 newConfig := makeConfigUpdateEnvelope(defaultChain, makeConfigSet(), makeConfigSet(makeConfigPair("foo", "foo", 1, []byte("foo")))) 200 201 configEnv, err := cm.ProposeConfigUpdate(newConfig) 202 if err != nil { 203 t.Errorf("Should not have errored proposing config: %s", err) 204 } 205 206 err = cm.Validate(configEnv) 207 if err != nil { 208 t.Errorf("Should not have errored validating config: %s", err) 209 } 210 211 err = cm.Apply(configEnv) 212 if err != nil { 213 t.Errorf("Should not have errored applying config: %s", err) 214 } 215 } 216 217 // TestConfigChangeRegressedSequence tests to make sure that a new config cannot roll back one of the 218 // config values while advancing another 219 func TestConfigChangeRegressedSequence(t *testing.T) { 220 cm, err := NewManagerImpl( 221 makeEnvelopeConfig(defaultChain, makeConfigPair("foo", "foo", 1, []byte("foo"))), 222 defaultInitializer(), nil) 223 224 if err != nil { 225 t.Fatalf("Error constructing config manager: %s", err) 226 } 227 228 newConfig := makeConfigUpdateEnvelope( 229 defaultChain, 230 makeConfigSet(makeConfigPair("foo", "foo", 0, []byte("foo"))), 231 makeConfigSet(makeConfigPair("bar", "bar", 2, []byte("bar"))), 232 ) 233 234 _, err = cm.ProposeConfigUpdate(newConfig) 235 if err == nil { 236 t.Error("Should have errored proposing config because foo's sequence number regressed") 237 } 238 } 239 240 // TestConfigChangeOldSequence tests to make sure that a new config cannot roll back one of the 241 // config values while advancing another 242 func TestConfigChangeOldSequence(t *testing.T) { 243 cm, err := NewManagerImpl( 244 makeEnvelopeConfig(defaultChain, makeConfigPair("foo", "foo", 1, []byte("foo"))), 245 defaultInitializer(), nil) 246 247 if err != nil { 248 t.Fatalf("Error constructing config manager: %s", err) 249 } 250 251 newConfig := makeConfigUpdateEnvelope( 252 defaultChain, 253 makeConfigSet(), 254 makeConfigSet( 255 makeConfigPair("foo", "foo", 2, []byte("foo")), 256 makeConfigPair("bar", "bar", 1, []byte("bar")), 257 ), 258 ) 259 260 _, err = cm.ProposeConfigUpdate(newConfig) 261 if err == nil { 262 t.Error("Should have errored proposing config because bar was new but its sequence number was old") 263 } 264 } 265 266 // TestConfigPartialUpdate tests to make sure that a new config can set only part 267 // of the config and still be accepted 268 func TestConfigPartialUpdate(t *testing.T) { 269 cm, err := NewManagerImpl( 270 makeEnvelopeConfig( 271 defaultChain, 272 makeConfigPair("foo", "foo", 0, []byte("foo")), 273 makeConfigPair("bar", "bar", 0, []byte("bar")), 274 ), 275 defaultInitializer(), nil) 276 277 if err != nil { 278 t.Fatalf("Error constructing config manager: %s", err) 279 } 280 281 newConfig := makeConfigUpdateEnvelope( 282 defaultChain, 283 makeConfigSet(), 284 makeConfigSet(makeConfigPair("bar", "bar", 1, []byte("bar"))), 285 ) 286 287 _, err = cm.ProposeConfigUpdate(newConfig) 288 assert.NoError(t, err, "Should have allowed partial update") 289 } 290 291 // TestEmptyConfigUpdate tests to make sure that an empty config is rejected as an update 292 func TestEmptyConfigUpdate(t *testing.T) { 293 cm, err := NewManagerImpl( 294 makeEnvelopeConfig(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))), 295 defaultInitializer(), nil) 296 297 if err != nil { 298 t.Fatalf("Error constructing config manager: %s", err) 299 } 300 301 newConfig := &cb.Envelope{} 302 303 _, err = cm.ProposeConfigUpdate(newConfig) 304 if err == nil { 305 t.Error("Should not errored proposing config because new config is empty") 306 } 307 } 308 309 // TestSilentConfigModification tests to make sure that even if a validly signed new config for an existing sequence number 310 // is substituted into an otherwise valid new config, that the new config is rejected for attempting a modification without 311 // increasing the config item's LastModified 312 func TestSilentConfigModification(t *testing.T) { 313 cm, err := NewManagerImpl( 314 makeEnvelopeConfig( 315 defaultChain, 316 makeConfigPair("foo", "foo", 0, []byte("foo")), 317 makeConfigPair("bar", "bar", 0, []byte("bar")), 318 ), 319 defaultInitializer(), nil) 320 321 if err != nil { 322 t.Fatalf("Error constructing config manager: %s", err) 323 } 324 325 newConfig := makeConfigUpdateEnvelope( 326 defaultChain, 327 makeConfigSet(), 328 makeConfigSet( 329 makeConfigPair("foo", "foo", 0, []byte("different")), 330 makeConfigPair("bar", "bar", 1, []byte("bar")), 331 ), 332 ) 333 334 _, err = cm.ProposeConfigUpdate(newConfig) 335 if err == nil { 336 t.Error("Should have errored proposing config because foo was silently modified (despite modification allowed by policy)") 337 } 338 } 339 340 // TestConfigChangeViolatesPolicy checks to make sure that if policy rejects the validation of a config item that 341 // it is rejected in a config update 342 func TestConfigChangeViolatesPolicy(t *testing.T) { 343 initializer := defaultInitializer() 344 cm, err := NewManagerImpl( 345 makeEnvelopeConfig(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))), 346 initializer, nil) 347 348 if err != nil { 349 t.Fatalf("Error constructing config manager: %s", err) 350 } 351 // Set the mock policy to error 352 initializer.Resources.PolicyManagerVal.Policy.Err = fmt.Errorf("err") 353 354 newConfig := makeConfigUpdateEnvelope(defaultChain, makeConfigSet(), makeConfigSet(makeConfigPair("foo", "foo", 1, []byte("foo")))) 355 356 _, err = cm.ProposeConfigUpdate(newConfig) 357 if err == nil { 358 t.Error("Should have errored proposing config because policy rejected modification") 359 } 360 } 361 362 // TestUnchangedConfigViolatesPolicy checks to make sure that existing config items are not revalidated against their modification policies 363 // as the policy may have changed, certs revoked, etc. since the config was adopted. 364 func TestUnchangedConfigViolatesPolicy(t *testing.T) { 365 initializer := defaultInitializer() 366 cm, err := NewManagerImpl( 367 makeEnvelopeConfig(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))), 368 initializer, nil) 369 370 if err != nil { 371 t.Fatalf("Error constructing config manager: %s", err) 372 } 373 374 // Set the mock policy to error 375 initializer.Resources.PolicyManagerVal.PolicyMap = make(map[string]policies.Policy) 376 initializer.Resources.PolicyManagerVal.PolicyMap["foo"] = &mockpolicies.Policy{Err: fmt.Errorf("err")} 377 378 newConfig := makeConfigUpdateEnvelope( 379 defaultChain, 380 makeConfigSet(makeConfigPair("foo", "foo", 0, []byte("foo"))), 381 makeConfigSet(makeConfigPair("bar", "bar", 0, []byte("foo"))), 382 ) 383 384 configEnv, err := cm.ProposeConfigUpdate(newConfig) 385 if err != nil { 386 t.Errorf("Should not have errored proposing config, but got %s", err) 387 } 388 389 err = cm.Validate(configEnv) 390 if err != nil { 391 t.Errorf("Should not have errored validating config, but got %s", err) 392 } 393 394 err = cm.Apply(configEnv) 395 if err != nil { 396 t.Errorf("Should not have errored applying config, but got %s", err) 397 } 398 } 399 400 // TestInvalidProposal checks that even if the policy allows the transaction and the sequence etc. is well formed, 401 // that if the handler does not accept the config, it is rejected 402 func TestInvalidProposal(t *testing.T) { 403 initializer := defaultInitializer() 404 cm, err := NewManagerImpl( 405 makeEnvelopeConfig(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))), 406 initializer, nil) 407 408 if err != nil { 409 t.Fatalf("Error constructing config manager: %s", err) 410 } 411 412 initializer.ValueProposerVal = &mockconfigtx.ValueProposer{DeserializeError: fmt.Errorf("err")} 413 414 newConfig := makeConfigUpdateEnvelope(defaultChain, makeConfigSet(), makeConfigSet(makeConfigPair("foo", "foo", 1, []byte("foo")))) 415 416 _, err = cm.ProposeConfigUpdate(newConfig) 417 if err == nil { 418 t.Error("Should have errored proposing config because the handler rejected it") 419 } 420 } 421 422 // TestMissingHeader checks that a config envelope with a missing header causes the config to be rejected 423 func TestMissingHeader(t *testing.T) { 424 group := cb.NewConfigGroup() 425 group.Values["foo"] = &cb.ConfigValue{} 426 _, err := NewManagerImpl( 427 &cb.Envelope{Payload: utils.MarshalOrPanic(&cb.Payload{Data: utils.MarshalOrPanic(&cb.ConfigEnvelope{Config: &cb.Config{ChannelGroup: group}})})}, 428 defaultInitializer(), nil) 429 430 if err == nil { 431 t.Error("Should have errored creating the config manager because of the missing header") 432 } 433 } 434 435 // TestMissingChainID checks that a config item with a missing chainID causes the config to be rejected 436 func TestMissingChainID(t *testing.T) { 437 _, err := NewManagerImpl( 438 makeEnvelopeConfig("", makeConfigPair("foo", "foo", 0, []byte("foo"))), 439 defaultInitializer(), nil) 440 441 if err == nil { 442 t.Error("Should have errored creating the config manager because of the missing header") 443 } 444 }