github.com/MetalBlockchain/metalgo@v1.11.9/snow/consensus/snowman/bootstrapper/minority_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 bootstrapper 5 6 import ( 7 "context" 8 "testing" 9 10 "github.com/stretchr/testify/require" 11 12 "github.com/MetalBlockchain/metalgo/ids" 13 "github.com/MetalBlockchain/metalgo/utils/logging" 14 "github.com/MetalBlockchain/metalgo/utils/set" 15 ) 16 17 func TestNewMinority(t *testing.T) { 18 minority := NewMinority( 19 logging.NoLog{}, // log 20 set.Of(nodeID0), // frontierNodes 21 2, // maxOutstanding 22 ) 23 24 expectedMinority := &Minority{ 25 requests: requests{ 26 maxOutstanding: 2, 27 pendingSend: set.Of(nodeID0), 28 }, 29 log: logging.NoLog{}, 30 } 31 require.Equal(t, expectedMinority, minority) 32 } 33 34 func TestMinorityGetPeers(t *testing.T) { 35 tests := []struct { 36 name string 37 minority Poll 38 expectedState Poll 39 expectedPeers set.Set[ids.NodeID] 40 }{ 41 { 42 name: "max outstanding", 43 minority: &Minority{ 44 requests: requests{ 45 maxOutstanding: 1, 46 pendingSend: set.Of(nodeID0), 47 outstanding: set.Of(nodeID1), 48 }, 49 log: logging.NoLog{}, 50 }, 51 expectedState: &Minority{ 52 requests: requests{ 53 maxOutstanding: 1, 54 pendingSend: set.Of(nodeID0), 55 outstanding: set.Of(nodeID1), 56 }, 57 log: logging.NoLog{}, 58 }, 59 expectedPeers: nil, 60 }, 61 { 62 name: "send until max outstanding", 63 minority: &Minority{ 64 requests: requests{ 65 maxOutstanding: 2, 66 pendingSend: set.Of(nodeID0, nodeID1), 67 }, 68 log: logging.NoLog{}, 69 }, 70 expectedState: &Minority{ 71 requests: requests{ 72 maxOutstanding: 2, 73 pendingSend: set.Set[ids.NodeID]{}, 74 outstanding: set.Of(nodeID0, nodeID1), 75 }, 76 log: logging.NoLog{}, 77 }, 78 expectedPeers: set.Of(nodeID0, nodeID1), 79 }, 80 { 81 name: "send until no more to send", 82 minority: &Minority{ 83 requests: requests{ 84 maxOutstanding: 2, 85 pendingSend: set.Of(nodeID0), 86 }, 87 log: logging.NoLog{}, 88 }, 89 expectedState: &Minority{ 90 requests: requests{ 91 maxOutstanding: 2, 92 pendingSend: set.Set[ids.NodeID]{}, 93 outstanding: set.Of(nodeID0), 94 }, 95 log: logging.NoLog{}, 96 }, 97 expectedPeers: set.Of(nodeID0), 98 }, 99 } 100 for _, test := range tests { 101 t.Run(test.name, func(t *testing.T) { 102 require := require.New(t) 103 104 peers := test.minority.GetPeers(context.Background()) 105 require.Equal(test.expectedState, test.minority) 106 require.Equal(test.expectedPeers, peers) 107 }) 108 } 109 } 110 111 func TestMinorityRecordOpinion(t *testing.T) { 112 tests := []struct { 113 name string 114 minority Poll 115 nodeID ids.NodeID 116 blkIDs set.Set[ids.ID] 117 expectedState Poll 118 expectedErr error 119 }{ 120 { 121 name: "unexpected response", 122 minority: &Minority{ 123 requests: requests{ 124 maxOutstanding: 1, 125 pendingSend: set.Of(nodeID0), 126 outstanding: set.Of(nodeID1), 127 }, 128 log: logging.NoLog{}, 129 }, 130 nodeID: nodeID0, 131 blkIDs: nil, 132 expectedState: &Minority{ 133 requests: requests{ 134 maxOutstanding: 1, 135 pendingSend: set.Of(nodeID0), 136 outstanding: set.Of(nodeID1), 137 }, 138 log: logging.NoLog{}, 139 }, 140 expectedErr: nil, 141 }, 142 { 143 name: "unfinished after response", 144 minority: &Minority{ 145 requests: requests{ 146 maxOutstanding: 1, 147 pendingSend: set.Of(nodeID0), 148 outstanding: set.Of(nodeID1), 149 }, 150 log: logging.NoLog{}, 151 }, 152 nodeID: nodeID1, 153 blkIDs: set.Of(blkID0), 154 expectedState: &Minority{ 155 requests: requests{ 156 maxOutstanding: 1, 157 pendingSend: set.Of(nodeID0), 158 outstanding: set.Set[ids.NodeID]{}, 159 }, 160 log: logging.NoLog{}, 161 receivedSet: set.Of(blkID0), 162 }, 163 expectedErr: nil, 164 }, 165 { 166 name: "finished after response", 167 minority: &Minority{ 168 requests: requests{ 169 maxOutstanding: 1, 170 outstanding: set.Of(nodeID2), 171 }, 172 log: logging.NoLog{}, 173 }, 174 nodeID: nodeID2, 175 blkIDs: set.Of(blkID1), 176 expectedState: &Minority{ 177 requests: requests{ 178 maxOutstanding: 1, 179 outstanding: set.Set[ids.NodeID]{}, 180 }, 181 log: logging.NoLog{}, 182 receivedSet: set.Of(blkID1), 183 received: []ids.ID{blkID1}, 184 }, 185 expectedErr: nil, 186 }, 187 } 188 for _, test := range tests { 189 t.Run(test.name, func(t *testing.T) { 190 require := require.New(t) 191 192 err := test.minority.RecordOpinion(context.Background(), test.nodeID, test.blkIDs) 193 require.Equal(test.expectedState, test.minority) 194 require.ErrorIs(err, test.expectedErr) 195 }) 196 } 197 } 198 199 func TestMinorityResult(t *testing.T) { 200 tests := []struct { 201 name string 202 minority Poll 203 expectedAccepted []ids.ID 204 expectedFinalized bool 205 }{ 206 { 207 name: "not finalized", 208 minority: &Minority{ 209 requests: requests{ 210 maxOutstanding: 1, 211 outstanding: set.Of(nodeID1), 212 }, 213 log: logging.NoLog{}, 214 received: nil, 215 }, 216 expectedAccepted: nil, 217 expectedFinalized: false, 218 }, 219 { 220 name: "finalized", 221 minority: &Minority{ 222 requests: requests{ 223 maxOutstanding: 1, 224 }, 225 log: logging.NoLog{}, 226 receivedSet: set.Of(blkID0), 227 received: []ids.ID{blkID0}, 228 }, 229 expectedAccepted: []ids.ID{blkID0}, 230 expectedFinalized: true, 231 }, 232 } 233 for _, test := range tests { 234 t.Run(test.name, func(t *testing.T) { 235 require := require.New(t) 236 237 accepted, finalized := test.minority.Result(context.Background()) 238 require.Equal(test.expectedAccepted, accepted) 239 require.Equal(test.expectedFinalized, finalized) 240 }) 241 } 242 }