Skip to content

Commit

Permalink
Unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Gilthoniel committed May 12, 2020
1 parent 1b094c6 commit 165efe7
Show file tree
Hide file tree
Showing 5 changed files with 285 additions and 30 deletions.
26 changes: 3 additions & 23 deletions ledger/byzcoin/mod.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,26 +80,6 @@ func NewLedger(m mino.Mino, signer crypto.AggregateSigner) *Ledger {
}
}

// GetValue implements ledger.Ledger.
func (ldgr *Ledger) GetValue(key []byte) (proto.Message, error) {
latest, err := ldgr.bc.GetBlock()
if err != nil {
return nil, err
}

page, err := ldgr.proc.inventory.GetPage(latest.GetIndex())
if err != nil {
return nil, err
}

value, err := page.Read(key)
if err != nil {
return nil, err
}

return value, nil
}

// Listen implements ledger.Ledger. It starts to participate in the blockchain
// and returns an actor that can send transactions.
func (ldgr *Ledger) Listen() (ledger.Actor, error) {
Expand Down Expand Up @@ -133,7 +113,7 @@ func (ldgr *Ledger) Listen() (ledger.Actor, error) {

authority, err := ldgr.governance.GetAuthority(genesis.GetIndex())
if err != nil {
ldgr.initiated <- xerrors.Errorf("couldn't read authority: %v", err)
ldgr.initiated <- xerrors.Errorf("couldn't read chain roster: %v", err)
return
}

Expand All @@ -149,7 +129,7 @@ func (ldgr *Ledger) Listen() (ledger.Actor, error) {
go ldgr.proposeBlocks(bcActor, authority)
}()

return newActor(ldgr, bcActor), err
return newActor(ldgr, bcActor), nil
}

func (ldgr *Ledger) gossipTxs() {
Expand Down Expand Up @@ -334,7 +314,7 @@ func (a actorLedger) HasStarted() <-chan error {
func (a actorLedger) Setup(players mino.Players) error {
authority, ok := players.(crypto.CollectiveAuthority)
if !ok {
return xerrors.Errorf("players must implement '%T'", authority)
return xerrors.Errorf("players must implement 'crypto.CollectiveAuthority'")
}

rosterpb, err := a.encoder.Pack(a.governance.GetAuthorityFactory().New(authority))
Expand Down
206 changes: 206 additions & 0 deletions ledger/byzcoin/mod_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ import (
"bytes"
"context"
"fmt"
"sync"
"testing"
"time"

"github.com/golang/protobuf/proto"
"github.com/stretchr/testify/require"
"go.dedis.ch/fabric/blockchain"
"go.dedis.ch/fabric/consensus/viewchange"
"go.dedis.ch/fabric/crypto"
"go.dedis.ch/fabric/crypto/bls"
"go.dedis.ch/fabric/encoding"
Expand All @@ -20,7 +23,9 @@ import (
"go.dedis.ch/fabric/ledger/transactions"
"go.dedis.ch/fabric/ledger/transactions/basic"
"go.dedis.ch/fabric/mino"
"go.dedis.ch/fabric/mino/gossip"
"go.dedis.ch/fabric/mino/minoch"
"golang.org/x/xerrors"
)

func TestMessages(t *testing.T) {
Expand Down Expand Up @@ -98,6 +103,123 @@ func TestLedger_Basic(t *testing.T) {
require.NoError(t, err)
}

func TestLedger_Listen(t *testing.T) {
ledger := &Ledger{
initiated: make(chan error, 1),
closing: make(chan struct{}),
bc: fakeBlockchain{},
governance: fakeGovernance{},
gossiper: fakeGossiper{},
}

actor, err := ledger.Listen()
<-ledger.initiated
require.NoError(t, err)
require.NotNil(t, actor)
require.NoError(t, actor.Close())

ledger.bc = fakeBlockchain{errListen: xerrors.New("oops")}
_, err = ledger.Listen()
require.EqualError(t, err, "couldn't start the blockchain: oops")

blocks := make(chan blockchain.Block, 1)
blocks <- fakeBlock{index: 1}
ledger.bc = fakeBlockchain{blocks: blocks, errBlock: xerrors.New("oops")}
ledger.initiated = make(chan error, 1)
_, err = ledger.Listen()
require.NoError(t, err)
err = <-ledger.initiated
require.EqualError(t, err, "expect genesis but got block 1")

ledger.bc = fakeBlockchain{}
ledger.governance = fakeGovernance{err: xerrors.New("oops")}
ledger.initiated = make(chan error, 1)
_, err = ledger.Listen()
require.NoError(t, err)
err = <-ledger.initiated
require.EqualError(t, err, "couldn't read chain roster: oops")

ledger.governance = fakeGovernance{}
ledger.gossiper = fakeGossiper{err: xerrors.New("oops")}
ledger.initiated = make(chan error, 1)
_, err = ledger.Listen()
require.NoError(t, err)
err = <-ledger.initiated
require.EqualError(t, err, "couldn't start the gossiper: oops")
}

func TestLedger_GossipTxs(t *testing.T) {
rumors := make(chan gossip.Rumor)

ledger := &Ledger{
closing: make(chan struct{}),
bag: newTxBag(),
gossiper: fakeGossiper{rumors: rumors, err: xerrors.New("oops")},
}

wg := sync.WaitGroup{}
wg.Add(1)
go func() {
ledger.gossipTxs()
wg.Done()
}()

rumors <- fakeTx{id: []byte{0x01}}
rumors <- fakeTx{id: []byte{0x01}}
require.Len(t, ledger.bag.GetAll(), 1)
rumors <- fakeTx{id: []byte{0x02}}
rumors <- fakeTx{id: []byte{0x02}}
require.Len(t, ledger.bag.GetAll(), 2)

close(ledger.closing)
wg.Wait()
}

func TestActor_Setup(t *testing.T) {
actor := actorLedger{
Ledger: &Ledger{
encoder: encoding.NewProtoEncoder(),
proc: newTxProcessor(nil, fakeInventory{}),
governance: fakeGovernance{},
},
bcActor: fakeActor{},
}

err := actor.Setup(fake.NewAuthority(3, fake.NewSigner))
require.NoError(t, err)

err = actor.Setup(mino.NewAddresses())
require.EqualError(t, err, "players must implement 'crypto.CollectiveAuthority'")

actor.encoder = fake.BadPackEncoder{}
err = actor.Setup(fake.NewAuthority(3, fake.NewSigner))
require.EqualError(t, err, "couldn't pack roster: fake error")

actor.encoder = encoding.NewProtoEncoder()
actor.proc = newTxProcessor(nil, fakeInventory{err: xerrors.New("oops")})
err = actor.Setup(fake.NewAuthority(3, fake.NewSigner))
require.EqualError(t, err,
"couldn't store genesis payload: couldn't stage page: oops")

actor.proc = newTxProcessor(nil, fakeInventory{})
actor.bcActor = fakeActor{err: xerrors.New("oops")}
err = actor.Setup(fake.NewAuthority(3, fake.NewSigner))
require.EqualError(t, err, "couldn't initialize the chain: oops")
}

func TestActor_AddTransaction(t *testing.T) {
actor := &actorLedger{
Ledger: &Ledger{gossiper: fakeGossiper{}},
}

err := actor.AddTransaction(fakeTx{})
require.NoError(t, err)

actor.gossiper = fakeGossiper{err: xerrors.New("oops")}
err = actor.AddTransaction(fakeTx{})
require.EqualError(t, err, "couldn't propagate the tx: oops")
}

// -----------------------------------------------------------------------------
// Utility functions

Expand Down Expand Up @@ -157,3 +279,87 @@ func sendTx(t *testing.T, ledger ledger.Ledger, actor ledger.Actor, tx transacti
}
}
}

type fakeBlock struct {
blockchain.Block
index uint64
}

func (b fakeBlock) GetIndex() uint64 {
return b.index
}

func (b fakeBlock) GetHash() []byte {
return []byte{0x12}
}

type fakeBlockchain struct {
blockchain.Blockchain
blocks chan blockchain.Block
errListen error
errBlock error
}

func (bc fakeBlockchain) Listen(blockchain.PayloadProcessor) (blockchain.Actor, error) {
return nil, bc.errListen
}

func (bc fakeBlockchain) GetBlock() (blockchain.Block, error) {
return fakeBlock{}, bc.errBlock
}

func (bc fakeBlockchain) Watch(context.Context) <-chan blockchain.Block {
return bc.blocks
}

type fakeAuthorityFactory struct {
viewchange.AuthorityFactory
}

func (f fakeAuthorityFactory) New(crypto.CollectiveAuthority) viewchange.EvolvableAuthority {
return fake.NewAuthority(3, fake.NewSigner)
}

type fakeGovernance struct {
viewchange.Governance
err error
}

func (gov fakeGovernance) GetAuthorityFactory() viewchange.AuthorityFactory {
return roster.NewRosterFactory(nil, nil)
}

func (gov fakeGovernance) GetAuthority(index uint64) (viewchange.EvolvableAuthority, error) {
return fake.NewAuthority(3, fake.NewSigner), gov.err
}

type fakeGossiper struct {
gossip.Gossiper
rumors chan gossip.Rumor
err error
}

func (g fakeGossiper) Add(gossip.Rumor) error {
return g.err
}

func (g fakeGossiper) Start(mino.Players) error {
return g.err
}

func (g fakeGossiper) Rumors() <-chan gossip.Rumor {
return g.rumors
}

func (g fakeGossiper) Stop() error {
return g.err
}

type fakeActor struct {
blockchain.Actor
err error
}

func (a fakeActor) InitChain(proto.Message, mino.Players) error {
return a.err
}
7 changes: 4 additions & 3 deletions ledger/byzcoin/task.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ func newtaskFactory(m mino.Mino, signer crypto.Signer,
return f, gov
}

// Register registers the factory for the protobuf message.
// Register registers the factory for the protobuf message. If a message has
// already been registered, it will overwritten.
func (f *taskFactory) Register(pb proto.Message, factory basic.TaskFactory) {
key := reflect.TypeOf(pb)
f.registry[key] = factory
Expand All @@ -55,7 +56,7 @@ func (f *taskFactory) FromProto(in proto.Message) (basic.ServerTask, error) {
var err error
in, err = f.encoder.UnmarshalDynamicAny(inAny)
if err != nil {
return nil, err
return nil, xerrors.Errorf("couldn't unmarshal message: %v", err)
}
}

Expand All @@ -67,7 +68,7 @@ func (f *taskFactory) FromProto(in proto.Message) (basic.ServerTask, error) {

task, err := factory.FromProto(in)
if err != nil {
return nil, err
return nil, xerrors.Errorf("couldn't decode task: %v", err)
}

return task, nil
Expand Down
72 changes: 72 additions & 0 deletions ledger/byzcoin/task_test.go
Original file line number Diff line number Diff line change
@@ -1 +1,73 @@
package byzcoin

import (
"reflect"
"testing"

proto "github.com/golang/protobuf/proto"
"github.com/golang/protobuf/ptypes"
"github.com/golang/protobuf/ptypes/empty"
"github.com/golang/protobuf/ptypes/wrappers"
"github.com/stretchr/testify/require"
"go.dedis.ch/fabric/encoding"
"go.dedis.ch/fabric/internal/testing/fake"
"go.dedis.ch/fabric/ledger/transactions/basic"
"golang.org/x/xerrors"
)

func TestTaskFactory_Register(t *testing.T) {
factory := &taskFactory{
registry: make(map[reflect.Type]basic.TaskFactory),
}

factory.Register(&empty.Empty{}, fakeTaskFactory{})
factory.Register(&empty.Empty{}, fakeTaskFactory{})
factory.Register(&wrappers.BoolValue{}, fakeTaskFactory{})
require.Len(t, factory.registry, 2)
}

func TestTaskFactory_FromProto(t *testing.T) {
factory := &taskFactory{
encoder: encoding.NewProtoEncoder(),
registry: make(map[reflect.Type]basic.TaskFactory),
}

factory.Register(&empty.Empty{}, fakeTaskFactory{})

task, err := factory.FromProto(&empty.Empty{})
require.NoError(t, err)
require.NotNil(t, task)

inAny, err := ptypes.MarshalAny(&empty.Empty{})
require.NoError(t, err)
task, err = factory.FromProto(inAny)
require.NoError(t, err)
require.NotNil(t, task)

factory.encoder = fake.BadUnmarshalDynEncoder{}
_, err = factory.FromProto(inAny)
require.EqualError(t, err, "couldn't unmarshal message: fake error")

_, err = factory.FromProto(&wrappers.BoolValue{})
require.EqualError(t, err, "unknown task type '*wrappers.BoolValue'")

factory.Register(&empty.Empty{}, fakeTaskFactory{err: xerrors.New("oops")})
_, err = factory.FromProto(&empty.Empty{})
require.EqualError(t, err, "couldn't decode task: oops")
}

// -----------------------------------------------------------------------------
// Utility functions

type fakeTask struct {
basic.ServerTask
}

type fakeTaskFactory struct {
basic.TaskFactory
err error
}

func (f fakeTaskFactory) FromProto(proto.Message) (basic.ServerTask, error) {
return fakeTask{}, f.err
}
Loading

0 comments on commit 165efe7

Please sign in to comment.