go_study/fabric-main/orderer/common/server/attestationserver_test.go

239 lines
6.5 KiB
Go

/*
Copyright IBM Corp. 2017 All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package server
import (
"context"
"testing"
"time"
cb "github.com/hyperledger/fabric-protos-go/common"
ab "github.com/hyperledger/fabric-protos-go/orderer"
"github.com/hyperledger/fabric/common/ledger/blockledger"
"github.com/hyperledger/fabric/common/ledger/blockledger/fileledger"
"github.com/hyperledger/fabric/common/metrics/disabled"
"github.com/hyperledger/fabric/common/util"
"github.com/hyperledger/fabric/orderer/common/blockcutter"
"github.com/hyperledger/fabric/orderer/common/msgprocessor"
"github.com/hyperledger/fabric/orderer/common/multichannel"
"github.com/hyperledger/fabric/orderer/common/multichannel/mocks"
"github.com/hyperledger/fabric/orderer/consensus"
"github.com/hyperledger/fabric/protoutil"
"github.com/pkg/errors"
"github.com/stretchr/testify/require"
"google.golang.org/grpc"
)
type AttestationServerStream struct {
grpc.ServerStream
ctx context.Context
ServerChan chan *ab.BlockAttestationResponse
}
func NewAttestationServerStream() *AttestationServerStream {
return &AttestationServerStream{
ctx: context.Background(),
ServerChan: make(chan *ab.BlockAttestationResponse, 10),
}
}
func (ss *AttestationServerStream) Context() context.Context {
return ss.ctx
}
func (ss *AttestationServerStream) Send(resp *ab.BlockAttestationResponse) error {
ss.ServerChan <- resp
return nil
}
func (ss *AttestationServerStream) RecvResponse() (*ab.BlockAttestationResponse, error) {
response, more := <-ss.ServerChan
if !more {
return nil, errors.New("empty")
}
return response, nil
}
func newLedgerAndFactory(dir string, chainID string, genesisBlockSys *cb.Block) (blockledger.Factory, blockledger.ReadWriter) {
rlf := newFactory(dir)
rl := newLedger(rlf, chainID, genesisBlockSys)
return rlf, rl
}
func newFactory(dir string) blockledger.Factory {
rlf, err := fileledger.New(dir, &disabled.Provider{})
if err != nil {
panic(err)
}
return rlf
}
func newLedger(rlf blockledger.Factory, chainID string, genesisBlockSys *cb.Block) blockledger.ReadWriter {
rl, err := rlf.GetOrCreate(chainID)
if err != nil {
panic(err)
}
if genesisBlockSys != nil {
err = rl.Append(genesisBlockSys)
if err != nil {
panic(err)
}
}
return rl
}
func mockCrypto() *mocks.SignerSerializer {
return &mocks.SignerSerializer{}
}
type mockChainCluster struct {
*mockChain
}
type mockChain struct {
queue chan *cb.Envelope
cutter blockcutter.Receiver
support consensus.ConsenterSupport
metadata *cb.Metadata
done chan struct{}
}
func (mch *mockChain) Errored() <-chan struct{} {
return nil
}
func (mch *mockChain) Order(env *cb.Envelope, configSeq uint64) error {
mch.queue <- env
return nil
}
func (mch *mockChain) Configure(config *cb.Envelope, configSeq uint64) error {
mch.queue <- config
return nil
}
func (mch *mockChain) WaitReady() error {
return nil
}
func (mch *mockChain) Start() {
go func() {
defer close(mch.done)
for {
msg, ok := <-mch.queue
if !ok {
return
}
chdr, err := protoutil.ChannelHeader(msg)
if err != nil {
logger.Panicf("If a message has arrived to this point, it should already have had header inspected once: %s", err)
}
class := mch.support.ClassifyMsg(chdr)
switch class {
case msgprocessor.ConfigMsg:
batch := mch.support.BlockCutter().Cut()
if batch != nil {
block := mch.support.CreateNextBlock(batch)
mch.support.WriteBlock(block, nil)
}
_, err := mch.support.ProcessNormalMsg(msg)
if err != nil {
logger.Warningf("Discarding bad config message: %s", err)
continue
}
block := mch.support.CreateNextBlock([]*cb.Envelope{msg})
mch.support.WriteConfigBlock(block, nil)
case msgprocessor.NormalMsg:
batches, _ := mch.support.BlockCutter().Ordered(msg)
for _, batch := range batches {
block := mch.support.CreateNextBlock(batch)
mch.support.WriteBlock(block, nil)
}
case msgprocessor.ConfigUpdateMsg:
logger.Panicf("Not expecting msg class ConfigUpdateMsg here")
default:
logger.Panicf("Unsupported msg classification: %v", class)
}
}
}()
}
func (mch *mockChain) Halt() {
close(mch.queue)
}
func handleChainCluster(support consensus.ConsenterSupport, metadata *cb.Metadata) (consensus.Chain, error) {
chain := &mockChain{
queue: make(chan *cb.Envelope),
cutter: support.BlockCutter(),
support: support,
metadata: metadata,
done: make(chan struct{}),
}
return &mockChainCluster{mockChain: chain}, nil
}
func Test_attestationserver_BlockAttestations(t *testing.T) {
ts := util.CreateUtcTimestamp()
channelHeader := &cb.ChannelHeader{
ChannelId: "mychannel",
Timestamp: ts,
}
seekInfo := &ab.SeekInfo{
Start: &ab.SeekPosition{
Type: &ab.SeekPosition_Specified{
Specified: &ab.SeekSpecified{Number: 0},
},
},
Stop: &ab.SeekPosition{
Type: &ab.SeekPosition_Specified{
Specified: &ab.SeekSpecified{Number: 0},
},
},
}
envelope := &cb.Envelope{}
payload := &cb.Payload{
Header: &cb.Header{
ChannelHeader: protoutil.MarshalOrPanic(channelHeader),
SignatureHeader: protoutil.MarshalOrPanic(&cb.SignatureHeader{}),
},
Data: protoutil.MarshalOrPanic(seekInfo),
}
envelope.Payload = protoutil.MarshalOrPanic(payload)
// TODO This is preparation work for the BFT block puller. Right now it is used only in unit tests.
// We need to update these tests.
t.Run("Complete block attestation is successfully", func(t *testing.T) {
t.Skip("Work in progress. BFT Block Puller preparatory work. This test needs to be rewritten.")
// TODO
})
t.Run("Block attestation returns with BAD_REQUEST when envelope is malformed", func(t *testing.T) {
mockstream := NewAttestationServerStream()
asr := NewAttestationService(&multichannel.Registrar{}, &disabled.Provider{}, nil, time.Second, false, false)
err := asr.BlockAttestations(&cb.Envelope{}, mockstream)
require.NoError(t, err)
StatusResponse, _ := mockstream.RecvResponse()
require.Equal(t, cb.Status_BAD_REQUEST, StatusResponse.GetStatus())
})
t.Run("Block attestion returns with NOTFOUND when custom policy check fails", func(t *testing.T) {
mockstream := NewAttestationServerStream()
asr := NewAttestationService(&multichannel.Registrar{}, &disabled.Provider{}, nil, time.Second, false, false)
err := asr.BlockAttestations(envelope, mockstream)
require.NoError(t, err)
StatusResponse, _ := mockstream.RecvResponse()
require.Equal(t, cb.Status_NOT_FOUND, StatusResponse.GetStatus())
})
}