Skip to content

Commit

Permalink
fix: add working sims tests
Browse files Browse the repository at this point in the history
  • Loading branch information
NagaTulasi committed Sep 30, 2024
1 parent 36d23ae commit 4016b10
Show file tree
Hide file tree
Showing 8 changed files with 854 additions and 22 deletions.
149 changes: 149 additions & 0 deletions .github/workflows/sims.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
name: Sims
# Sims workflow runs multiple types of simulations (nondeterminism, import-export, after-import, multi-seed-short)
# This workflow will run on all Pull Requests, if a .go, .mod or .sum file have been changed
on:
pull_request:
push:
branches:
- main

concurrency:
group: ci-${{ github.ref }}-sims
cancel-in-progress: true

jobs:
build:
permissions:
contents: read # for actions/checkout to fetch code
runs-on: ubuntu-latest
if: "!contains(github.event.head_commit.message, 'skip-sims')"
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: "1.21"
check-latest: true
- run: make -C simapp build
- name: Install runsim
run: go install github.com/cosmos/tools/cmd/[email protected]
- uses: actions/cache@v3
with:
path: ~/go/bin
key: ${{ runner.os }}-go-runsim-binary

test-sim-nondeterminism:
runs-on: ubuntu-latest
needs: [build]
timeout-minutes: 60
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: "1.21"
check-latest: true
- uses: actions/cache@v3
with:
path: ~/go/bin
key: ${{ runner.os }}-go-runsim-binary
- name: test-sim-import-export
run: |
make test-sim-nondeterminism
test-sim-import-export:
runs-on: ubuntu-latest
needs: [build]
timeout-minutes: 60
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: "1.21"
check-latest: true
- uses: actions/cache@v3
with:
path: ~/go/bin
key: ${{ runner.os }}-go-runsim-binary
- name: test-sim-import-export
run: |
make test-sim-import-export
test-sim-after-import:
runs-on: ubuntu-latest
needs: [build]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: "1.21"
check-latest: true
- uses: actions/cache@v3
with:
path: ~/go/bin
key: ${{ runner.os }}-go-runsim-binary
- name: test-sim-after-import
run: |
make test-sim-after-import
test-sim-multi-seed-short:
runs-on: ubuntu-latest
needs: [build]
timeout-minutes: 60
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: "1.21"
check-latest: true
- uses: actions/cache@v3
with:
path: ~/go/bin
key: ${{ runner.os }}-go-runsim-binary
- name: test-sim-multi-seed-short
run: |
make test-sim-multi-seed-short
sims-notify-success:
needs:
[test-sim-multi-seed-short, test-sim-after-import, test-sim-import-export]
runs-on: ubuntu-latest
if: ${{ success() }}
steps:
- name: Check out repository
uses: actions/checkout@v3
- name: Get previous workflow status
uses: ./.github/actions/last-workflow-status
id: last_status
with:
github_token: ${{ secrets.GITHUB_TOKEN }}

- name: Notify Slack on success
if: ${{ steps.last_status.outputs.last_status == 'failure' }}
uses: rtCamp/[email protected]
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACK_CHANNEL: sdk-sims
SLACK_USERNAME: Sim Tests
SLACK_ICON_EMOJI: ":white_check_mark:"
SLACK_COLOR: good
SLACK_MESSAGE: Sims are passing
SLACK_FOOTER: ""

sims-notify-failure:
permissions:
contents: none
needs:
[test-sim-multi-seed-short, test-sim-after-import, test-sim-import-export]
runs-on: ubuntu-latest
if: ${{ failure() }}
steps:
- name: Notify Slack on failure
uses: rtCamp/[email protected]
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACK_CHANNEL: sdk-sims
SLACK_USERNAME: Sim Tests
SLACK_ICON_EMOJI: ":skull:"
SLACK_COLOR: danger
SLACK_MESSAGE: Sims are failing
SLACK_FOOTER: ""

