node/node_test: add TestWatcherConfig
This commit is contained in:
parent
670117f601
commit
e240477798
|
@ -255,7 +255,7 @@ func GuardianOptionWatchers(watcherConfigs []watchers.WatcherConfig, ibcWatcherC
|
|||
|
||||
for _, wc := range watcherConfigs {
|
||||
if _, ok := watchers[wc.GetNetworkID()]; ok {
|
||||
logger.Fatal("NetworkID already configured", zap.String("network_id", string(wc.GetNetworkID())))
|
||||
return fmt.Errorf("NetworkID already configured: %s", string(wc.GetNetworkID()))
|
||||
}
|
||||
|
||||
watcherName := string(wc.GetNetworkID()) + "watch"
|
||||
|
@ -280,7 +280,7 @@ func GuardianOptionWatchers(watcherConfigs []watchers.WatcherConfig, ibcWatcherC
|
|||
l1finalizer, runnable, err := wc.Create(chainMsgC[wc.GetChainID()], chainObsvReqC[wc.GetChainID()], g.setC.writeC, g.env)
|
||||
|
||||
if err != nil {
|
||||
logger.Fatal("error creating watcher", zap.Error(err))
|
||||
return fmt.Errorf("error creating watcher: %w", err)
|
||||
}
|
||||
|
||||
g.runnablesWithScissors[watcherName] = runnable
|
||||
|
@ -316,7 +316,7 @@ func GuardianOptionWatchers(watcherConfigs []watchers.WatcherConfig, ibcWatcherC
|
|||
readiness.RegisterComponent(common.ReadinessIBCSyncing)
|
||||
g.runnablesWithScissors["ibcwatch"] = ibc.NewWatcher(ibcWatcherConfig.Websocket, ibcWatcherConfig.Lcd, ibcWatcherConfig.Contract, chainConfig).Run
|
||||
} else {
|
||||
logger.Error("Although IBC is enabled, there are no chains for it to monitor")
|
||||
return errors.New("Although IBC is enabled, there are no chains for it to monitor")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -563,6 +563,7 @@ func (g *G) Run(rootCtxCancel context.CancelFunc, options ...*GuardianOption) su
|
|||
if err := g.applyOptions(ctx, logger, options); err != nil {
|
||||
logger.Fatal("failed to initialize GuardianNode", zap.Error(err))
|
||||
}
|
||||
logger.Info("GuardianNode initialization done.") // Do not modify this message, node_test.go relies on it.
|
||||
|
||||
// Start the watchers
|
||||
for runnableName, runnable := range g.runnablesWithScissors {
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -184,9 +185,11 @@ func mockGuardianRunnable(gs []*mockGuardian, mockGuardianIndex uint, obsDb mock
|
|||
}
|
||||
|
||||
// setupLogsCapture is a helper function for making a zap logger/observer combination for testing that certain logs have been made
|
||||
func setupLogsCapture() (*zap.Logger, *observer.ObservedLogs) {
|
||||
func setupLogsCapture(options ...zap.Option) (*zap.Logger, *observer.ObservedLogs) {
|
||||
observedCore, logs := observer.New(zap.DebugLevel)
|
||||
logger, _ := zap.NewDevelopment(zap.WrapCore(func(c zapcore.Core) zapcore.Core { return zapcore.NewTee(c, observedCore) }))
|
||||
wcOpt := zap.WrapCore(func(c zapcore.Core) zapcore.Core { return zapcore.NewTee(c, observedCore) })
|
||||
options = append(options, wcOpt)
|
||||
logger, _ := zap.NewDevelopment(options...)
|
||||
return logger, logs
|
||||
}
|
||||
|
||||
|
@ -354,9 +357,137 @@ func TestMain(m *testing.M) {
|
|||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
// TestInvalidWatcherConfig tries to instantiate a guardian with various invlid []watchers.WatcherConfig and asserts that it errors
|
||||
func TestInvalidWatcherConfig(t *testing.T) {
|
||||
// TODO
|
||||
type testCaseGuardianConfig struct {
|
||||
name string
|
||||
opts []*GuardianOption
|
||||
err string
|
||||
}
|
||||
|
||||
// TestWatcherConfigs tries to instantiate a guardian with various invlid []watchers.WatcherConfig and asserts that it errors
|
||||
func TestWatcherConfigs(t *testing.T) {
|
||||
tc := []testCaseGuardianConfig{
|
||||
{
|
||||
name: "no error",
|
||||
opts: []*GuardianOption{
|
||||
GuardianOptionWatchers([]watchers.WatcherConfig{
|
||||
&mock.WatcherConfig{
|
||||
NetworkID: "mock",
|
||||
ChainID: vaa.ChainIDSolana,
|
||||
},
|
||||
}, nil),
|
||||
},
|
||||
err: "",
|
||||
},
|
||||
{
|
||||
name: "watcher-NetworkID-collision",
|
||||
opts: []*GuardianOption{
|
||||
GuardianOptionWatchers([]watchers.WatcherConfig{
|
||||
&mock.WatcherConfig{
|
||||
NetworkID: "mock",
|
||||
ChainID: vaa.ChainIDSolana,
|
||||
},
|
||||
&mock.WatcherConfig{
|
||||
NetworkID: "mock",
|
||||
ChainID: vaa.ChainIDSolana,
|
||||
},
|
||||
}, nil),
|
||||
},
|
||||
err: "NetworkID already configured: mock",
|
||||
},
|
||||
}
|
||||
testGuardianConfigurations(t, tc)
|
||||
}
|
||||
|
||||
func TestGuardianConfigs(t *testing.T) {
|
||||
tc := []testCaseGuardianConfig{
|
||||
{
|
||||
name: "unfulfilled-dependency",
|
||||
opts: []*GuardianOption{
|
||||
GuardianOptionAccountant("", "", false, nil),
|
||||
},
|
||||
err: "Check the order of your options.",
|
||||
},
|
||||
}
|
||||
testGuardianConfigurations(t, tc)
|
||||
}
|
||||
|
||||
func testGuardianConfigurations(t *testing.T, testCases []testCaseGuardianConfig) {
|
||||
for _, tc := range testCases {
|
||||
// because we're only instantiating the guardians and kill them right after they started running, 2s should be plenty of time
|
||||
const testTimeout = time.Second * 2
|
||||
|
||||
// Test's main lifecycle context.
|
||||
rootCtx, rootCtxCancel := context.WithTimeout(context.Background(), testTimeout)
|
||||
defer rootCtxCancel()
|
||||
|
||||
// we need to catch a zap.Logger.Fatal() here.
|
||||
// By default zap.Logger.Fatal() will os.Exit(1), which we can't catch.
|
||||
// We modify zap's behavior to instead assert that the error is the one we're looking for and then panic
|
||||
// The panic will be subsequently caught by the supervisor
|
||||
fatalHook := make(fatalHook)
|
||||
defer close(fatalHook)
|
||||
zapLogger, zapObserver := setupLogsCapture(zap.WithFatalHook(fatalHook))
|
||||
|
||||
supervisor.New(rootCtx, zapLogger, func(ctx context.Context) error {
|
||||
// Create a sub-context with cancel function that we can pass to G.run.
|
||||
ctx, ctxCancel := context.WithCancel(ctx)
|
||||
defer ctxCancel()
|
||||
logger := supervisor.Logger(ctx)
|
||||
|
||||
if err := supervisor.Run(ctx, tc.name, NewGuardianNode(common.GoTest, nil).Run(ctxCancel, tc.opts...)); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
supervisor.Signal(ctx, supervisor.SignalHealthy)
|
||||
|
||||
// wait for all options to get applied
|
||||
// If we were expecting an error, we should never get past this point.
|
||||
for len(zapObserver.FilterMessage("GuardianNode initialization done.").All()) == 0 {
|
||||
//logger.Info("Guardian not yet initialized. Waiting 10ms...")
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
}
|
||||
|
||||
// Test done.
|
||||
logger.Info("Test done.")
|
||||
supervisor.Signal(ctx, supervisor.SignalDone)
|
||||
rootCtxCancel()
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
select {
|
||||
case r := <-fatalHook:
|
||||
if tc.err == "" {
|
||||
assert.Equal(t, tc.err, r)
|
||||
}
|
||||
assert.Contains(t, r, tc.err)
|
||||
rootCtxCancel()
|
||||
case <-rootCtx.Done():
|
||||
assert.NotEqual(t, rootCtx.Err(), context.DeadlineExceeded)
|
||||
assert.Equal(t, tc.err, "") // we only want to end up here if we did not expect an error.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fatalHook catches zap.Logger.Fatal(), sends them to triggerC, and then panics.
|
||||
type fatalHook chan string
|
||||
|
||||
func (c fatalHook) OnWrite(ce *zapcore.CheckedEntry, fields []zapcore.Field) {
|
||||
// construct message, which will be the main log message, followed by all errors
|
||||
var sb strings.Builder
|
||||
|
||||
sb.WriteString(ce.Message)
|
||||
|
||||
for _, f := range fields {
|
||||
err, ok := f.Interface.(error)
|
||||
if ok {
|
||||
sb.WriteString(", error:")
|
||||
sb.WriteString(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
c <- sb.String()
|
||||
panic(ce.Message)
|
||||
}
|
||||
|
||||
// TestBasicConsensus tests that a set of guardians can form consensus on certain messages and reject certain other messages
|
||||
|
|
Loading…
Reference in New Issue