assertAllInvarients changes, Operation reorg
This commit is contained in:
parent
1ee6c3295d
commit
ff327049ee
|
@ -13,16 +13,16 @@ import (
|
||||||
// The simulator will then halt and print the logs.
|
// The simulator will then halt and print the logs.
|
||||||
type Invariant func(app *baseapp.BaseApp) error
|
type Invariant func(app *baseapp.BaseApp) error
|
||||||
|
|
||||||
// assertAllInvariants asserts a list of provided invariants against
|
// group of Invarient
|
||||||
// application state
|
type Invariants []Invariant
|
||||||
func assertAllInvariants(t *testing.T, app *baseapp.BaseApp,
|
|
||||||
invariants []Invariant, where string, displayLogs func()) {
|
|
||||||
|
|
||||||
for i := 0; i < len(invariants); i++ {
|
// assertAll asserts the all invariants against application state
|
||||||
err := invariants[i](app)
|
func (invs Invariants) assertAll(t *testing.T, app *baseapp.BaseApp,
|
||||||
if err != nil {
|
event string, displayLogs func()) {
|
||||||
fmt.Printf("Invariants broken after %s\n", where)
|
|
||||||
fmt.Println(err.Error())
|
for i := 0; i < len(invs); i++ {
|
||||||
|
if err := invs[i](app); err != nil {
|
||||||
|
fmt.Printf("Invariants broken after %s\n%s\n", event, err.Error())
|
||||||
displayLogs()
|
displayLogs()
|
||||||
t.Fatal()
|
t.Fatal()
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package simulation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||||
|
@ -24,6 +25,41 @@ type Operation func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||||
// queue of operations
|
// queue of operations
|
||||||
type OperationQueue map[int][]Operation
|
type OperationQueue map[int][]Operation
|
||||||
|
|
||||||
|
// adds all future operations into the operation queue.
|
||||||
|
func queueOperations(queuedOps OperationQueue,
|
||||||
|
queuedTimeOps []FutureOperation,
|
||||||
|
futureOps []FutureOperation) {
|
||||||
|
|
||||||
|
if futureOps == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, futureOp := range futureOps {
|
||||||
|
if futureOp.BlockHeight != 0 {
|
||||||
|
if val, ok := queuedOps[futureOp.BlockHeight]; ok {
|
||||||
|
queuedOps[futureOp.BlockHeight] = append(val, futureOp.Op)
|
||||||
|
} else {
|
||||||
|
queuedOps[futureOp.BlockHeight] = []Operation{futureOp.Op}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Replace with proper sorted data structure, so don't have the
|
||||||
|
// copy entire slice
|
||||||
|
index := sort.Search(
|
||||||
|
len(queuedTimeOps),
|
||||||
|
func(i int) bool {
|
||||||
|
return queuedTimeOps[i].BlockTime.After(futureOp.BlockTime)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
queuedTimeOps = append(queuedTimeOps, FutureOperation{})
|
||||||
|
copy(queuedTimeOps[index+1:], queuedTimeOps[index:])
|
||||||
|
queuedTimeOps[index] = futureOp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//________________________________________________________________________
|
||||||
|
|
||||||
// FutureOperation is an operation which will be ran at the beginning of the
|
// FutureOperation is an operation which will be ran at the beginning of the
|
||||||
// provided BlockHeight. If both a BlockHeight and BlockTime are specified, it
|
// provided BlockHeight. If both a BlockHeight and BlockTime are specified, it
|
||||||
// will use the BlockHeight. In the (likely) event that multiple operations
|
// will use the BlockHeight. In the (likely) event that multiple operations
|
||||||
|
@ -34,6 +70,8 @@ type FutureOperation struct {
|
||||||
Op Operation
|
Op Operation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//________________________________________________________________________
|
||||||
|
|
||||||
// WeightedOperation is an operation with associated weight.
|
// WeightedOperation is an operation with associated weight.
|
||||||
// This is used to bias the selection operation within the simulator.
|
// This is used to bias the selection operation within the simulator.
|
||||||
type WeightedOperation struct {
|
type WeightedOperation struct {
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"sort"
|
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -27,7 +26,7 @@ type RandSetup func(r *rand.Rand, accounts []Account)
|
||||||
func Simulate(t *testing.T, app *baseapp.BaseApp,
|
func Simulate(t *testing.T, app *baseapp.BaseApp,
|
||||||
appStateFn func(r *rand.Rand, accs []Account) json.RawMessage,
|
appStateFn func(r *rand.Rand, accs []Account) json.RawMessage,
|
||||||
ops []WeightedOperation, setups []RandSetup,
|
ops []WeightedOperation, setups []RandSetup,
|
||||||
invariants []Invariant, numBlocks int, blockSize int, commit bool) error {
|
invariants Invariants, numBlocks int, blockSize int, commit bool) error {
|
||||||
|
|
||||||
time := time.Now().UnixNano()
|
time := time.Now().UnixNano()
|
||||||
return SimulateFromSeed(t, app, appStateFn, time, ops,
|
return SimulateFromSeed(t, app, appStateFn, time, ops,
|
||||||
|
@ -55,7 +54,7 @@ func initChain(r *rand.Rand, params Params,
|
||||||
// operations, testing the provided invariants, but using the provided seed.
|
// operations, testing the provided invariants, but using the provided seed.
|
||||||
func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp,
|
func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp,
|
||||||
appStateFn func(r *rand.Rand, accs []Account) json.RawMessage,
|
appStateFn func(r *rand.Rand, accs []Account) json.RawMessage,
|
||||||
seed int64, ops []WeightedOperation, setups []RandSetup, invariants []Invariant,
|
seed int64, ops WeightedOperations, setups []RandSetup, invariants Invariants,
|
||||||
numBlocks int, blockSize int, commit bool) (simError error) {
|
numBlocks int, blockSize int, commit bool) (simError error) {
|
||||||
|
|
||||||
// in case we have to end early, don't os.Exit so that we can run cleanup code.
|
// in case we have to end early, don't os.Exit so that we can run cleanup code.
|
||||||
|
@ -154,7 +153,7 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp,
|
||||||
|
|
||||||
if testingMode {
|
if testingMode {
|
||||||
// Make sure invariants hold at beginning of block
|
// Make sure invariants hold at beginning of block
|
||||||
assertAllInvariants(t, app, invariants, "BeginBlock", displayLogs)
|
invariants.assertAll(t, app, "BeginBlock", displayLogs)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := app.NewContext(false, header)
|
ctx := app.NewContext(false, header)
|
||||||
|
@ -171,15 +170,15 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp,
|
||||||
logWriter, displayLogs, event)
|
logWriter, displayLogs, event)
|
||||||
if testingMode && onOperation {
|
if testingMode && onOperation {
|
||||||
// Make sure invariants hold at end of queued operations
|
// Make sure invariants hold at end of queued operations
|
||||||
assertAllInvariants(t, app, invariants, "QueuedOperations", displayLogs)
|
invariants.assertAll(t, app, "QueuedOperations", displayLogs)
|
||||||
}
|
}
|
||||||
|
|
||||||
logWriter("Standard operations")
|
logWriter("Standard operations")
|
||||||
operations := blockSimulator(r, app, ctx, accs, header, logWriter)
|
operations := blockSimulator(r, app, ctx, accs, header, logWriter)
|
||||||
opCount += operations + numQueuedOpsRan + numQueuedTimeOpsRan
|
opCount += operations + numQueuedOpsRan + numQueuedTimeOpsRan
|
||||||
if testingMode {
|
if testingMode {
|
||||||
// Make sure invariants hold at end of block
|
// Make sure invariants hold at the operation
|
||||||
assertAllInvariants(t, app, invariants, "StandardOperations", displayLogs)
|
invariants.assertAll(t, app, "StandardOperations", displayLogs)
|
||||||
}
|
}
|
||||||
|
|
||||||
res := app.EndBlock(abci.RequestEndBlock{})
|
res := app.EndBlock(abci.RequestEndBlock{})
|
||||||
|
@ -193,7 +192,7 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp,
|
||||||
|
|
||||||
if testingMode {
|
if testingMode {
|
||||||
// Make sure invariants hold at end of block
|
// Make sure invariants hold at end of block
|
||||||
assertAllInvariants(t, app, invariants, "EndBlock", displayLogs)
|
invariants.assertAll(t, app, "EndBlock", displayLogs)
|
||||||
}
|
}
|
||||||
if commit {
|
if commit {
|
||||||
app.Commit()
|
app.Commit()
|
||||||
|
@ -235,7 +234,7 @@ type blockSimFn func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||||
// Returns a function to simulate blocks. Written like this to avoid constant
|
// Returns a function to simulate blocks. Written like this to avoid constant
|
||||||
// parameters being passed everytime, to minimize memory overhead
|
// parameters being passed everytime, to minimize memory overhead
|
||||||
func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, params Params,
|
func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, params Params,
|
||||||
event func(string), invariants []Invariant, ops WeightedOperations,
|
event func(string), invariants Invariants, ops WeightedOperations,
|
||||||
operationQueue map[int][]Operation, timeOperationQueue []FutureOperation,
|
operationQueue map[int][]Operation, timeOperationQueue []FutureOperation,
|
||||||
totalNumBlocks int, avgBlockSize int, displayLogs func()) blockSimFn {
|
totalNumBlocks int, avgBlockSize int, displayLogs func()) blockSimFn {
|
||||||
|
|
||||||
|
@ -262,8 +261,8 @@ func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, params
|
||||||
queueOperations(operationQueue, timeOperationQueue, futureOps)
|
queueOperations(operationQueue, timeOperationQueue, futureOps)
|
||||||
if testingMode {
|
if testingMode {
|
||||||
if onOperation {
|
if onOperation {
|
||||||
assertAllInvariants(t, app, invariants,
|
eventStr := fmt.Sprintf("operation: %v", logUpdate)
|
||||||
fmt.Sprintf("operation: %v", logUpdate), displayLogs)
|
invariants.assertAll(t, app, eventStr, displayLogs)
|
||||||
}
|
}
|
||||||
if opCount%50 == 0 {
|
if opCount%50 == 0 {
|
||||||
fmt.Printf("\rSimulating... block %d/%d, operation %d/%d. ",
|
fmt.Printf("\rSimulating... block %d/%d, operation %d/%d. ",
|
||||||
|
@ -276,37 +275,6 @@ func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, params
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// adds all future operations into the operation queue.
|
|
||||||
func queueOperations(queuedOperations map[int][]Operation,
|
|
||||||
queuedTimeOperations []FutureOperation,
|
|
||||||
futureOperations []FutureOperation) {
|
|
||||||
|
|
||||||
if futureOperations == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, futureOp := range futureOperations {
|
|
||||||
if futureOp.BlockHeight != 0 {
|
|
||||||
if val, ok := queuedOperations[futureOp.BlockHeight]; ok {
|
|
||||||
queuedOperations[futureOp.BlockHeight] = append(val, futureOp.Op)
|
|
||||||
} else {
|
|
||||||
queuedOperations[futureOp.BlockHeight] = []Operation{futureOp.Op}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// TODO: Replace with proper sorted data structure, so don't have the copy entire slice
|
|
||||||
index := sort.Search(
|
|
||||||
len(queuedTimeOperations),
|
|
||||||
func(i int) bool {
|
|
||||||
return queuedTimeOperations[i].BlockTime.After(futureOp.BlockTime)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
queuedTimeOperations = append(queuedTimeOperations, FutureOperation{})
|
|
||||||
copy(queuedTimeOperations[index+1:], queuedTimeOperations[index:])
|
|
||||||
queuedTimeOperations[index] = futureOp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// nolint: errcheck
|
// nolint: errcheck
|
||||||
func runQueuedOperations(queueOps map[int][]Operation,
|
func runQueuedOperations(queueOps map[int][]Operation,
|
||||||
height int, tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
height int, tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||||
|
@ -318,8 +286,8 @@ func runQueuedOperations(queueOps map[int][]Operation,
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
numOps := len(queuedOp)
|
numOpsRan = len(queuedOp)
|
||||||
for i := 0; i < numOps; i++ {
|
for i := 0; i < numOpsRan; i++ {
|
||||||
// For now, queued operations cannot queue more operations.
|
// For now, queued operations cannot queue more operations.
|
||||||
// If a need arises for us to support queued messages to queue more messages, this can
|
// If a need arises for us to support queued messages to queue more messages, this can
|
||||||
// be changed.
|
// be changed.
|
||||||
|
@ -331,7 +299,7 @@ func runQueuedOperations(queueOps map[int][]Operation,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete(queueOps, height)
|
delete(queueOps, height)
|
||||||
return numOps
|
return numOpsRan
|
||||||
}
|
}
|
||||||
|
|
||||||
func runQueuedTimeOperations(queueOps []FutureOperation,
|
func runQueuedTimeOperations(queueOps []FutureOperation,
|
||||||
|
|
Loading…
Reference in New Issue