diff --git a/orderer/common/blockcutter/blockcutter_test.go b/orderer/common/blockcutter/blockcutter_test.go index 54cbec70e35..fd8e153cc18 100644 --- a/orderer/common/blockcutter/blockcutter_test.go +++ b/orderer/common/blockcutter/blockcutter_test.go @@ -21,7 +21,7 @@ import ( "testing" "github.com/hyperledger/fabric/orderer/common/filter" - "github.com/hyperledger/fabric/orderer/mocks" + mocksharedconfig "github.com/hyperledger/fabric/orderer/mocks/sharedconfig" cb "github.com/hyperledger/fabric/protos/common" ) @@ -74,7 +74,7 @@ var unmatchedTx = &cb.Envelope{Payload: []byte("UNMATCHED")} func TestNormalBatch(t *testing.T) { filters := getFilters() batchSize := 2 - r := NewReceiverImpl(&mocks.SharedConfigManager{BatchSizeVal: batchSize}, filters) + r := NewReceiverImpl(&mocksharedconfig.Manager{BatchSizeVal: batchSize}, filters) batches, committers, ok := r.Ordered(goodTx) @@ -101,7 +101,7 @@ func TestNormalBatch(t *testing.T) { func TestBadMessageInBatch(t *testing.T) { filters := getFilters() batchSize := 2 - r := NewReceiverImpl(&mocks.SharedConfigManager{BatchSizeVal: batchSize}, filters) + r := NewReceiverImpl(&mocksharedconfig.Manager{BatchSizeVal: batchSize}, filters) batches, committers, ok := r.Ordered(badTx) @@ -137,7 +137,7 @@ func TestBadMessageInBatch(t *testing.T) { func TestUnmatchedMessageInBatch(t *testing.T) { filters := getFilters() batchSize := 2 - r := NewReceiverImpl(&mocks.SharedConfigManager{BatchSizeVal: batchSize}, filters) + r := NewReceiverImpl(&mocksharedconfig.Manager{BatchSizeVal: batchSize}, filters) batches, committers, ok := r.Ordered(unmatchedTx) @@ -173,7 +173,7 @@ func TestUnmatchedMessageInBatch(t *testing.T) { func TestIsolatedEmptyBatch(t *testing.T) { filters := getFilters() batchSize := 2 - r := NewReceiverImpl(&mocks.SharedConfigManager{BatchSizeVal: batchSize}, filters) + r := NewReceiverImpl(&mocksharedconfig.Manager{BatchSizeVal: batchSize}, filters) batches, committers, ok := r.Ordered(isolatedTx) @@ -197,7 +197,7 @@ func TestIsolatedEmptyBatch(t *testing.T) { func TestIsolatedPartialBatch(t *testing.T) { filters := getFilters() batchSize := 2 - r := NewReceiverImpl(&mocks.SharedConfigManager{BatchSizeVal: batchSize}, filters) + r := NewReceiverImpl(&mocksharedconfig.Manager{BatchSizeVal: batchSize}, filters) batches, committers, ok := r.Ordered(goodTx) diff --git a/orderer/mocks/blockcutter/blockcutter.go b/orderer/mocks/blockcutter/blockcutter.go new file mode 100644 index 00000000000..4435053d479 --- /dev/null +++ b/orderer/mocks/blockcutter/blockcutter.go @@ -0,0 +1,104 @@ +/* +Copyright IBM Corp. 2016 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package mocks + +import ( + "github.com/hyperledger/fabric/orderer/common/filter" + cb "github.com/hyperledger/fabric/protos/common" +) + +import ( + "github.com/op/go-logging" +) + +var logger = logging.MustGetLogger("orderer/mocks/blockcutter") + +// Receiver mocks the blockcutter.Receiver interface +type Receiver struct { + // QueueNext causes Ordered returns nil false when not set to true + QueueNext bool + + // IsolatedTx causes Ordered returns [][]{curBatch, []{newTx}}, true when set to true + IsolatedTx bool + + // CutNext causes Ordered returns [][]{append(curBatch, newTx)}, true when set to true + CutNext bool + + // CurBatch is the currently outstanding messages in the batch + CurBatch []*cb.Envelope + + // Block is a channel which is read from before returning from Ordered, it is useful for synchronization + // If you do not wish synchronization for whatever reason, simply close the channel + Block chan struct{} +} + +// NewReceiver returns the mock blockcutter.Receiver implemenation +func NewReceiver() *Receiver { + return &Receiver{ + QueueNext: true, + IsolatedTx: false, + CutNext: false, + Block: make(chan struct{}), + } +} + +func noopCommitters(size int) []filter.Committer { + res := make([]filter.Committer, size) + for i := range res { + res[i] = filter.NoopCommitter + } + return res +} + +// Ordered will add or cut the batch according to the state of Receiver, it blocks reading from Block on return +func (mbc *Receiver) Ordered(env *cb.Envelope) ([][]*cb.Envelope, [][]filter.Committer, bool) { + defer func() { + <-mbc.Block + }() + + if !mbc.QueueNext { + logger.Debugf("Not queueing message") + return nil, nil, false + } + + if mbc.IsolatedTx { + logger.Debugf("Receiver: Returning dual batch") + res := [][]*cb.Envelope{mbc.CurBatch, []*cb.Envelope{env}} + mbc.CurBatch = nil + return res, [][]filter.Committer{noopCommitters(len(res[0])), noopCommitters(len(res[1]))}, true + } + + mbc.CurBatch = append(mbc.CurBatch, env) + + if mbc.CutNext { + logger.Debugf("Returning regular batch") + res := [][]*cb.Envelope{mbc.CurBatch} + mbc.CurBatch = nil + return res, [][]filter.Committer{noopCommitters(len(res))}, true + } + + logger.Debugf("Appending to batch") + return nil, nil, true +} + +// Cut terminates the current batch, returning it +func (mbc *Receiver) Cut() ([]*cb.Envelope, []filter.Committer) { + logger.Debugf("Cutting batch") + res := mbc.CurBatch + mbc.CurBatch = nil + return res, noopCommitters(len(res)) +} diff --git a/orderer/mocks/blockcutter/blockcutter_test.go b/orderer/mocks/blockcutter/blockcutter_test.go new file mode 100644 index 00000000000..514e538ec7f --- /dev/null +++ b/orderer/mocks/blockcutter/blockcutter_test.go @@ -0,0 +1,27 @@ +/* +Copyright IBM Corp. 2016 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package mocks + +import ( + "testing" + + "github.com/hyperledger/fabric/orderer/common/blockcutter" +) + +func TestBlockCutterInterface(t *testing.T) { + _ = blockcutter.Receiver(NewReceiver()) +} diff --git a/orderer/mocks/multichain/multichain.go b/orderer/mocks/multichain/multichain.go new file mode 100644 index 00000000000..11faaef3edc --- /dev/null +++ b/orderer/mocks/multichain/multichain.go @@ -0,0 +1,59 @@ +/* +Copyright IBM Corp. 2016 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package multichain + +import ( + "github.com/hyperledger/fabric/orderer/common/blockcutter" + "github.com/hyperledger/fabric/orderer/common/filter" + "github.com/hyperledger/fabric/orderer/common/sharedconfig" + mockblockcutter "github.com/hyperledger/fabric/orderer/mocks/blockcutter" + mocksharedconfig "github.com/hyperledger/fabric/orderer/mocks/sharedconfig" + cb "github.com/hyperledger/fabric/protos/common" + + "github.com/op/go-logging" +) + +var logger = logging.MustGetLogger("orderer/mocks/multichain") + +// ConsenterSupport is used to mock the multichain.ConsenterSupport interface +// Whenever a block is written, it writes to the Batches channel to allow for synchronization +type ConsenterSupport struct { + // SharedConfigVal is the value returned by SharedConfig() + SharedConfigVal *mocksharedconfig.Manager + + // BlockCutterVal is the value returned by BlockCutter() + BlockCutterVal *mockblockcutter.Receiver + + // Batches is the channel which WriteBlock writes data to + Batches chan []*cb.Envelope +} + +// BlockCutter returns BlockCutterVal +func (mcs *ConsenterSupport) BlockCutter() blockcutter.Receiver { + return mcs.BlockCutterVal +} + +// SharedConfig returns SharedConfigVal +func (mcs *ConsenterSupport) SharedConfig() sharedconfig.Manager { + return mcs.SharedConfigVal +} + +// WriteBlock writes data to the Batches channel +func (mcs *ConsenterSupport) WriteBlock(data []*cb.Envelope, metadata [][]byte, committers []filter.Committer) { + logger.Debugf("mockWriter: attempting to write batch") + mcs.Batches <- data +} diff --git a/orderer/mocks/multichain/multichain_test.go b/orderer/mocks/multichain/multichain_test.go new file mode 100644 index 00000000000..c2b14f4beb8 --- /dev/null +++ b/orderer/mocks/multichain/multichain_test.go @@ -0,0 +1,27 @@ +/* +Copyright IBM Corp. 2016 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package multichain + +import ( + "testing" + + "github.com/hyperledger/fabric/orderer/multichain" +) + +func TestConsenterSupportInterface(t *testing.T) { + _ = multichain.ConsenterSupport(&ConsenterSupport{}) +} diff --git a/orderer/mocks/sharedconfig.go b/orderer/mocks/sharedconfig/sharedconfig.go similarity index 63% rename from orderer/mocks/sharedconfig.go rename to orderer/mocks/sharedconfig/sharedconfig.go index f23e22d05b6..4349f47bf9e 100644 --- a/orderer/mocks/sharedconfig.go +++ b/orderer/mocks/sharedconfig/sharedconfig.go @@ -14,10 +14,10 @@ See the License for the specific language governing permissions and limitations under the License. */ -package mocks +package sharedconfig -// MockSharedConfigManager is a mock implementation of sharedconfig.Manager -type SharedConfigManager struct { +// Manager is a mock implementation of sharedconfig.Manager +type Manager struct { // ConsensusTypeVal is returned as the result of ConsensusType() ConsensusTypeVal string // BatchSizeVal is returned as the result of BatchSize() @@ -26,18 +26,17 @@ type SharedConfigManager struct { ChainCreatorsVal []string } -// ConsensusType returns the configured consensus type -func (scm *SharedConfigManager) ConsensusType() string { +// ConsensusType returns the ConsensusTypeVal +func (scm *Manager) ConsensusType() string { return scm.ConsensusTypeVal } -// BatchSize returns the maximum number of messages to include in a block -func (scm *SharedConfigManager) BatchSize() int { +// BatchSize returns the BatchSizeVal +func (scm *Manager) BatchSize() int { return scm.BatchSizeVal } -// ChainCreators returns the policy names which are allowed for chain creation -// This field is only set for the system ordering chain -func (scm *SharedConfigManager) ChainCreators() []string { +// ChainCreators returns the ChainCreatorsVal +func (scm *Manager) ChainCreators() []string { return scm.ChainCreatorsVal } diff --git a/orderer/mocks/sharedconfig_test.go b/orderer/mocks/sharedconfig/sharedconfig_test.go similarity index 91% rename from orderer/mocks/sharedconfig_test.go rename to orderer/mocks/sharedconfig/sharedconfig_test.go index 45ad71ab311..7413945d19d 100644 --- a/orderer/mocks/sharedconfig_test.go +++ b/orderer/mocks/sharedconfig/sharedconfig_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package mocks +package sharedconfig import ( "testing" @@ -23,5 +23,5 @@ import ( ) func TestSharedConfigInterface(t *testing.T) { - _ = sharedconfig.Manager(&SharedConfigManager{}) + _ = sharedconfig.Manager(&Manager{}) } diff --git a/orderer/solo/consensus_test.go b/orderer/solo/consensus_test.go index cbba3e1acc4..1706c9f74e8 100644 --- a/orderer/solo/consensus_test.go +++ b/orderer/solo/consensus_test.go @@ -20,96 +20,16 @@ import ( "testing" "time" - "github.com/hyperledger/fabric/orderer/common/blockcutter" - "github.com/hyperledger/fabric/orderer/common/filter" - "github.com/hyperledger/fabric/orderer/common/sharedconfig" - "github.com/hyperledger/fabric/orderer/multichain" + mockblockcutter "github.com/hyperledger/fabric/orderer/mocks/blockcutter" + mockmultichain "github.com/hyperledger/fabric/orderer/mocks/multichain" cb "github.com/hyperledger/fabric/protos/common" ) -type mockBlockCutter struct { - queueNext bool // Ordered returns nil false when not set to true - isolatedTx bool // Ordered returns [][]{curBatch, []{newTx}}, true when set to true - cutNext bool // Ordered returns [][]{append(curBatch, newTx)}, true when set to true - curBatch []*cb.Envelope - block chan struct{} -} - -func newMockBlockCutter() *mockBlockCutter { - return &mockBlockCutter{ - queueNext: true, - isolatedTx: false, - cutNext: false, - block: make(chan struct{}), - } -} - -func noopCommitters(size int) []filter.Committer { - res := make([]filter.Committer, size) - for i := range res { - res[i] = filter.NoopCommitter - } - return res -} - -func (mbc *mockBlockCutter) Ordered(env *cb.Envelope) ([][]*cb.Envelope, [][]filter.Committer, bool) { - defer func() { - <-mbc.block - }() - - if !mbc.queueNext { - logger.Debugf("mockBlockCutter: Not queueing message") - return nil, nil, false - } - - if mbc.isolatedTx { - logger.Debugf("mockBlockCutter: Returning dual batch") - res := [][]*cb.Envelope{mbc.curBatch, []*cb.Envelope{env}} - mbc.curBatch = nil - return res, [][]filter.Committer{noopCommitters(len(res[0])), noopCommitters(len(res[1]))}, true - } - - mbc.curBatch = append(mbc.curBatch, env) - - if mbc.cutNext { - logger.Debugf("mockBlockCutter: Returning regular batch") - res := [][]*cb.Envelope{mbc.curBatch} - mbc.curBatch = nil - return res, [][]filter.Committer{noopCommitters(len(res))}, true - } - - logger.Debugf("mockBlockCutter: Appending to batch") - return nil, nil, true -} - -func (mbc *mockBlockCutter) Cut() ([]*cb.Envelope, []filter.Committer) { - logger.Debugf("mockBlockCutter: Cutting batch") - res := mbc.curBatch - mbc.curBatch = nil - return res, noopCommitters(len(res)) -} - -type mockConsenterSupport struct { - cutter *mockBlockCutter - batches chan []*cb.Envelope -} - -func (mcs *mockConsenterSupport) BlockCutter() blockcutter.Receiver { - return mcs.cutter -} -func (mcs *mockConsenterSupport) SharedConfig() sharedconfig.Manager { - panic("Unimplemented") -} -func (mcs *mockConsenterSupport) WriteBlock(data []*cb.Envelope, metadata [][]byte, committers []filter.Committer) { - logger.Debugf("mockWriter: attempting to write batch") - mcs.batches <- data -} - var testMessage = &cb.Envelope{Payload: []byte("TEST_MESSAGE")} -func syncQueueMessage(msg *cb.Envelope, chain multichain.Chain, bc *mockBlockCutter) { +func syncQueueMessage(msg *cb.Envelope, chain *chain, bc *mockblockcutter.Receiver) { chain.Enqueue(msg) - bc.block <- struct{}{} + bc.Block <- struct{}{} } type waitableGo struct { @@ -128,74 +48,74 @@ func goWithWait(target func()) *waitableGo { } func TestEmptyBatch(t *testing.T) { - support := &mockConsenterSupport{ - batches: make(chan []*cb.Envelope), - cutter: newMockBlockCutter(), + support := &mockmultichain.ConsenterSupport{ + Batches: make(chan []*cb.Envelope), + BlockCutterVal: mockblockcutter.NewReceiver(), } - defer close(support.cutter.block) + defer close(support.BlockCutterVal.Block) bs := newChain(time.Millisecond, support) wg := goWithWait(bs.main) defer bs.Halt() - syncQueueMessage(testMessage, bs, support.cutter) + syncQueueMessage(testMessage, bs, support.BlockCutterVal) bs.Halt() select { - case <-support.batches: + case <-support.Batches: t.Fatalf("Expected no invocations of Append") case <-wg.done: } } func TestBatchTimer(t *testing.T) { - support := &mockConsenterSupport{ - batches: make(chan []*cb.Envelope), - cutter: newMockBlockCutter(), + support := &mockmultichain.ConsenterSupport{ + Batches: make(chan []*cb.Envelope), + BlockCutterVal: mockblockcutter.NewReceiver(), } - defer close(support.cutter.block) + defer close(support.BlockCutterVal.Block) bs := newChain(time.Millisecond, support) wg := goWithWait(bs.main) defer bs.Halt() - syncQueueMessage(testMessage, bs, support.cutter) + syncQueueMessage(testMessage, bs, support.BlockCutterVal) select { - case <-support.batches: + case <-support.Batches: case <-time.After(time.Second): t.Fatalf("Expected a block to be cut because of batch timer expiration but did not") } - syncQueueMessage(testMessage, bs, support.cutter) + syncQueueMessage(testMessage, bs, support.BlockCutterVal) select { - case <-support.batches: + case <-support.Batches: case <-time.After(time.Second): t.Fatalf("Did not create the second batch, indicating that the timer was not appopriately reset") } bs.Halt() select { - case <-support.batches: + case <-support.Batches: t.Fatalf("Expected no invocations of Append") case <-wg.done: } } func TestBatchTimerHaltOnFilledBatch(t *testing.T) { - support := &mockConsenterSupport{ - batches: make(chan []*cb.Envelope), - cutter: newMockBlockCutter(), + support := &mockmultichain.ConsenterSupport{ + Batches: make(chan []*cb.Envelope), + BlockCutterVal: mockblockcutter.NewReceiver(), } - defer close(support.cutter.block) + defer close(support.BlockCutterVal.Block) bs := newChain(time.Hour, support) wg := goWithWait(bs.main) defer bs.Halt() - syncQueueMessage(testMessage, bs, support.cutter) - support.cutter.cutNext = true - syncQueueMessage(testMessage, bs, support.cutter) + syncQueueMessage(testMessage, bs, support.BlockCutterVal) + support.BlockCutterVal.CutNext = true + syncQueueMessage(testMessage, bs, support.BlockCutterVal) select { - case <-support.batches: + case <-support.Batches: case <-time.After(time.Second): t.Fatalf("Expected a block to be cut because the batch was filled, but did not") } @@ -203,11 +123,11 @@ func TestBatchTimerHaltOnFilledBatch(t *testing.T) { // Change the batch timeout to be near instant, if the timer was not reset, it will still be waiting an hour bs.batchTimeout = time.Millisecond - support.cutter.cutNext = false - syncQueueMessage(testMessage, bs, support.cutter) + support.BlockCutterVal.CutNext = false + syncQueueMessage(testMessage, bs, support.BlockCutterVal) select { - case <-support.batches: + case <-support.Batches: case <-time.After(time.Second): t.Fatalf("Did not create the second batch, indicating that the old timer was still running") } @@ -221,27 +141,27 @@ func TestBatchTimerHaltOnFilledBatch(t *testing.T) { } func TestConfigStyleMultiBatch(t *testing.T) { - support := &mockConsenterSupport{ - batches: make(chan []*cb.Envelope), - cutter: newMockBlockCutter(), + support := &mockmultichain.ConsenterSupport{ + Batches: make(chan []*cb.Envelope), + BlockCutterVal: mockblockcutter.NewReceiver(), } - defer close(support.cutter.block) + defer close(support.BlockCutterVal.Block) bs := newChain(time.Hour, support) wg := goWithWait(bs.main) defer bs.Halt() - syncQueueMessage(testMessage, bs, support.cutter) - support.cutter.isolatedTx = true - syncQueueMessage(testMessage, bs, support.cutter) + syncQueueMessage(testMessage, bs, support.BlockCutterVal) + support.BlockCutterVal.IsolatedTx = true + syncQueueMessage(testMessage, bs, support.BlockCutterVal) select { - case <-support.batches: + case <-support.Batches: case <-time.After(time.Second): t.Fatalf("Expected two blocks to be cut but never got the first") } select { - case <-support.batches: + case <-support.Batches: case <-time.After(time.Second): t.Fatalf("Expected the config type tx to create two blocks, but only go the first") }