142 lines
4.8 KiB
Go
142 lines
4.8 KiB
Go
package builders
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
|
|
"github.com/filecoin-project/go-address"
|
|
"github.com/filecoin-project/lotus/chain/state"
|
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
|
"github.com/ipfs/go-cid"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// Asserter offers useful assertions to verify outcomes at various stages of
|
|
// the test vector creation.
|
|
type Asserter struct {
|
|
*require.Assertions
|
|
|
|
b *Builder
|
|
stage Stage
|
|
}
|
|
|
|
var _ require.TestingT = &Asserter{}
|
|
|
|
func newAsserter(b *Builder, stage Stage) *Asserter {
|
|
a := &Asserter{stage: stage, b: b}
|
|
a.Assertions = require.New(a)
|
|
return a
|
|
}
|
|
|
|
// In is assert fluid version of require.Contains. It inverts the argument order,
|
|
// such that the admissible set can be supplied through assert variadic argument.
|
|
func (a *Asserter) In(v interface{}, set ...interface{}) {
|
|
a.Contains(set, v, "set %v does not contain element %v", set, v)
|
|
}
|
|
|
|
// BalanceEq verifies that the balance of the address equals the expected one.
|
|
func (a *Asserter) BalanceEq(addr address.Address, expected abi.TokenAmount) {
|
|
actor, err := a.b.StateTree.GetActor(addr)
|
|
a.NoError(err, "failed to fetch actor %s from state", addr)
|
|
a.Equal(expected, actor.Balance, "balances mismatch for address %s", addr)
|
|
}
|
|
|
|
// NonceEq verifies that the nonce of the actor equals the expected one.
|
|
func (a *Asserter) NonceEq(addr address.Address, expected uint64) {
|
|
actor, err := a.b.StateTree.GetActor(addr)
|
|
a.NoError(err, "failed to fetch actor %s from state", addr)
|
|
a.Equal(expected, actor.Nonce, "expected actor %s nonce: %d, got: %d", addr, expected, actor.Nonce)
|
|
}
|
|
|
|
// HeadEq verifies that the head of the actor equals the expected one.
|
|
func (a *Asserter) HeadEq(addr address.Address, expected cid.Cid) {
|
|
actor, err := a.b.StateTree.GetActor(addr)
|
|
a.NoError(err, "failed to fetch actor %s from state", addr)
|
|
a.Equal(expected, actor.Head, "expected actor %s head: %v, got: %v", addr, expected, actor.Head)
|
|
}
|
|
|
|
// ActorExists verifies that the actor exists in the state tree.
|
|
func (a *Asserter) ActorExists(addr address.Address) {
|
|
_, err := a.b.StateTree.GetActor(addr)
|
|
a.NoError(err, "expected no error while looking up actor %s", addr)
|
|
}
|
|
|
|
// ActorExists verifies that the actor is absent from the state tree.
|
|
func (a *Asserter) ActorMissing(addr address.Address) {
|
|
_, err := a.b.StateTree.GetActor(addr)
|
|
a.Error(err, "expected error while looking up actor %s", addr)
|
|
}
|
|
|
|
// EveryMessageResultSatisfies verifies that every message result satisfies the
|
|
// provided predicate.
|
|
func (a *Asserter) EveryMessageResultSatisfies(predicate ApplyRetPredicate, except ...*ApplicableMessage) {
|
|
exceptm := make(map[*ApplicableMessage]struct{}, len(except))
|
|
for _, am := range except {
|
|
exceptm[am] = struct{}{}
|
|
}
|
|
for i, m := range a.b.Messages.messages {
|
|
if _, ok := exceptm[m]; ok {
|
|
continue
|
|
}
|
|
err := predicate(m.Result)
|
|
a.NoError(err, "message result predicate failed on message %d: %s", i, err)
|
|
}
|
|
}
|
|
|
|
// EveryMessageSenderSatisfies verifies that the sender actors of the supplied
|
|
// messages match a condition.
|
|
//
|
|
// This function groups ApplicableMessages by sender actor, and calls the
|
|
// predicate for each unique sender, passing in the initial state (when
|
|
// preconditions were committed), the final state (could be nil), and the
|
|
// ApplicableMessages themselves.
|
|
func (a *Asserter) MessageSendersSatisfy(predicate ActorPredicate, ams ...*ApplicableMessage) {
|
|
bysender := make(map[AddressHandle][]*ApplicableMessage, len(ams))
|
|
for _, am := range ams {
|
|
h := a.b.Actors.HandleFor(am.Message.From)
|
|
bysender[h] = append(bysender[h], am)
|
|
}
|
|
// we now have messages organized by unique senders.
|
|
for sender, amss := range bysender {
|
|
// get precondition state
|
|
pretree, err := state.LoadStateTree(a.b.Stores.CBORStore, a.b.PreRoot)
|
|
a.NoError(err)
|
|
prestate, err := pretree.GetActor(sender.Robust)
|
|
a.NoError(err)
|
|
|
|
// get postcondition state; if actor has been deleted, we store a nil.
|
|
poststate, _ := a.b.StateTree.GetActor(sender.Robust)
|
|
|
|
// invoke predicate.
|
|
err = predicate(sender, prestate, poststate, amss)
|
|
a.NoError(err, "'every sender actor' predicate failed for sender %s: %s", sender, err)
|
|
}
|
|
}
|
|
|
|
// EveryMessageSenderSatisfies is sugar for MessageSendersSatisfy(predicate, Messages.All()),
|
|
// but supports an exclusion set to restrict the messages that will actually be asserted.
|
|
func (a *Asserter) EveryMessageSenderSatisfies(predicate ActorPredicate, except ...*ApplicableMessage) {
|
|
ams := a.b.Messages.All()
|
|
if len(except) > 0 {
|
|
filtered := ams[:0]
|
|
for _, ex := range except {
|
|
for _, am := range ams {
|
|
if am == ex {
|
|
continue
|
|
}
|
|
filtered = append(filtered, am)
|
|
}
|
|
}
|
|
ams = filtered
|
|
}
|
|
a.MessageSendersSatisfy(predicate, ams...)
|
|
}
|
|
|
|
func (a *Asserter) FailNow() {
|
|
os.Exit(1)
|
|
}
|
|
|
|
func (a *Asserter) Errorf(format string, args ...interface{}) {
|
|
fmt.Printf("%s: "+format, append([]interface{}{a.stage}, args...))
|
|
}
|