github.com/tenywen/fabric@v1.0.0-beta.0.20170620030522-a5b1ed380643/orderer/kafka/consenter_test.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package kafka 8 9 import ( 10 "fmt" 11 "log" 12 "os" 13 "strings" 14 "testing" 15 "time" 16 17 "github.com/Shopify/sarama" 18 "github.com/golang/protobuf/proto" 19 "github.com/hyperledger/fabric/common/flogging" 20 mockconfig "github.com/hyperledger/fabric/common/mocks/config" 21 localconfig "github.com/hyperledger/fabric/orderer/localconfig" 22 mockblockcutter "github.com/hyperledger/fabric/orderer/mocks/blockcutter" 23 mockmultichain "github.com/hyperledger/fabric/orderer/mocks/multichain" 24 "github.com/hyperledger/fabric/orderer/multichain" 25 cb "github.com/hyperledger/fabric/protos/common" 26 ab "github.com/hyperledger/fabric/protos/orderer" 27 "github.com/hyperledger/fabric/protos/utils" 28 "github.com/stretchr/testify/assert" 29 ) 30 31 var mockRetryOptions = localconfig.Retry{ 32 ShortInterval: 50 * time.Millisecond, 33 ShortTotal: 100 * time.Millisecond, 34 LongInterval: 60 * time.Millisecond, 35 LongTotal: 120 * time.Millisecond, 36 NetworkTimeouts: localconfig.NetworkTimeouts{ 37 DialTimeout: 40 * time.Millisecond, 38 ReadTimeout: 40 * time.Millisecond, 39 WriteTimeout: 40 * time.Millisecond, 40 }, 41 Metadata: localconfig.Metadata{ 42 RetryMax: 2, 43 RetryBackoff: 40 * time.Millisecond, 44 }, 45 Producer: localconfig.Producer{ 46 RetryMax: 2, 47 RetryBackoff: 40 * time.Millisecond, 48 }, 49 Consumer: localconfig.Consumer{ 50 RetryBackoff: 40 * time.Millisecond, 51 }, 52 } 53 54 func init() { 55 mockLocalConfig = newMockLocalConfig(false, mockRetryOptions, false) 56 mockBrokerConfig = newMockBrokerConfig(mockLocalConfig.General.TLS, mockLocalConfig.Kafka.Retry, mockLocalConfig.Kafka.Version, defaultPartition) 57 mockConsenter = newMockConsenter(mockBrokerConfig, mockLocalConfig.General.TLS, mockLocalConfig.Kafka.Retry, mockLocalConfig.Kafka.Version) 58 setupTestLogging("ERROR", mockLocalConfig.Kafka.Verbose) 59 } 60 61 func TestNew(t *testing.T) { 62 _ = multichain.Consenter(New(mockLocalConfig.General.TLS, mockLocalConfig.Kafka.Retry, mockLocalConfig.Kafka.Version)) 63 } 64 65 func TestHandleChain(t *testing.T) { 66 consenter := multichain.Consenter(New(mockLocalConfig.General.TLS, mockLocalConfig.Kafka.Retry, mockLocalConfig.Kafka.Version)) 67 68 oldestOffset := int64(0) 69 newestOffset := int64(5) 70 message := sarama.StringEncoder("messageFoo") 71 72 mockChannel := newChannel(channelNameForTest(t), defaultPartition) 73 74 mockBroker := sarama.NewMockBroker(t, 0) 75 mockBroker.SetHandlerByMap(map[string]sarama.MockResponse{ 76 "MetadataRequest": sarama.NewMockMetadataResponse(t). 77 SetBroker(mockBroker.Addr(), mockBroker.BrokerID()). 78 SetLeader(mockChannel.topic(), mockChannel.partition(), mockBroker.BrokerID()), 79 "ProduceRequest": sarama.NewMockProduceResponse(t). 80 SetError(mockChannel.topic(), mockChannel.partition(), sarama.ErrNoError), 81 "OffsetRequest": sarama.NewMockOffsetResponse(t). 82 SetOffset(mockChannel.topic(), mockChannel.partition(), sarama.OffsetOldest, oldestOffset). 83 SetOffset(mockChannel.topic(), mockChannel.partition(), sarama.OffsetNewest, newestOffset), 84 "FetchRequest": sarama.NewMockFetchResponse(t, 1). 85 SetMessage(mockChannel.topic(), mockChannel.partition(), newestOffset, message), 86 }) 87 88 mockSupport := &mockmultichain.ConsenterSupport{ 89 ChainIDVal: mockChannel.topic(), 90 SharedConfigVal: &mockconfig.Orderer{ 91 KafkaBrokersVal: []string{mockBroker.Addr()}, 92 }, 93 } 94 95 mockMetadata := &cb.Metadata{Value: utils.MarshalOrPanic(&ab.KafkaMetadata{LastOffsetPersisted: newestOffset - 1})} 96 97 _, err := consenter.HandleChain(mockSupport, mockMetadata) 98 assert.NoError(t, err, "Expected the HandleChain call to return without errors") 99 } 100 101 // Test helper functions and mock objects defined here 102 103 var mockConsenter commonConsenter 104 var mockLocalConfig *localconfig.TopLevel 105 var mockBrokerConfig *sarama.Config 106 107 func extractEncodedOffset(marshalledOrdererMetadata []byte) int64 { 108 omd := &cb.Metadata{} 109 _ = proto.Unmarshal(marshalledOrdererMetadata, omd) 110 kmd := &ab.KafkaMetadata{} 111 _ = proto.Unmarshal(omd.GetValue(), kmd) 112 return kmd.LastOffsetPersisted 113 } 114 115 func newMockBrokerConfig(tlsConfig localconfig.TLS, retryOptions localconfig.Retry, kafkaVersion sarama.KafkaVersion, chosenStaticPartition int32) *sarama.Config { 116 brokerConfig := newBrokerConfig(tlsConfig, retryOptions, kafkaVersion, chosenStaticPartition) 117 brokerConfig.ClientID = "test" 118 return brokerConfig 119 } 120 121 func newMockConsenter(brokerConfig *sarama.Config, tlsConfig localconfig.TLS, retryOptions localconfig.Retry, kafkaVersion sarama.KafkaVersion) *consenterImpl { 122 return &consenterImpl{ 123 brokerConfigVal: brokerConfig, 124 tlsConfigVal: tlsConfig, 125 retryOptionsVal: retryOptions, 126 kafkaVersionVal: kafkaVersion, 127 } 128 } 129 130 func newMockConsumerMessage(wrappedMessage *ab.KafkaMessage) *sarama.ConsumerMessage { 131 return &sarama.ConsumerMessage{ 132 Value: sarama.ByteEncoder(utils.MarshalOrPanic(wrappedMessage)), 133 } 134 } 135 136 func newMockEnvelope(content string) *cb.Envelope { 137 return &cb.Envelope{Payload: []byte(content)} 138 } 139 140 func newMockLocalConfig(enableTLS bool, retryOptions localconfig.Retry, verboseLog bool) *localconfig.TopLevel { 141 return &localconfig.TopLevel{ 142 General: localconfig.General{ 143 TLS: localconfig.TLS{ 144 Enabled: enableTLS, 145 }, 146 }, 147 Kafka: localconfig.Kafka{ 148 Retry: retryOptions, 149 Verbose: verboseLog, 150 Version: sarama.V0_9_0_1, 151 }, 152 } 153 } 154 155 func setupTestLogging(logLevel string, verbose bool) { 156 // This call allows us to (a) get the logging backend initialization that 157 // takes place in the `flogging` package, and (b) adjust the verbosity of 158 // the logs when running tests on this package. 159 flogging.SetModuleLevel(pkgLogID, logLevel) 160 161 if verbose { 162 sarama.Logger = log.New(os.Stdout, "[sarama] ", log.Ldate|log.Lmicroseconds|log.Lshortfile) 163 } 164 } 165 166 // Taken from orderer/solo/consensus_test.go 167 func syncQueueMessage(message *cb.Envelope, chain *chainImpl, mockBlockcutter *mockblockcutter.Receiver) { 168 chain.Enqueue(message) 169 mockBlockcutter.Block <- struct{}{} // We'll move past this line (and the function will return) only when the mock blockcutter is about to return 170 } 171 172 func tamperBytes(original []byte) []byte { 173 byteCount := len(original) 174 return original[:byteCount-1] 175 } 176 177 func channelNameForTest(t *testing.T) string { 178 name := strings.Split(fmt.Sprint(t), " ")[18] // w/golang 1.8, use t.Name() 179 return fmt.Sprintf("%s.channel", strings.Replace(strings.ToLower(name), "/", ".", -1)) 180 }