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  }