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