14 changes: 7 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -162,33 +162,33 @@ test-sim-nondeterminism:
test-sim-custom-genesis-fast:
@echo "Running custom genesis simulation..."
@echo "By default, ${HOME}/.cada/config/genesis.json will be used."
@cd ${CURRENT_DIR}/simapp && go test -mod=readonly -run TestFullAppSimulation -Genesis=${HOME}/.cada/config/genesis.json \
@cd ${CURRENT_DIR}/simapp/app && go test -mod=readonly -run TestFullAppSimulation -Genesis=${HOME}/.cada/config/genesis.json \
-Enabled=true -NumBlocks=100 -BlockSize=200 -Commit=true -Seed=99 -Period=5 -v -timeout 24h

test-sim-import-export: runsim
@echo "Running application import/export simulation. This may take several minutes..."
@cd ${CURRENT_DIR}/simapp && $(BINDIR)/runsim -Jobs=4 -SimAppPkg=. -ExitOnFail 50 5 TestAppImportExport
@cd ${CURRENT_DIR}/simapp/app && $(BINDIR)/runsim -Jobs=4 -SimAppPkg=. -ExitOnFail 50 5 TestAppImportExport

test-sim-after-import: runsim
@echo "Running application simulation-after-import. This may take several minutes..."
@cd ${CURRENT_DIR}/simapp && $(BINDIR)/runsim -Jobs=4 -SimAppPkg=. -ExitOnFail 50 5 TestAppSimulationAfterImport
@cd ${CURRENT_DIR}/simapp/app && $(BINDIR)/runsim -Jobs=4 -SimAppPkg=. -ExitOnFail 50 5 TestAppSimulationAfterImport

test-sim-custom-genesis-multi-seed: runsim
@echo "Running multi-seed custom genesis simulation..."
@echo "By default, ${HOME}/.cada/config/genesis.json will be used."
@cd ${CURRENT_DIR}/simapp && $(BINDIR)/runsim -Genesis=${HOME}/.cada/config/genesis.json -SimAppPkg=. -ExitOnFail 400 5 TestFullAppSimulation
@cd ${CURRENT_DIR}/simapp/app && $(BINDIR)/runsim -Genesis=${HOME}/.cada/config/genesis.json -SimAppPkg=. -ExitOnFail 400 5 TestFullAppSimulation

test-sim-multi-seed-long: runsim
@echo "Running long multi-seed application simulation. This may take awhile!"
@cd ${CURRENT_DIR}/simapp && $(BINDIR)/runsim -Jobs=4 -SimAppPkg=. -ExitOnFail 500 50 TestFullAppSimulation
@cd ${CURRENT_DIR}/simapp/app && $(BINDIR)/runsim -Jobs=4 -SimAppPkg=. -ExitOnFail 500 50 TestFullAppSimulation

test-sim-multi-seed-short: runsim
@echo "Running short multi-seed application simulation. This may take awhile!"
@cd ${CURRENT_DIR}/simapp && $(BINDIR)/runsim -Jobs=4 -SimAppPkg=. -ExitOnFail 50 10 TestFullAppSimulation
@cd ${CURRENT_DIR}/simapp/app && $(BINDIR)/runsim -Jobs=4 -SimAppPkg=. -ExitOnFail 50 10 TestFullAppSimulation

test-sim-benchmark-invariants:
@echo "Running simulation invariant benchmarks..."
cd ${CURRENT_DIR}/simapp && @go test -mod=readonly -benchmem -bench=BenchmarkInvariants -run=^$ \
cd ${CURRENT_DIR}/simapp/app && @go test -mod=readonly -benchmem -bench=BenchmarkInvariants -run=^$ \
-Enabled=true -NumBlocks=1000 -BlockSize=200 \
-Period=1 -Commit=true -Seed=57 -v -timeout 24h

Expand Down
150 changes: 150 additions & 0 deletions simapp/app/sim_bench_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package app

import (
"fmt"
"os"
"testing"

"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/server"
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
"github.com/cosmos/cosmos-sdk/x/simulation"
simcli "github.com/cosmos/cosmos-sdk/x/simulation/client/cli"
)

