refactor(schema)!: move view interfaces from testing to schema (#21204)
This commit is contained in:
parent
df3b035dd8
commit
431b52309c
@ -5,6 +5,7 @@ import (
|
||||
|
||||
"cosmossdk.io/schema/appdata"
|
||||
"cosmossdk.io/schema/logutil"
|
||||
"cosmossdk.io/schema/view"
|
||||
)
|
||||
|
||||
// Config species the configuration passed to an indexer initialization function.
|
||||
@ -55,10 +56,11 @@ type InitParams struct {
|
||||
Config Config
|
||||
|
||||
// Context is the context that the indexer should use to listen for a shutdown signal via Context.Done(). Other
|
||||
// parameters may also be passed through context from the app if necessary.
|
||||
// parameters may also be passed through context from the app if necessary. It is expected to be non-nil.
|
||||
Context context.Context
|
||||
|
||||
// Logger is a logger the indexer can use to write log messages.
|
||||
// Logger is a logger the indexer can use to write log messages. It may be nil if the indexer does not need
|
||||
// to write logs.
|
||||
Logger logutil.Logger
|
||||
}
|
||||
|
||||
@ -67,12 +69,13 @@ type InitResult struct {
|
||||
// Listener is the indexer's app data listener.
|
||||
Listener appdata.Listener
|
||||
|
||||
// LastBlockPersisted indicates the last block that the indexer persisted (if it is persisting data). It
|
||||
// should be 0 if the indexer has no data stored and wants to start syncing state. It should be -1 if the indexer
|
||||
// does not care to persist state at all and is just listening for some other streaming purpose. If the indexer
|
||||
// has persisted state and has missed some blocks, a runtime error will occur to prevent the indexer from continuing
|
||||
// in an invalid state. If an indexer starts indexing after a chain's genesis (returning 0), the indexer manager
|
||||
// will attempt to perform a catch-up sync of state. Historical events will not be replayed, but an accurate
|
||||
// View is a view of indexed data that indexers can provide. It is optional and may be nil.
|
||||
// If it is provided it can be used for automated testing and other purposes.
|
||||
// At indexer start-up, the block number returned by the view will be used to determine the
|
||||
// starting block for the indexer. If the block number is 0, the indexer manager will attempt
|
||||
// to perform a catch-up sync of state. Historical events will not be replayed, but an accurate
|
||||
// representation of the current state at the height at which indexing began can be reproduced.
|
||||
LastBlockPersisted int64
|
||||
// If the block number is non-zero but does not match the current chain height, a runtime error
|
||||
// will occur because this is an unsafe condition that indicates lost data.
|
||||
View view.AppData
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ import (
|
||||
"cosmossdk.io/schema"
|
||||
"cosmossdk.io/schema/appdata"
|
||||
"cosmossdk.io/schema/testing/statesim"
|
||||
"cosmossdk.io/schema/view"
|
||||
)
|
||||
|
||||
// Options are the options for creating an app data simulator.
|
||||
@ -151,11 +152,11 @@ func (a *Simulator) ProcessPacket(packet appdata.Packet) error {
|
||||
}
|
||||
|
||||
// AppState returns the current app state backing the simulator.
|
||||
func (a *Simulator) AppState() statesim.AppState {
|
||||
func (a *Simulator) AppState() view.AppState {
|
||||
return a.state
|
||||
}
|
||||
|
||||
// BlockNum returns the current block number of the simulator.
|
||||
func (a *Simulator) BlockNum() uint64 {
|
||||
return a.blockNum
|
||||
func (a *Simulator) BlockNum() (uint64, error) {
|
||||
return a.blockNum, nil
|
||||
}
|
||||
|
||||
@ -4,25 +4,15 @@ import (
|
||||
"fmt"
|
||||
|
||||
"cosmossdk.io/schema/testing/statesim"
|
||||
"cosmossdk.io/schema/view"
|
||||
)
|
||||
|
||||
// HasAppData defines an interface for things that hold app data include app state.
|
||||
// If an indexer implements this then DiffAppData can be used to compare it with
|
||||
// the Simulator state which also implements this.
|
||||
type HasAppData interface {
|
||||
// AppState returns the app state.
|
||||
AppState() statesim.AppState
|
||||
|
||||
// BlockNum returns the latest block number.
|
||||
BlockNum() uint64
|
||||
}
|
||||
|
||||
// DiffAppData compares the app data of two objects that implement HasAppData.
|
||||
// This can be used by indexer to compare their state with the Simulator state
|
||||
// if the indexer implements HasAppData.
|
||||
// It returns a human-readable diff if the app data differs and the empty string
|
||||
// if they are the same.
|
||||
func DiffAppData(expected, actual HasAppData) string {
|
||||
func DiffAppData(expected, actual view.AppData) string {
|
||||
res := ""
|
||||
|
||||
if stateDiff := statesim.DiffAppStates(expected.AppState(), actual.AppState()); stateDiff != "" {
|
||||
@ -30,8 +20,20 @@ func DiffAppData(expected, actual HasAppData) string {
|
||||
res += stateDiff
|
||||
}
|
||||
|
||||
if expected.BlockNum() != actual.BlockNum() {
|
||||
res += fmt.Sprintf("BlockNum: expected %d, got %d\n", expected.BlockNum(), actual.BlockNum())
|
||||
expectedBlock, err := expected.BlockNum()
|
||||
if err != nil {
|
||||
res += fmt.Sprintf("ERROR getting expected block num: %s\n", err)
|
||||
return res
|
||||
}
|
||||
|
||||
actualBlock, err := actual.BlockNum()
|
||||
if err != nil {
|
||||
res += fmt.Sprintf("ERROR getting actual block num: %s\n", err)
|
||||
return res
|
||||
}
|
||||
|
||||
if expectedBlock != actualBlock {
|
||||
res += fmt.Sprintf("BlockNum: expected %d, got %d\n", expectedBlock, actualBlock)
|
||||
}
|
||||
|
||||
return res
|
||||
|
||||
@ -78,7 +78,7 @@ StartBlock: {6 <nil> <nil>}
|
||||
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["A𞥟",981],"Value":null,"Delete":false},{"TypeName":"ManyValues","Key":"ᵕ؏A","Value":{"Value1":-317,"Value2":"AA==","Value3":-37.62890625,"Value4":232},"Delete":false}]}
|
||||
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"AACHBAjyAgFHOQAABo+PGAK3Bj7TwwBb/wAB3gE=","Value":{"valNotNull":"HBwBHAY6AAKO+UwDKRICAT0lgRRvCRvHFFoNAigBAUEDHoQUfB2qApRB/z41AAubARsBATQg3gCppQMAAQwHAQ=="},"Delete":false}]}
|
||||
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_decimal","Key":"9.5E+8","Value":["-2","88111430.0122412446"],"Delete":false}]}
|
||||
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint8","Key":7,"Value":null,"Delete":true},{"TypeName":"test_time","Key":"1970-01-01T00:59:59.999999999+01:00","Value":["1970-01-01T01:00:00.000000001+01:00",null],"Delete":false}]}
|
||||
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint8","Key":7,"Value":null,"Delete":true},{"TypeName":"test_time","Key":"1969-12-31T18:59:59.999999999-05:00","Value":["1969-12-31T19:00:00.000000001-05:00",null],"Delete":false}]}
|
||||
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"൴~𝔶ٞ蹯a_ ᛮ!؋aض©-?","Value":{"Value2":""},"Delete":false}]}
|
||||
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint8","Key":14,"Value":{"valNotNull":116},"Delete":false},{"TypeName":"test_duration","Key":100403021838,"Value":[1547,null],"Delete":false}]}
|
||||
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int64","Key":-34196421,"Value":[56,224549431],"Delete":false},{"TypeName":"test_bool","Key":true,"Value":{"valNotNull":true,"valNullable":null},"Delete":false}]}
|
||||
|
||||
@ -60,10 +60,10 @@ Module all_kinds
|
||||
Object key=℠¼々¢~;-Ⱥ!˃a[ʰᾌ?{ᪧ৵%ᾯ¦〈: NOT FOUND
|
||||
Object Collection test_time
|
||||
OBJECT COUNT ERROR: expected 4, got 3
|
||||
Object key=1970-01-01 01:00:00.000000005 +0100 CET: NOT FOUND
|
||||
Object key=1970-01-01 01:00:00.001598687 +0100 CET
|
||||
valNotNull: expected 1970-01-01 01:00:00.007727197 +0100 CET, got 1970-01-01 01:00:00.034531678 +0100 CET
|
||||
valNullable: expected 1970-01-01 01:00:00.000000484 +0100 CET, got 1970-01-01 01:00:00.000000033 +0100 CET
|
||||
Object key=1969-12-31 19:00:00.000000005 -0500 EST: NOT FOUND
|
||||
Object key=1969-12-31 19:00:00.001598687 -0500 EST
|
||||
valNotNull: expected 1969-12-31 19:00:00.007727197 -0500 EST, got 1969-12-31 19:00:00.034531678 -0500 EST
|
||||
valNullable: expected 1969-12-31 19:00:00.000000484 -0500 EST, got 1969-12-31 19:00:00.000000033 -0500 EST
|
||||
Object Collection test_uint16
|
||||
OBJECT COUNT ERROR: expected 4, got 3
|
||||
Object key=23712: NOT FOUND
|
||||
@ -75,5 +75,5 @@ Module all_kinds
|
||||
Object Collection test_uint8
|
||||
OBJECT COUNT ERROR: expected 3, got 2
|
||||
Object key=1: NOT FOUND
|
||||
Module test_cases: NOT FOUND
|
||||
Module test_cases: actual module NOT FOUND
|
||||
BlockNum: expected 2, got 1
|
||||
|
||||
@ -9,6 +9,7 @@ import (
|
||||
|
||||
"cosmossdk.io/schema"
|
||||
"cosmossdk.io/schema/appdata"
|
||||
"cosmossdk.io/schema/view"
|
||||
)
|
||||
|
||||
// App is a collection of simulated module states corresponding to an app's schema for testing purposes.
|
||||
@ -27,7 +28,7 @@ func NewApp(appSchema map[string]schema.ModuleSchema, options Options) *App {
|
||||
}
|
||||
|
||||
for moduleName, moduleSchema := range appSchema {
|
||||
moduleState := NewModule(moduleSchema, options)
|
||||
moduleState := NewModule(moduleName, moduleSchema, options)
|
||||
app.moduleStates.Set(moduleName, moduleState)
|
||||
}
|
||||
|
||||
@ -62,7 +63,7 @@ func (a *App) InitializeModule(data appdata.ModuleInitializationData) error {
|
||||
return fmt.Errorf("module %s already initialized", data.ModuleName)
|
||||
}
|
||||
|
||||
a.moduleStates.Set(data.ModuleName, NewModule(data.Schema, a.options))
|
||||
a.moduleStates.Set(data.ModuleName, NewModule(data.ModuleName, data.Schema, a.options))
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -91,18 +92,22 @@ func (a *App) UpdateGen() *rapid.Generator[appdata.ObjectUpdateData] {
|
||||
}
|
||||
|
||||
// GetModule returns the module state for the given module name.
|
||||
func (a *App) GetModule(moduleName string) (ModuleState, bool) {
|
||||
return a.moduleStates.Get(moduleName)
|
||||
func (a *App) GetModule(moduleName string) (view.ModuleState, error) {
|
||||
mod, ok := a.moduleStates.Get(moduleName)
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
return mod, nil
|
||||
}
|
||||
|
||||
// Modules iterates over all the module state instances in the app.
|
||||
func (a *App) Modules(f func(moduleName string, modState ModuleState) bool) {
|
||||
func (a *App) Modules(f func(modState view.ModuleState, err error) bool) {
|
||||
a.moduleStates.Scan(func(key string, value *Module) bool {
|
||||
return f(key, value)
|
||||
return f(value, nil)
|
||||
})
|
||||
}
|
||||
|
||||
// NumModules returns the number of modules in the app.
|
||||
func (a *App) NumModules() int {
|
||||
return a.moduleStates.Len()
|
||||
func (a *App) NumModules() (int, error) {
|
||||
return a.moduleStates.Len(), nil
|
||||
}
|
||||
|
||||
@ -1,32 +1,46 @@
|
||||
package statesim
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
// AppState defines an interface for things that represent application state in schema format.
|
||||
type AppState interface {
|
||||
// GetModule returns the module state for the given module name.
|
||||
GetModule(moduleName string) (ModuleState, bool)
|
||||
|
||||
// Modules iterates over all the module state instances in the app.
|
||||
Modules(f func(moduleName string, modState ModuleState) bool)
|
||||
|
||||
// NumModules returns the number of modules in the app.
|
||||
NumModules() int
|
||||
}
|
||||
"cosmossdk.io/schema/view"
|
||||
)
|
||||
|
||||
// DiffAppStates compares the app state of two objects that implement AppState and returns a string with a diff if they
|
||||
// are different or the empty string if they are the same.
|
||||
func DiffAppStates(expected, actual AppState) string {
|
||||
func DiffAppStates(expected, actual view.AppState) string {
|
||||
res := ""
|
||||
|
||||
if expected.NumModules() != actual.NumModules() {
|
||||
res += fmt.Sprintf("MODULE COUNT ERROR: expected %d, got %d\n", expected.NumModules(), actual.NumModules())
|
||||
expectNumModules, err := expected.NumModules()
|
||||
if err != nil {
|
||||
res += fmt.Sprintf("ERROR getting expected num modules: %s\n", err)
|
||||
return res
|
||||
}
|
||||
|
||||
expected.Modules(func(moduleName string, expectedMod ModuleState) bool {
|
||||
actualMod, found := actual.GetModule(moduleName)
|
||||
if !found {
|
||||
res += fmt.Sprintf("Module %s: NOT FOUND\n", moduleName)
|
||||
actualNumModules, err := actual.NumModules()
|
||||
if err != nil {
|
||||
res += fmt.Sprintf("ERROR getting actual num modules: %s\n", err)
|
||||
return res
|
||||
}
|
||||
|
||||
if expectNumModules != actualNumModules {
|
||||
res += fmt.Sprintf("MODULE COUNT ERROR: expected %d, got %d\n", expectNumModules, actualNumModules)
|
||||
}
|
||||
|
||||
expected.Modules(func(expectedMod view.ModuleState, err error) bool {
|
||||
if err != nil {
|
||||
res += fmt.Sprintf("ERROR getting expected module: %s\n", err)
|
||||
return true
|
||||
}
|
||||
|
||||
moduleName := expectedMod.ModuleName()
|
||||
actualMod, err := actual.GetModule(moduleName)
|
||||
if err != nil {
|
||||
res += fmt.Sprintf("ERROR getting actual module: %s\n", err)
|
||||
return true
|
||||
}
|
||||
if actualMod == nil {
|
||||
res += fmt.Sprintf("Module %s: actual module NOT FOUND\n", moduleName)
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@ -8,17 +8,19 @@ import (
|
||||
"pgregory.net/rapid"
|
||||
|
||||
"cosmossdk.io/schema"
|
||||
"cosmossdk.io/schema/view"
|
||||
)
|
||||
|
||||
// Module is a collection of object collections corresponding to a module's schema for testing purposes.
|
||||
type Module struct {
|
||||
name string
|
||||
moduleSchema schema.ModuleSchema
|
||||
objectCollections *btree.Map[string, *ObjectCollection]
|
||||
updateGen *rapid.Generator[schema.ObjectUpdate]
|
||||
}
|
||||
|
||||
// NewModule creates a new Module for the given module schema.
|
||||
func NewModule(moduleSchema schema.ModuleSchema, options Options) *Module {
|
||||
func NewModule(name string, moduleSchema schema.ModuleSchema, options Options) *Module {
|
||||
objectCollections := &btree.Map[string, *ObjectCollection]{}
|
||||
var objectTypeNames []string
|
||||
|
||||
@ -39,6 +41,7 @@ func NewModule(moduleSchema schema.ModuleSchema, options Options) *Module {
|
||||
})
|
||||
|
||||
return &Module{
|
||||
name: name,
|
||||
moduleSchema: moduleSchema,
|
||||
updateGen: updateGen,
|
||||
objectCollections: objectCollections,
|
||||
@ -61,24 +64,33 @@ func (o *Module) UpdateGen() *rapid.Generator[schema.ObjectUpdate] {
|
||||
return o.updateGen
|
||||
}
|
||||
|
||||
// ModuleName returns the name of the module.
|
||||
func (o *Module) ModuleName() string {
|
||||
return o.name
|
||||
}
|
||||
|
||||
// ModuleSchema returns the module schema for the module.
|
||||
func (o *Module) ModuleSchema() schema.ModuleSchema {
|
||||
return o.moduleSchema
|
||||
}
|
||||
|
||||
// GetObjectCollection returns the object collection for the given object type.
|
||||
func (o *Module) GetObjectCollection(objectType string) (ObjectCollectionState, bool) {
|
||||
return o.objectCollections.Get(objectType)
|
||||
func (o *Module) GetObjectCollection(objectType string) (view.ObjectCollection, error) {
|
||||
obj, ok := o.objectCollections.Get(objectType)
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
// ObjectCollections iterates over all object collections in the module.
|
||||
func (o *Module) ObjectCollections(f func(value ObjectCollectionState) bool) {
|
||||
func (o *Module) ObjectCollections(f func(value view.ObjectCollection, err error) bool) {
|
||||
o.objectCollections.Scan(func(key string, value *ObjectCollection) bool {
|
||||
return f(value)
|
||||
return f(value, nil)
|
||||
})
|
||||
}
|
||||
|
||||
// NumObjectCollections returns the number of object collections in the module.
|
||||
func (o *Module) NumObjectCollections() int {
|
||||
return o.objectCollections.Len()
|
||||
func (o *Module) NumObjectCollections() (int, error) {
|
||||
return o.objectCollections.Len(), nil
|
||||
}
|
||||
|
||||
@ -3,38 +3,44 @@ package statesim
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"cosmossdk.io/schema"
|
||||
"cosmossdk.io/schema/view"
|
||||
)
|
||||
|
||||
// ModuleState defines an interface for things that represent module state in schema format.
|
||||
type ModuleState interface {
|
||||
// ModuleSchema returns the schema for the module.
|
||||
ModuleSchema() schema.ModuleSchema
|
||||
|
||||
// GetObjectCollection returns the object collection state for the given object type.
|
||||
GetObjectCollection(objectType string) (ObjectCollectionState, bool)
|
||||
|
||||
// ObjectCollections iterates over all the object collection states in the module.
|
||||
ObjectCollections(f func(value ObjectCollectionState) bool)
|
||||
|
||||
// NumObjectCollections returns the number of object collections in the module.
|
||||
NumObjectCollections() int
|
||||
}
|
||||
|
||||
// DiffModuleStates compares the module state of two objects that implement ModuleState and returns a string with a diff if they
|
||||
// are different or the empty string if they are the same.
|
||||
func DiffModuleStates(expected, actual ModuleState) string {
|
||||
func DiffModuleStates(expected, actual view.ModuleState) string {
|
||||
res := ""
|
||||
|
||||
if expected.NumObjectCollections() != actual.NumObjectCollections() {
|
||||
res += fmt.Sprintf("OBJECT COLLECTION COUNT ERROR: expected %d, got %d\n", expected.NumObjectCollections(), actual.NumObjectCollections())
|
||||
expectedNumObjectCollections, err := expected.NumObjectCollections()
|
||||
if err != nil {
|
||||
res += fmt.Sprintf("ERROR getting expected num object collections: %s\n", err)
|
||||
return res
|
||||
}
|
||||
|
||||
expected.ObjectCollections(func(expectedColl ObjectCollectionState) bool {
|
||||
actualNumObjectCollections, err := actual.NumObjectCollections()
|
||||
if err != nil {
|
||||
res += fmt.Sprintf("ERROR getting actual num object collections: %s\n", err)
|
||||
return res
|
||||
}
|
||||
|
||||
if expectedNumObjectCollections != actualNumObjectCollections {
|
||||
res += fmt.Sprintf("OBJECT COLLECTION COUNT ERROR: expected %d, got %d\n", expectedNumObjectCollections, actualNumObjectCollections)
|
||||
}
|
||||
|
||||
expected.ObjectCollections(func(expectedColl view.ObjectCollection, err error) bool {
|
||||
if err != nil {
|
||||
res += fmt.Sprintf("ERROR getting expected object collection: %s\n", err)
|
||||
return true
|
||||
}
|
||||
|
||||
objTypeName := expectedColl.ObjectType().Name
|
||||
actualColl, found := actual.GetObjectCollection(objTypeName)
|
||||
if !found {
|
||||
res += fmt.Sprintf("Object Collection %s: NOT FOUND\n", objTypeName)
|
||||
actualColl, err := actual.GetObjectCollection(objTypeName)
|
||||
if err != nil {
|
||||
res += fmt.Sprintf("ERROR getting actual object collection: %s\n", err)
|
||||
return true
|
||||
}
|
||||
if actualColl == nil {
|
||||
res += fmt.Sprintf("Object Collection %s: actuall collection NOT FOUND\n", objTypeName)
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@ -110,16 +110,17 @@ func (o *ObjectCollection) UpdateGen() *rapid.Generator[schema.ObjectUpdate] {
|
||||
|
||||
// AllState iterates over the state of the collection by calling the given function with each item in
|
||||
// state represented as an object update.
|
||||
func (o *ObjectCollection) AllState(f func(schema.ObjectUpdate) bool) {
|
||||
func (o *ObjectCollection) AllState(f func(schema.ObjectUpdate, error) bool) {
|
||||
o.objects.Scan(func(_ string, v schema.ObjectUpdate) bool {
|
||||
return f(v)
|
||||
return f(v, nil)
|
||||
})
|
||||
}
|
||||
|
||||
// GetObject returns the object with the given key from the collection represented as an ObjectUpdate
|
||||
// itself. Deletions that are retained are returned as ObjectUpdate's with delete set to true.
|
||||
func (o *ObjectCollection) GetObject(key any) (update schema.ObjectUpdate, found bool) {
|
||||
return o.objects.Get(fmtObjectKey(o.objectType, key))
|
||||
func (o *ObjectCollection) GetObject(key interface{}) (update schema.ObjectUpdate, found bool, err error) {
|
||||
update, ok := o.objects.Get(fmtObjectKey(o.objectType, key))
|
||||
return update, ok, nil
|
||||
}
|
||||
|
||||
// ObjectType returns the object type of the collection.
|
||||
@ -128,8 +129,8 @@ func (o *ObjectCollection) ObjectType() schema.ObjectType {
|
||||
}
|
||||
|
||||
// Len returns the number of objects in the collection.
|
||||
func (o *ObjectCollection) Len() int {
|
||||
return o.objects.Len()
|
||||
func (o *ObjectCollection) Len() (int, error) {
|
||||
return o.objects.Len(), nil
|
||||
}
|
||||
|
||||
func fmtObjectKey(objectType schema.ObjectType, key any) string {
|
||||
|
||||
@ -6,46 +6,49 @@ import (
|
||||
|
||||
"cosmossdk.io/schema"
|
||||
schematesting "cosmossdk.io/schema/testing"
|
||||
"cosmossdk.io/schema/view"
|
||||
)
|
||||
|
||||
// ObjectCollectionState is the interface for the state of an object collection
|
||||
// represented by ObjectUpdate's for an ObjectType. ObjectUpdates must not include
|
||||
// ValueUpdates in the Value field. When ValueUpdates are applied they must be
|
||||
// converted to individual value or array format depending on the number of fields in
|
||||
// the value. For collections which retain deletions, ObjectUpdate's with the Delete
|
||||
// field set to true should be returned with the latest Value still intact.
|
||||
type ObjectCollectionState interface {
|
||||
// ObjectType returns the object type for the collection.
|
||||
ObjectType() schema.ObjectType
|
||||
|
||||
// GetObject returns the object update for the given key if it exists.
|
||||
GetObject(key any) (update schema.ObjectUpdate, found bool)
|
||||
|
||||
// AllState iterates over the state of the collection by calling the given function with each item in
|
||||
// state represented as an object update.
|
||||
AllState(f func(schema.ObjectUpdate) bool)
|
||||
|
||||
// Len returns the number of objects in the collection.
|
||||
Len() int
|
||||
}
|
||||
|
||||
// DiffObjectCollections compares the object collection state of two objects that implement ObjectCollectionState and returns a string with a diff if they
|
||||
// are different or the empty string if they are the same.
|
||||
func DiffObjectCollections(expected, actual ObjectCollectionState) string {
|
||||
func DiffObjectCollections(expected, actual view.ObjectCollection) string {
|
||||
res := ""
|
||||
if expected.Len() != actual.Len() {
|
||||
res += fmt.Sprintf("OBJECT COUNT ERROR: expected %d, got %d\n", expected.Len(), actual.Len())
|
||||
|
||||
expectedNumObjects, err := expected.Len()
|
||||
if err != nil {
|
||||
res += fmt.Sprintf("ERROR getting expected num objects: %s\n", err)
|
||||
return res
|
||||
}
|
||||
|
||||
expected.AllState(func(expectedUpdate schema.ObjectUpdate) bool {
|
||||
actualUpdate, found := actual.GetObject(expectedUpdate.Key)
|
||||
actualNumObjects, err := actual.Len()
|
||||
if err != nil {
|
||||
res += fmt.Sprintf("ERROR getting actual num objects: %s\n", err)
|
||||
return res
|
||||
}
|
||||
|
||||
if expectedNumObjects != actualNumObjects {
|
||||
res += fmt.Sprintf("OBJECT COUNT ERROR: expected %d, got %d\n", expectedNumObjects, actualNumObjects)
|
||||
}
|
||||
|
||||
expected.AllState(func(expectedUpdate schema.ObjectUpdate, err error) bool {
|
||||
if err != nil {
|
||||
res += fmt.Sprintf("ERROR getting expected object: %s\n", err)
|
||||
return true
|
||||
}
|
||||
|
||||
keyStr := fmtObjectKey(expected.ObjectType(), expectedUpdate.Key)
|
||||
actualUpdate, found, err := actual.GetObject(expectedUpdate.Key)
|
||||
if err != nil {
|
||||
res += fmt.Sprintf("Object %s: ERROR: %v\n", keyStr, err)
|
||||
return true
|
||||
}
|
||||
if !found {
|
||||
res += fmt.Sprintf("Object %s: NOT FOUND\n", fmtObjectKey(expected.ObjectType(), expectedUpdate.Key))
|
||||
res += fmt.Sprintf("Object %s: NOT FOUND\n", keyStr)
|
||||
return true
|
||||
}
|
||||
|
||||
if expectedUpdate.Delete != actualUpdate.Delete {
|
||||
res += fmt.Sprintf("Object %s: Deleted mismatch, expected %v, got %v\n", fmtObjectKey(expected.ObjectType(), expectedUpdate.Key), expectedUpdate.Delete, actualUpdate.Delete)
|
||||
res += fmt.Sprintf("Object %s: Deleted mismatch, expected %v, got %v\n", keyStr, expectedUpdate.Delete, actualUpdate.Delete)
|
||||
}
|
||||
|
||||
if expectedUpdate.Delete {
|
||||
@ -55,7 +58,7 @@ func DiffObjectCollections(expected, actual ObjectCollectionState) string {
|
||||
valueDiff := schematesting.DiffObjectValues(expected.ObjectType().ValueFields, expectedUpdate.Value, actualUpdate.Value)
|
||||
if valueDiff != "" {
|
||||
res += "Object "
|
||||
res += fmtObjectKey(expected.ObjectType(), expectedUpdate.Key)
|
||||
res += keyStr
|
||||
res += "\n"
|
||||
res += indentAllLines(valueDiff)
|
||||
}
|
||||
|
||||
15
schema/view/app.go
Normal file
15
schema/view/app.go
Normal file
@ -0,0 +1,15 @@
|
||||
package view
|
||||
|
||||
// AppState defines an interface for things that represent application state in schema format.
|
||||
type AppState interface {
|
||||
// GetModule returns the module state for the given module name. If the module does not exist, nil and no error
|
||||
// should be returned.
|
||||
GetModule(moduleName string) (ModuleState, error)
|
||||
|
||||
// Modules iterates over all the module state instances in the app. If there is an error getting a module state,
|
||||
// modState may be nil and err will be non-nil.
|
||||
Modules(f func(modState ModuleState, err error) bool)
|
||||
|
||||
// NumModules returns the number of modules in the app.
|
||||
NumModules() (int, error)
|
||||
}
|
||||
16
schema/view/app_data.go
Normal file
16
schema/view/app_data.go
Normal file
@ -0,0 +1,16 @@
|
||||
package view
|
||||
|
||||
// AppData is an interface which indexer data targets can implement to allow their app data including
|
||||
// state, blocks, transactions and events to be queried. An app's state and event store can also implement
|
||||
// this interface to provide an authoritative source of data for comparing with indexed data.
|
||||
type AppData interface {
|
||||
// BlockNum indicates the last block that was persisted. It should be 0 if the target has no data
|
||||
// stored and wants to start syncing state.
|
||||
// If an indexer starts indexing after a chain's genesis (returning 0), the indexer manager
|
||||
// will attempt to perform a catch-up sync of state. Historical events will not be replayed, but an accurate
|
||||
// representation of the current state at the height at which indexing began can be reproduced.
|
||||
BlockNum() (uint64, error)
|
||||
|
||||
// AppState returns the app state. If the view doesn't persist app state, nil should be returned.
|
||||
AppState() AppState
|
||||
}
|
||||
2
schema/view/doc.go
Normal file
2
schema/view/doc.go
Normal file
@ -0,0 +1,2 @@
|
||||
// Package view defines interfaces for viewing the data stored in an indexer target or an app's original data store.
|
||||
package view
|
||||
23
schema/view/module.go
Normal file
23
schema/view/module.go
Normal file
@ -0,0 +1,23 @@
|
||||
package view
|
||||
|
||||
import "cosmossdk.io/schema"
|
||||
|
||||
// ModuleState defines an interface for things that represent module state in schema format.
|
||||
type ModuleState interface {
|
||||
// ModuleName returns the name of the module.
|
||||
ModuleName() string
|
||||
|
||||
// ModuleSchema returns the schema for the module.
|
||||
ModuleSchema() schema.ModuleSchema
|
||||
|
||||
// GetObjectCollection returns the object collection for the given object type. If the object collection
|
||||
// does not exist, nil and no error should be returned
|
||||
GetObjectCollection(objectType string) (ObjectCollection, error)
|
||||
|
||||
// ObjectCollections iterates over all the object collections in the module. If there is an error getting an object
|
||||
// collection, objColl may be nil and err will be non-nil.
|
||||
ObjectCollections(f func(value ObjectCollection, err error) bool)
|
||||
|
||||
// NumObjectCollections returns the number of object collections in the module.
|
||||
NumObjectCollections() (int, error)
|
||||
}
|
||||
27
schema/view/object.go
Normal file
27
schema/view/object.go
Normal file
@ -0,0 +1,27 @@
|
||||
package view
|
||||
|
||||
import "cosmossdk.io/schema"
|
||||
|
||||
// ObjectCollection is the interface for viewing the state of a collection of objects in a module
|
||||
// represented by ObjectUpdate's for an ObjectType. ObjectUpdates must not include
|
||||
// ValueUpdates in the Value field. When ValueUpdates are applied they must be
|
||||
// converted to individual value or array format depending on the number of fields in
|
||||
// the value. For collections which retain deletions, ObjectUpdate's with the Delete
|
||||
// field set to true should be returned with the latest Value still intact.
|
||||
type ObjectCollection interface {
|
||||
// ObjectType returns the object type for the collection.
|
||||
ObjectType() schema.ObjectType
|
||||
|
||||
// GetObject returns the object update for the given key if it exists. And error should only be returned
|
||||
// if there was an error getting the object update. If the object does not exist but there was no error,
|
||||
// then found should be false and the error should be nil.
|
||||
GetObject(key interface{}) (update schema.ObjectUpdate, found bool, err error)
|
||||
|
||||
// AllState iterates over the state of the collection by calling the given function with each item in
|
||||
// state represented as an object update. If there is an error getting an object update, the error will be
|
||||
// non-nil and the object update should be empty.
|
||||
AllState(f func(schema.ObjectUpdate, error) bool)
|
||||
|
||||
// Len returns the number of objects in the collection.
|
||||
Len() (int, error)
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user