github.com/MetalBlockchain/metalgo@v1.11.9/snow/networking/handler/health_test.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package handler 5 6 import ( 7 "context" 8 "testing" 9 "time" 10 11 "github.com/prometheus/client_golang/prometheus" 12 "github.com/stretchr/testify/require" 13 14 "github.com/MetalBlockchain/metalgo/ids" 15 "github.com/MetalBlockchain/metalgo/network/p2p" 16 "github.com/MetalBlockchain/metalgo/snow" 17 "github.com/MetalBlockchain/metalgo/snow/consensus/snowball" 18 "github.com/MetalBlockchain/metalgo/snow/engine/common" 19 "github.com/MetalBlockchain/metalgo/snow/networking/tracker" 20 "github.com/MetalBlockchain/metalgo/snow/snowtest" 21 "github.com/MetalBlockchain/metalgo/snow/validators" 22 "github.com/MetalBlockchain/metalgo/subnets" 23 "github.com/MetalBlockchain/metalgo/utils/logging" 24 "github.com/MetalBlockchain/metalgo/utils/math/meter" 25 "github.com/MetalBlockchain/metalgo/utils/resource" 26 "github.com/MetalBlockchain/metalgo/utils/set" 27 "github.com/MetalBlockchain/metalgo/version" 28 29 p2ppb "github.com/MetalBlockchain/metalgo/proto/pb/p2p" 30 commontracker "github.com/MetalBlockchain/metalgo/snow/engine/common/tracker" 31 ) 32 33 func TestHealthCheckSubnet(t *testing.T) { 34 tests := map[string]struct { 35 consensusParams snowball.Parameters 36 }{ 37 "default consensus params": { 38 consensusParams: snowball.DefaultParameters, 39 }, 40 "custom consensus params": { 41 func() snowball.Parameters { 42 params := snowball.DefaultParameters 43 params.K = params.AlphaConfidence 44 return params 45 }(), 46 }, 47 } 48 49 for name, test := range tests { 50 t.Run(name, func(t *testing.T) { 51 require := require.New(t) 52 53 snowCtx := snowtest.Context(t, snowtest.CChainID) 54 ctx := snowtest.ConsensusContext(snowCtx) 55 56 vdrs := validators.NewManager() 57 58 resourceTracker, err := tracker.NewResourceTracker( 59 prometheus.NewRegistry(), 60 resource.NoUsage, 61 meter.ContinuousFactory{}, 62 time.Second, 63 ) 64 require.NoError(err) 65 66 peerTracker := commontracker.NewPeers() 67 vdrs.RegisterSetCallbackListener(ctx.SubnetID, peerTracker) 68 69 sb := subnets.New( 70 ctx.NodeID, 71 subnets.Config{ 72 ConsensusParameters: test.consensusParams, 73 }, 74 ) 75 76 p2pTracker, err := p2p.NewPeerTracker( 77 logging.NoLog{}, 78 "", 79 prometheus.NewRegistry(), 80 nil, 81 version.CurrentApp, 82 ) 83 require.NoError(err) 84 85 handlerIntf, err := New( 86 ctx, 87 vdrs, 88 nil, 89 time.Second, 90 testThreadPoolSize, 91 resourceTracker, 92 validators.UnhandledSubnetConnector, 93 sb, 94 peerTracker, 95 p2pTracker, 96 prometheus.NewRegistry(), 97 ) 98 require.NoError(err) 99 100 bootstrapper := &common.BootstrapperTest{ 101 EngineTest: common.EngineTest{ 102 T: t, 103 }, 104 } 105 bootstrapper.Default(false) 106 107 engine := &common.EngineTest{T: t} 108 engine.Default(false) 109 engine.ContextF = func() *snow.ConsensusContext { 110 return ctx 111 } 112 113 handlerIntf.SetEngineManager(&EngineManager{ 114 Snowman: &Engine{ 115 Bootstrapper: bootstrapper, 116 Consensus: engine, 117 }, 118 }) 119 120 ctx.State.Set(snow.EngineState{ 121 Type: p2ppb.EngineType_ENGINE_TYPE_SNOWMAN, 122 State: snow.NormalOp, // assumed bootstrap is done 123 }) 124 125 bootstrapper.StartF = func(context.Context, uint32) error { 126 return nil 127 } 128 129 handlerIntf.Start(context.Background(), false) 130 131 testVdrCount := 4 132 vdrIDs := set.NewSet[ids.NodeID](testVdrCount) 133 for i := 0; i < testVdrCount; i++ { 134 vdrID := ids.GenerateTestNodeID() 135 vdrIDs.Add(vdrID) 136 137 require.NoError(vdrs.AddStaker(ctx.SubnetID, vdrID, nil, ids.Empty, 100)) 138 } 139 140 for index, nodeID := range vdrIDs.List() { 141 require.NoError(peerTracker.Connected(context.Background(), nodeID, nil)) 142 143 details, err := handlerIntf.HealthCheck(context.Background()) 144 expectedPercentConnected := float64(index+1) / float64(testVdrCount) 145 conf := sb.Config() 146 minPercentConnected := conf.ConsensusParameters.MinPercentConnectedHealthy() 147 if expectedPercentConnected >= minPercentConnected { 148 require.NoError(err) 149 continue 150 } 151 require.ErrorIs(err, ErrNotConnectedEnoughStake) 152 153 detailsMap, ok := details.(map[string]interface{}) 154 require.True(ok) 155 networkingMap, ok := detailsMap["networking"] 156 require.True(ok) 157 networkingDetails, ok := networkingMap.(map[string]float64) 158 require.True(ok) 159 percentConnected, ok := networkingDetails["percentConnected"] 160 require.True(ok) 161 require.Equal(expectedPercentConnected, percentConnected) 162 } 163 }) 164 } 165 }