github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/internal/pkg/gateway/event/iterator_test.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 SPDX-License-Identifier: Apache-2.0 4 */ 5 6 package event_test 7 8 import ( 9 "fmt" 10 "testing" 11 "time" 12 13 "github.com/golang/protobuf/proto" 14 "github.com/golang/protobuf/ptypes/timestamp" 15 "github.com/hechain20/hechain/common/ledger" 16 "github.com/hechain20/hechain/internal/pkg/gateway/event" 17 "github.com/hechain20/hechain/internal/pkg/gateway/event/mocks" 18 "github.com/hechain20/hechain/protoutil" 19 "github.com/hyperledger/fabric-protos-go/common" 20 "github.com/hyperledger/fabric-protos-go/gateway" 21 "github.com/hyperledger/fabric-protos-go/peer" 22 "github.com/pkg/errors" 23 "github.com/stretchr/testify/require" 24 ) 25 26 //go:generate counterfeiter -o mocks/resultsiterator.go --fake-name ResultsIterator . mockResultsIterator 27 type mockResultsIterator interface { 28 ledger.ResultsIterator 29 } 30 31 func TestIterators(t *testing.T) { 32 now := time.Now() 33 transactionId := "TRANSACTION_ID" 34 35 chaincodeEvent := &peer.ChaincodeEvent{ 36 ChaincodeId: "CHAINCODE_ID", 37 TxId: transactionId, 38 EventName: "EVENT_NAME", 39 Payload: []byte("PAYLOAD"), 40 } 41 42 txEnvelope := &common.Envelope{ 43 Payload: protoutil.MarshalOrPanic(&common.Payload{ 44 Header: &common.Header{ 45 ChannelHeader: protoutil.MarshalOrPanic(&common.ChannelHeader{ 46 Type: int32(common.HeaderType_ENDORSER_TRANSACTION), 47 Timestamp: ×tamp.Timestamp{ 48 Seconds: now.Unix(), 49 Nanos: int32(now.Nanosecond()), 50 }, 51 TxId: transactionId, 52 }), 53 }, 54 Data: protoutil.MarshalOrPanic(&peer.Transaction{ 55 Actions: []*peer.TransactionAction{ 56 { 57 Payload: protoutil.MarshalOrPanic(&peer.ChaincodeActionPayload{ 58 Action: &peer.ChaincodeEndorsedAction{ 59 ProposalResponsePayload: protoutil.MarshalOrPanic(&peer.ProposalResponsePayload{ 60 Extension: protoutil.MarshalOrPanic(&peer.ChaincodeAction{ 61 Events: protoutil.MarshalOrPanic(chaincodeEvent), 62 }), 63 }), 64 }, 65 }), 66 }, 67 }, 68 }), 69 }), 70 } 71 72 blockProto := &common.Block{ 73 Header: &common.BlockHeader{ 74 Number: 1337, 75 }, 76 Metadata: &common.BlockMetadata{ 77 Metadata: [][]byte{ 78 nil, 79 nil, 80 { 81 byte(peer.TxValidationCode_MVCC_READ_CONFLICT), 82 byte(peer.TxValidationCode_VALID), 83 byte(peer.TxValidationCode_VALID), 84 }, 85 nil, 86 nil, 87 }, 88 }, 89 Data: &common.BlockData{ 90 Data: [][]byte{ 91 protoutil.MarshalOrPanic(txEnvelope), 92 protoutil.MarshalOrPanic(txEnvelope), 93 protoutil.MarshalOrPanic(&common.Envelope{ 94 Payload: protoutil.MarshalOrPanic(&common.Payload{ 95 Header: &common.Header{ 96 ChannelHeader: protoutil.MarshalOrPanic(&common.ChannelHeader{ 97 Type: int32(common.HeaderType_CONFIG_UPDATE), 98 }), 99 }, 100 }), 101 }), 102 }, 103 }, 104 } 105 106 const invalidTxIndex = 0 107 const validTxIndex = 1 108 109 assertExpectedBlock := func(t *testing.T, block *event.Block) { 110 require.NotNil(t, block, "block") 111 require.EqualValues(t, blockProto.GetHeader().GetNumber(), block.Number(), "block.Number()") 112 113 transactions, err := block.Transactions() 114 require.NoError(t, err, "Transactions()") 115 require.Len(t, transactions, 2, "transactions") 116 117 for txIndex, transaction := range transactions { 118 require.Equal(t, block, transaction.Block(), "transaction[%d].Block()", txIndex) 119 require.Equal(t, transactionId, transaction.ID(), "transaction[%d].ID()", txIndex) 120 require.EqualValues(t, now.Unix(), transaction.Timestamp().Seconds, "transaction[%d].Timestamp.Seconds", txIndex) 121 require.EqualValues(t, now.Nanosecond(), transaction.Timestamp().Nanos, "transaction[%d].Tomestamp.Nanos", txIndex) 122 123 events, err := transaction.ChaincodeEvents() 124 require.NoError(t, err, "ChaincodeEvents()") 125 require.Len(t, events, 1, "chaincodeEvents") 126 127 for eventIndex, event := range events { 128 require.Equal(t, transaction, event.Transaction(), "transaction[%d].ChaincodeEvents()[%d].Transaction()", txIndex, eventIndex) 129 require.Equal(t, chaincodeEvent.GetChaincodeId(), event.ChaincodeID(), "transaction[%d].ChaincodeEvents()[%d].ChaincodeID()", txIndex, eventIndex) 130 require.Equal(t, chaincodeEvent.GetEventName(), event.EventName(), "transaction[%d].ChaincodeEvents()[%d].EventName()", txIndex, eventIndex) 131 require.EqualValues(t, chaincodeEvent.GetPayload(), event.Payload(), "transaction[%d].ChaincodeEvents()[%d].Payload()", txIndex, eventIndex) 132 require.True(t, proto.Equal(chaincodeEvent, event.ProtoMessage()), "transaction[%d].ChaincodeEvents()[%d].ProtoMessage(): %v", txIndex, eventIndex, event.ProtoMessage()) 133 } 134 } 135 } 136 137 t.Run("BlockIterator", func(t *testing.T) { 138 t.Run("Next", func(t *testing.T) { 139 t.Run("returns error from wrapped iterator", func(t *testing.T) { 140 resultIter := &mocks.ResultsIterator{} 141 resultIter.NextReturns(nil, errors.New("MY_ERROR")) 142 143 blockIter := event.NewBlockIterator(resultIter) 144 _, err := blockIter.Next() 145 146 require.ErrorContains(t, err, "MY_ERROR") 147 }) 148 149 t.Run("returns error if wrapped iterator returns unexpected type", func(t *testing.T) { 150 resultIter := &mocks.ResultsIterator{} 151 result := &common.Envelope{} 152 resultIter.NextReturns(result, nil) 153 154 blockIter := event.NewBlockIterator(resultIter) 155 _, err := blockIter.Next() 156 157 require.ErrorContains(t, err, fmt.Sprintf("%T", result)) 158 }) 159 160 t.Run("returns a block with no transactions", func(t *testing.T) { 161 resultIter := &mocks.ResultsIterator{} 162 result := &common.Block{ 163 Header: &common.BlockHeader{ 164 Number: 418, 165 }, 166 } 167 resultIter.NextReturns(result, nil) 168 169 blockIter := event.NewBlockIterator(resultIter) 170 block, err := blockIter.Next() 171 172 require.NoError(t, err, "Next()") 173 require.NotNil(t, block, "block") 174 require.EqualValues(t, result.GetHeader().GetNumber(), block.Number(), "Number()") 175 176 transactions, err := block.Transactions() 177 require.NoError(t, err, "Transactions()") 178 require.Len(t, transactions, 0, "transactions") 179 }) 180 181 t.Run("returns a block with invalid transaction", func(t *testing.T) { 182 resultIter := &mocks.ResultsIterator{} 183 resultIter.NextReturns(blockProto, nil) 184 185 blockIter := event.NewBlockIterator(resultIter) 186 block, err := blockIter.Next() 187 188 require.NoError(t, err, "Next()") 189 assertExpectedBlock(t, block) 190 191 transactions, _ := block.Transactions() 192 transaction := transactions[invalidTxIndex] 193 require.Equal(t, peer.TxValidationCode_MVCC_READ_CONFLICT, transaction.Status()) 194 require.False(t, transaction.Valid(), "Valid()") 195 }) 196 197 t.Run("returns a block with valid transaction", func(t *testing.T) { 198 resultIter := &mocks.ResultsIterator{} 199 resultIter.NextReturns(blockProto, nil) 200 201 blockIter := event.NewBlockIterator(resultIter) 202 block, err := blockIter.Next() 203 204 require.NoError(t, err, "Next()") 205 assertExpectedBlock(t, block) 206 207 transactions, _ := block.Transactions() 208 transaction := transactions[validTxIndex] 209 require.Equal(t, peer.TxValidationCode_VALID, transaction.Status()) 210 require.True(t, transaction.Valid(), "Valid()") 211 }) 212 }) 213 214 t.Run("Close", func(t *testing.T) { 215 t.Run("closes wrapped iterator", func(t *testing.T) { 216 resultIter := &mocks.ResultsIterator{} 217 218 blockIter := event.NewBlockIterator(resultIter) 219 blockIter.Close() 220 221 require.Equal(t, 1, resultIter.CloseCallCount()) 222 }) 223 }) 224 }) 225 226 t.Run("ChaincodeEventsIterator", func(t *testing.T) { 227 t.Run("Next", func(t *testing.T) { 228 t.Run("returns error from wrapped iterator", func(t *testing.T) { 229 resultIter := &mocks.ResultsIterator{} 230 resultIter.NextReturns(nil, errors.New("MY_ERROR")) 231 232 eventsIter := event.NewChaincodeEventsIterator(resultIter) 233 _, err := eventsIter.Next() 234 235 require.ErrorContains(t, err, "MY_ERROR") 236 }) 237 }) 238 239 t.Run("only returns events for valid transactions", func(t *testing.T) { 240 resultIter := &mocks.ResultsIterator{} 241 resultIter.NextReturns(blockProto, nil) 242 243 eventsIter := event.NewChaincodeEventsIterator(resultIter) 244 actual, err := eventsIter.Next() 245 246 require.NoError(t, err, "Next()") 247 require.NotNil(t, actual, "events") 248 249 expected := &gateway.ChaincodeEventsResponse{ 250 BlockNumber: blockProto.GetHeader().GetNumber(), 251 Events: []*peer.ChaincodeEvent{ 252 chaincodeEvent, 253 }, 254 } 255 require.True(t, proto.Equal(expected, actual), "ChaincodeEventsResponse: %v", actual) 256 }) 257 258 t.Run("skips blocks with no valid chaincode events", func(t *testing.T) { 259 emptyBlock := &common.Block{ 260 Header: &common.BlockHeader{ 261 Number: 418, 262 }, 263 } 264 resultIter := &mocks.ResultsIterator{} 265 resultIter.NextReturnsOnCall(0, emptyBlock, nil) 266 resultIter.NextReturnsOnCall(1, blockProto, nil) 267 268 eventsIter := event.NewChaincodeEventsIterator(resultIter) 269 actual, err := eventsIter.Next() 270 271 require.NoError(t, err, "Next()") 272 require.NotNil(t, actual, "events") 273 274 expected := &gateway.ChaincodeEventsResponse{ 275 BlockNumber: blockProto.GetHeader().GetNumber(), 276 Events: []*peer.ChaincodeEvent{ 277 chaincodeEvent, 278 }, 279 } 280 require.True(t, proto.Equal(expected, actual), "ChaincodeEventsResponse: %v", actual) 281 }) 282 283 t.Run("Close", func(t *testing.T) { 284 t.Run("closes wrapped iterator", func(t *testing.T) { 285 resultIter := &mocks.ResultsIterator{} 286 287 eventsIter := event.NewChaincodeEventsIterator(resultIter) 288 eventsIter.Close() 289 290 require.Equal(t, 1, resultIter.CloseCallCount()) 291 }) 292 }) 293 }) 294 }