// Profile with:
// /usr/local/go/bin/go test -benchmem -run=^$ cosmossdk.io/simapp -bench ^BenchmarkFullAppSimulation$ -Commit=true -cpuprofile cpu.out
func BenchmarkFullAppSimulation(b *testing.B) {
b.ReportAllocs()
config := simcli.NewConfigFromFlags()
config.ChainID = AppChainID

db, dir, logger, skip, err := simtestutil.SetupSimulation(config, "goleveldb-app-sim", "Simulation",
simcli.FlagVerboseValue, simcli.FlagEnabledValue)
if err != nil {
b.Fatalf("simulation setup failed: %s", err.Error())
}

if skip {
b.Skip("skipping benchmark application simulation")
}

defer func() {
db.Close()
err = os.RemoveAll(dir)
if err != nil {
b.Fatal(err)
}
}()

appOptions := make(simtestutil.AppOptionsMap, 0)
appOptions[flags.FlagHome] = DefaultNodeHome
appOptions[server.FlagInvCheckPeriod] = simcli.FlagPeriodValue

app := NewChainApp(logger, db, nil, true, appOptions, interBlockCacheOpt(), baseapp.SetChainID(AppChainID))

// run randomized simulation
_, simParams, simErr := simulation.SimulateFromSeed(
b,
os.Stdout,
app.BaseApp,
simtestutil.AppStateFn(app.AppCodec(), app.SimulationManager(), app.DefaultGenesis()),
simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1
simtestutil.SimulationOperations(app, app.AppCodec(), config),
BlockedAddresses(),
config,
app.AppCodec(),
)

// export state and simParams before the simulation error is checked
if err = simtestutil.CheckExportSimulation(app, config, simParams); err != nil {
b.Fatal(err)
}

if simErr != nil {
b.Fatal(simErr)
}

if config.Commit {
simtestutil.PrintStats(db)
}
}

func BenchmarkInvariants(b *testing.B) {
b.ReportAllocs()

config := simcli.NewConfigFromFlags()
config.ChainID = AppChainID

db, dir, logger, skip, err := simtestutil.SetupSimulation(config, "leveldb-app-invariant-bench", "Simulation",
simcli.FlagVerboseValue, simcli.FlagEnabledValue)
if err != nil {
b.Fatalf("simulation setup failed: %s", err.Error())
}

if skip {
b.Skip("skipping benchmark application simulation")
}

config.AllInvariants = false

defer func() {
db.Close()
err = os.RemoveAll(dir)
if err != nil {
b.Fatal(err)
}
}()

appOptions := make(simtestutil.AppOptionsMap, 0)
appOptions[flags.FlagHome] = DefaultNodeHome
appOptions[server.FlagInvCheckPeriod] = simcli.FlagPeriodValue

app := NewChainApp(logger, db, nil, true, appOptions, interBlockCacheOpt(), baseapp.SetChainID(AppChainID))

// run randomized simulation
_, simParams, simErr := simulation.SimulateFromSeed(
b,
os.Stdout,
app.BaseApp,
simtestutil.AppStateFn(app.AppCodec(), app.SimulationManager(), app.DefaultGenesis()),
simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1
simtestutil.SimulationOperations(app, app.AppCodec(), config),
BlockedAddresses(),
config,
app.AppCodec(),
)

// export state and simParams before the simulation error is checked
if err = simtestutil.CheckExportSimulation(app, config, simParams); err != nil {
b.Fatal(err)
}

if simErr != nil {
b.Fatal(simErr)
}

if config.Commit {
simtestutil.PrintStats(db)
}

ctx := app.NewContext(true)

// 3. Benchmark each invariant separately
//
// NOTE: We use the crisis keeper as it has all the invariants registered with
// their respective metadata which makes it useful for testing/benchmarking.
for _, cr := range app.CrisisKeeper.Routes() {
cr := cr
b.Run(fmt.Sprintf("%s/%s", cr.ModuleName, cr.Route), func(b *testing.B) {
if res, stop := cr.Invar(ctx); stop {
b.Fatalf(
"broken invariant at block %d of %d\n%s",
ctx.BlockHeight()-1, config.NumBlocks, res,
)
}
})
}
}
Loading

0 comments on commit 4016b10

Please sign in to comment.