Skip to content

Commit

Permalink
Merge pull request #227 from oasisprotocol/mitjat/genesis-test-from-file
Browse files Browse the repository at this point in the history
genesis_test: Numerous bugfixes and improvements
  • Loading branch information
mitjat authored Nov 29, 2022
2 parents 1ddd2d4 + 6b6dd3a commit aac10f7
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 40 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ start-e2e: start-docker-e2e

# Run dockerized postgres for local development
postgres:
@docker ps --format '{{.Names}}' | grep -q indexer-postgres && docker start indexer-postgres || \
@docker ps -a --format '{{.Names}}' | grep -q indexer-postgres && docker start indexer-postgres || \
docker run \
--name indexer-postgres \
-p 5432:5432 \
Expand Down
28 changes: 27 additions & 1 deletion storage/postgres/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ func (c *Client) Name() string {

// Wipe removes all contents of the database.
func (c *Client) Wipe(ctx context.Context) error {
// List, then drop all tables.
rows, err := c.Query(ctx, `
SELECT schemaname, tablename
FROM pg_tables
Expand All @@ -160,5 +161,30 @@ func (c *Client) Wipe(ctx context.Context) error {
return err
}
}
return err

// List, then drop all custom types.
// Query from https://stackoverflow.com/questions/3660787/how-to-list-custom-types-using-postgres-information-schema
rows, err = c.Query(ctx, `
SELECT n.nspname as schema, t.typname as type
FROM pg_type t
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
WHERE (t.typrelid = 0 OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid))
AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid)
AND n.nspname NOT IN ('pg_catalog', 'information_schema');
`)
if err != nil {
return fmt.Errorf("failed to list types: %w", err)
}
for rows.Next() {
var schema, typ string
if err = rows.Scan(&schema, &typ); err != nil {
return err
}
c.logger.Info("dropping type", "schema", schema, "type", typ)
if _, err = c.pool.Exec(ctx, fmt.Sprintf("DROP TYPE %s.%s CASCADE;", schema, typ)); err != nil {
return err
}
}

return nil
}
4 changes: 2 additions & 2 deletions tests/config.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package tests

const (
GenesisHeight = int64(1) // TODO: Get from config.
ChainID = "oasis-test" // TODO: Get from config.
GenesisHeight = int64(8_048_956) // TODO: Get from config.
ChainID = "oasis-test" // TODO: Get from config.
)

var baseEndpoint string
Expand Down
126 changes: 90 additions & 36 deletions tests/genesis/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package genesis

import (
"context"
"encoding/json"
"fmt"
"io"
"os"
Expand All @@ -11,9 +12,10 @@ import (
"github.com/iancoleman/strcase"
"github.com/oasisprotocol/oasis-core/go/common/entity"
"github.com/oasisprotocol/oasis-core/go/common/node"
governance "github.com/oasisprotocol/oasis-core/go/governance/api"
registry "github.com/oasisprotocol/oasis-core/go/registry/api"
staking "github.com/oasisprotocol/oasis-core/go/staking/api"
genesisAPI "github.com/oasisprotocol/oasis-core/go/genesis/api"
governanceAPI "github.com/oasisprotocol/oasis-core/go/governance/api"
registryAPI "github.com/oasisprotocol/oasis-core/go/registry/api"
stakingAPI "github.com/oasisprotocol/oasis-core/go/staking/api"
oasisConfig "github.com/oasisprotocol/oasis-sdk/client-sdk/go/config"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -86,7 +88,7 @@ type TestVote struct {

func newTargetClient(t *testing.T) (*postgres.Client, error) {
connString := os.Getenv("HEALTHCHECK_TEST_CONN_STRING")
logger, err := log.NewLogger("cockroach-test", io.Discard, log.FmtJSON, log.LevelInfo)
logger, err := log.NewLogger("db-test", io.Discard, log.FmtJSON, log.LevelInfo)
assert.Nil(t, err)

return postgres.NewClient(connString, logger)
Expand All @@ -100,10 +102,14 @@ func newSourceClientFactory() (*oasis.ClientFactory, error) {
return oasis.NewClientFactory(context.Background(), network)
}

var chainID = "" // Memoization for getChainId(). Assumes all tests access the same chain.
func getChainID(ctx context.Context, t *testing.T, source *oasis.ConsensusClient) string {
doc, err := source.GenesisDocument(ctx)
assert.Nil(t, err)
return strcase.ToSnake(doc.ChainID)
if chainID == "" {
doc, err := source.GenesisDocument(ctx)
assert.Nil(t, err)
chainID = strcase.ToSnake(doc.ChainID)
}
return chainID
}

func checkpointBackends(t *testing.T, source *oasis.ConsensusClient, target *postgres.Client) (int64, error) {
Expand Down Expand Up @@ -172,9 +178,7 @@ func TestBlocksSanityCheck(t *testing.T) {
postgresClient, err := newTargetClient(t)
require.Nil(t, err)

doc, err := oasisClient.GenesisDocument(ctx)
require.Nil(t, err)
chainID := strcase.ToSnake(doc.ChainID)
chainID := getChainID(ctx, t, oasisClient)

var latestHeight int64
err = postgresClient.QueryRow(ctx, fmt.Sprintf(
Expand Down Expand Up @@ -214,26 +218,48 @@ func TestGenesisFull(t *testing.T) {
assert.Nil(t, err)

t.Log("Creating checkpoint...")

height, err := checkpointBackends(t, oasisClient, postgresClient)
assert.Nil(t, err)

t.Logf("Validating at height %d...", height)
t.Logf("Fetching genesis at height %d...", height)
var registryGenesis *registryAPI.Genesis
var stakingGenesis *stakingAPI.Genesis
var governanceGenesis *governanceAPI.Genesis
genesisPath := os.Getenv("OASIS_GENESIS_DUMP")
if genesisPath != "" {
t.Log("Reading genesis from dump at", genesisPath)
gensisJSON, err := os.ReadFile(genesisPath)
if err != nil {
require.Nil(t, err)
}
var genesis genesisAPI.Document
err = json.Unmarshal(gensisJSON, &genesis)
if err != nil {
require.Nil(t, err)
}
if genesis.Height != height {
require.Nil(t, fmt.Errorf("height mismatch: %d (in genesis dump) != %d (in DB)", genesis.Height, height))
}
registryGenesis = &genesis.Registry
stakingGenesis = &genesis.Staking
governanceGenesis = &genesis.Governance
} else {
t.Log("Fetching genesis from node", genesisPath)
registryGenesis, err = oasisClient.RegistryGenesis(ctx, height)
require.Nil(t, err)
stakingGenesis, err = oasisClient.StakingGenesis(ctx, height)
require.Nil(t, err)
governanceGenesis, err = oasisClient.GovernanceGenesis(ctx, height)
require.Nil(t, err)
}

registryGenesis, err := oasisClient.RegistryGenesis(ctx, height)
require.Nil(t, err)
t.Logf("Validating at height %d...", height)
validateRegistryBackend(t, registryGenesis, oasisClient, postgresClient)

stakingGenesis, err := oasisClient.StakingGenesis(ctx, height)
require.Nil(t, err)
validateStakingBackend(t, stakingGenesis, oasisClient, postgresClient)

governanceGenesis, err := oasisClient.GovernanceGenesis(ctx, height)
require.Nil(t, err)
validateGovernanceBackend(t, governanceGenesis, oasisClient, postgresClient)
}

func validateRegistryBackend(t *testing.T, genesis *registry.Genesis, source *oasis.ConsensusClient, target *postgres.Client) {
func validateRegistryBackend(t *testing.T, genesis *registryAPI.Genesis, source *oasis.ConsensusClient, target *postgres.Client) {
t.Log("=== Validating registry backend ===")

validateEntities(t, genesis, source, target)
Expand All @@ -243,7 +269,7 @@ func validateRegistryBackend(t *testing.T, genesis *registry.Genesis, source *oa
t.Log("=== Done validating registry backend ===")
}

func validateEntities(t *testing.T, genesis *registry.Genesis, source *oasis.ConsensusClient, target *postgres.Client) {
func validateEntities(t *testing.T, genesis *registryAPI.Genesis, source *oasis.ConsensusClient, target *postgres.Client) {
t.Log("Validating entities...")

ctx := context.Background()
Expand All @@ -255,7 +281,7 @@ func validateEntities(t *testing.T, genesis *registry.Genesis, source *oasis.Con
continue
}
var e entity.Entity
err := se.Open(registry.RegisterEntitySignatureContext, &e)
err := se.Open(registryAPI.RegisterEntitySignatureContext, &e)
assert.Nil(t, err)

te := TestEntity{
Expand Down Expand Up @@ -351,7 +377,7 @@ func validateEntities(t *testing.T, genesis *registry.Genesis, source *oasis.Con
}
}

func validateNodes(t *testing.T, genesis *registry.Genesis, source *oasis.ConsensusClient, target *postgres.Client) {
func validateNodes(t *testing.T, genesis *registryAPI.Genesis, source *oasis.ConsensusClient, target *postgres.Client) {
t.Log("Validating nodes...")

ctx := context.Background()
Expand All @@ -363,7 +389,7 @@ func validateNodes(t *testing.T, genesis *registry.Genesis, source *oasis.Consen
continue
}
var n node.Node
err := sn.Open(registry.RegisterNodeSignatureContext, &n)
err := sn.Open(registryAPI.RegisterNodeSignatureContext, &n)
assert.Nil(t, err)

vrfPubkey := ""
Expand Down Expand Up @@ -414,7 +440,7 @@ func validateNodes(t *testing.T, genesis *registry.Genesis, source *oasis.Consen
actualNodes[n.ID] = n
}

assert.Equal(t, len(expectedNodes), len(actualNodes))
assert.Equal(t, len(expectedNodes), len(actualNodes), "wrong number of nodes")
for ke, ve := range expectedNodes {
va, ok := actualNodes[ke]
if !ok {
Expand All @@ -433,7 +459,7 @@ func validateNodes(t *testing.T, genesis *registry.Genesis, source *oasis.Consen
}
}

func validateRuntimes(t *testing.T, genesis *registry.Genesis, source *oasis.ConsensusClient, target *postgres.Client) {
func validateRuntimes(t *testing.T, genesis *registryAPI.Genesis, source *oasis.ConsensusClient, target *postgres.Client) {
t.Log("Validating runtimes...")

ctx := context.Background()
Expand Down Expand Up @@ -480,7 +506,7 @@ func validateRuntimes(t *testing.T, genesis *registry.Genesis, source *oasis.Con
}

runtimeRows, err := target.Query(ctx, fmt.Sprintf(
`SELECT id, suspended, kind, tee_hardware, key_manager FROM %s.runtimes_checkpoint`, chainID),
`SELECT id, suspended, kind, tee_hardware, COALESCE(key_manager, 'none') FROM %s.runtimes_checkpoint`, chainID),
)
require.Nil(t, err)

Expand All @@ -494,7 +520,10 @@ func validateRuntimes(t *testing.T, genesis *registry.Genesis, source *oasis.Con
&tr.TeeHardware,
&tr.KeyManager,
)
assert.Nil(t, err)
if err != nil {
// We want to display err.Error(), or else the message is incomprehensible when it fails.
require.Nil(t, err, "error scanning runtime row", "errMsg", err.Error())
}

actualRuntimes[tr.ID] = tr
}
Expand All @@ -518,15 +547,15 @@ func validateRuntimes(t *testing.T, genesis *registry.Genesis, source *oasis.Con
}
}

func validateStakingBackend(t *testing.T, genesis *staking.Genesis, source *oasis.ConsensusClient, target *postgres.Client) {
func validateStakingBackend(t *testing.T, genesis *stakingAPI.Genesis, source *oasis.ConsensusClient, target *postgres.Client) {
t.Log("=== Validating staking backend ===")

validateAccounts(t, genesis, source, target)

t.Log("=== Done validating staking backend! ===")
}

func validateAccounts(t *testing.T, genesis *staking.Genesis, source *oasis.ConsensusClient, target *postgres.Client) {
func validateAccounts(t *testing.T, genesis *stakingAPI.Genesis, source *oasis.ConsensusClient, target *postgres.Client) {
t.Log("Validating accounts...")

ctx := context.Background()
Expand All @@ -537,6 +566,7 @@ func validateAccounts(t *testing.T, genesis *staking.Genesis, source *oasis.Cons
FROM %s.accounts_checkpoint`, chainID),
)
require.Nil(t, err)
actualAccts := make(map[string]bool)
for acctRows.Next() {
var a TestAccount
err = acctRows.Scan(
Expand All @@ -547,6 +577,16 @@ func validateAccounts(t *testing.T, genesis *staking.Genesis, source *oasis.Cons
&a.Debonding,
)
assert.Nil(t, err)
actualAccts[a.Address] = true

isReservedAddress := a.Address == stakingAPI.CommonPoolAddress.String() ||
a.Address == stakingAPI.FeeAccumulatorAddress.String() ||
a.Address == stakingAPI.GovernanceDepositsAddress.String() ||
a.Address == "oasis1qzq8u7xs328puu2jy524w3fygzs63rv3u5967970" // == stakingAPI.BurnAddress.String(); not yet exposed in the released stakingAPI
if isReservedAddress {
// Reserved addresses are explicitly not included in the ledger (and thus in the genesis dump).
continue
}

actualAllowances := make(map[string]uint64)
allowanceRows, err := target.Query(ctx, fmt.Sprintf(`
Expand All @@ -569,13 +609,14 @@ func validateAccounts(t *testing.T, genesis *staking.Genesis, source *oasis.Cons
}
a.Allowances = actualAllowances

var address staking.Address
var address stakingAPI.Address
err = address.UnmarshalText([]byte(a.Address))
assert.Nil(t, err)

acct, ok := genesis.Ledger[address]
if !ok {
t.Logf("address %s expected, but not found", address.String())
t.Logf("address %s found, but not expected", address.String())
t.Fail()
continue
}

Expand All @@ -594,9 +635,22 @@ func validateAccounts(t *testing.T, genesis *staking.Genesis, source *oasis.Cons
}
assert.Equal(t, e, a)
}
for addr, acct := range genesis.Ledger {
hasBalance := !acct.General.Balance.IsZero() ||
!acct.Escrow.Active.Balance.IsZero() ||
!acct.Escrow.Debonding.Balance.IsZero()
if !hasBalance { // the indexer doesn't have to know about this acct
continue
}

if !actualAccts[addr.String()] {
t.Logf("address %s expected, but not found", addr.String())
t.Fail()
}
}
}

func validateGovernanceBackend(t *testing.T, genesis *governance.Genesis, source *oasis.ConsensusClient, target *postgres.Client) {
func validateGovernanceBackend(t *testing.T, genesis *governanceAPI.Genesis, source *oasis.ConsensusClient, target *postgres.Client) {
t.Log("=== Validating governance backend ===")

validateProposals(t, genesis, source, target)
Expand All @@ -605,7 +659,7 @@ func validateGovernanceBackend(t *testing.T, genesis *governance.Genesis, source
t.Log("=== Done validating governance backend! ===")
}

func validateProposals(t *testing.T, genesis *governance.Genesis, source *oasis.ConsensusClient, target *postgres.Client) {
func validateProposals(t *testing.T, genesis *governanceAPI.Genesis, source *oasis.ConsensusClient, target *postgres.Client) {
t.Log("Validating proposals...")

ctx := context.Background()
Expand Down Expand Up @@ -691,7 +745,7 @@ func validateProposals(t *testing.T, genesis *governance.Genesis, source *oasis.
}
}

func validateVotes(t *testing.T, genesis *governance.Genesis, source *oasis.ConsensusClient, target *postgres.Client) {
func validateVotes(t *testing.T, genesis *governanceAPI.Genesis, source *oasis.ConsensusClient, target *postgres.Client) {
t.Log("Validating votes...")

ctx := context.Background()
Expand Down

0 comments on commit aac10f7

Please sign in to comment.