github.com/MetalBlockchain/metalgo@v1.11.9/snow/engine/common/test_sender.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package common 5 6 import ( 7 "context" 8 "errors" 9 10 "github.com/stretchr/testify/require" 11 12 "github.com/MetalBlockchain/metalgo/ids" 13 "github.com/MetalBlockchain/metalgo/utils/set" 14 ) 15 16 var ( 17 _ Sender = (*SenderTest)(nil) 18 _ AppSender = (*FakeSender)(nil) 19 20 errSendAppRequest = errors.New("unexpectedly called SendAppRequest") 21 errSendAppResponse = errors.New("unexpectedly called SendAppResponse") 22 errSendAppError = errors.New("unexpectedly called SendAppError") 23 errSendAppGossip = errors.New("unexpectedly called SendAppGossip") 24 ) 25 26 // SenderTest is a test sender 27 type SenderTest struct { 28 T require.TestingT 29 30 CantSendGetStateSummaryFrontier, CantSendStateSummaryFrontier, 31 CantSendGetAcceptedStateSummary, CantSendAcceptedStateSummary, 32 CantSendGetAcceptedFrontier, CantSendAcceptedFrontier, 33 CantSendGetAccepted, CantSendAccepted, 34 CantSendGet, CantSendGetAncestors, CantSendPut, CantSendAncestors, 35 CantSendPullQuery, CantSendPushQuery, CantSendChits, 36 CantSendAppRequest, CantSendAppResponse, CantSendAppError, 37 CantSendAppGossip, 38 CantSendCrossChainAppRequest, CantSendCrossChainAppResponse, CantSendCrossChainAppError bool 39 40 SendGetStateSummaryFrontierF func(context.Context, set.Set[ids.NodeID], uint32) 41 SendStateSummaryFrontierF func(context.Context, ids.NodeID, uint32, []byte) 42 SendGetAcceptedStateSummaryF func(context.Context, set.Set[ids.NodeID], uint32, []uint64) 43 SendAcceptedStateSummaryF func(context.Context, ids.NodeID, uint32, []ids.ID) 44 SendGetAcceptedFrontierF func(context.Context, set.Set[ids.NodeID], uint32) 45 SendAcceptedFrontierF func(context.Context, ids.NodeID, uint32, ids.ID) 46 SendGetAcceptedF func(context.Context, set.Set[ids.NodeID], uint32, []ids.ID) 47 SendAcceptedF func(context.Context, ids.NodeID, uint32, []ids.ID) 48 SendGetF func(context.Context, ids.NodeID, uint32, ids.ID) 49 SendGetAncestorsF func(context.Context, ids.NodeID, uint32, ids.ID) 50 SendPutF func(context.Context, ids.NodeID, uint32, []byte) 51 SendAncestorsF func(context.Context, ids.NodeID, uint32, [][]byte) 52 SendPushQueryF func(context.Context, set.Set[ids.NodeID], uint32, []byte, uint64) 53 SendPullQueryF func(context.Context, set.Set[ids.NodeID], uint32, ids.ID, uint64) 54 SendChitsF func(context.Context, ids.NodeID, uint32, ids.ID, ids.ID, ids.ID) 55 SendAppRequestF func(context.Context, set.Set[ids.NodeID], uint32, []byte) error 56 SendAppResponseF func(context.Context, ids.NodeID, uint32, []byte) error 57 SendAppErrorF func(context.Context, ids.NodeID, uint32, int32, string) error 58 SendAppGossipF func(context.Context, SendConfig, []byte) error 59 SendCrossChainAppRequestF func(context.Context, ids.ID, uint32, []byte) 60 SendCrossChainAppResponseF func(context.Context, ids.ID, uint32, []byte) 61 SendCrossChainAppErrorF func(context.Context, ids.ID, uint32, int32, string) 62 } 63 64 // Default set the default callable value to [cant] 65 func (s *SenderTest) Default(cant bool) { 66 s.CantSendGetStateSummaryFrontier = cant 67 s.CantSendStateSummaryFrontier = cant 68 s.CantSendGetAcceptedStateSummary = cant 69 s.CantSendAcceptedStateSummary = cant 70 s.CantSendGetAcceptedFrontier = cant 71 s.CantSendAcceptedFrontier = cant 72 s.CantSendGetAccepted = cant 73 s.CantSendAccepted = cant 74 s.CantSendGet = cant 75 s.CantSendGetAccepted = cant 76 s.CantSendPut = cant 77 s.CantSendAncestors = cant 78 s.CantSendPullQuery = cant 79 s.CantSendPushQuery = cant 80 s.CantSendChits = cant 81 s.CantSendAppRequest = cant 82 s.CantSendAppResponse = cant 83 s.CantSendAppGossip = cant 84 s.CantSendCrossChainAppRequest = cant 85 s.CantSendCrossChainAppResponse = cant 86 } 87 88 // SendGetStateSummaryFrontier calls SendGetStateSummaryFrontierF if it was 89 // initialized. If it wasn't initialized and this function shouldn't be called 90 // and testing was initialized, then testing will fail. 91 func (s *SenderTest) SendGetStateSummaryFrontier(ctx context.Context, validatorIDs set.Set[ids.NodeID], requestID uint32) { 92 if s.SendGetStateSummaryFrontierF != nil { 93 s.SendGetStateSummaryFrontierF(ctx, validatorIDs, requestID) 94 } else if s.CantSendGetStateSummaryFrontier && s.T != nil { 95 require.FailNow(s.T, "Unexpectedly called SendGetStateSummaryFrontier") 96 } 97 } 98 99 // SendStateSummaryFrontier calls SendStateSummaryFrontierF if it was 100 // initialized. If it wasn't initialized and this function shouldn't be called 101 // and testing was initialized, then testing will fail. 102 func (s *SenderTest) SendStateSummaryFrontier(ctx context.Context, validatorID ids.NodeID, requestID uint32, summary []byte) { 103 if s.SendStateSummaryFrontierF != nil { 104 s.SendStateSummaryFrontierF(ctx, validatorID, requestID, summary) 105 } else if s.CantSendStateSummaryFrontier && s.T != nil { 106 require.FailNow(s.T, "Unexpectedly called SendStateSummaryFrontier") 107 } 108 } 109 110 // SendGetAcceptedStateSummary calls SendGetAcceptedStateSummaryF if it was 111 // initialized. If it wasn't initialized and this function shouldn't be called 112 // and testing was initialized, then testing will fail. 113 func (s *SenderTest) SendGetAcceptedStateSummary(ctx context.Context, nodeIDs set.Set[ids.NodeID], requestID uint32, heights []uint64) { 114 if s.SendGetAcceptedStateSummaryF != nil { 115 s.SendGetAcceptedStateSummaryF(ctx, nodeIDs, requestID, heights) 116 } else if s.CantSendGetAcceptedStateSummary && s.T != nil { 117 require.FailNow(s.T, "Unexpectedly called SendGetAcceptedStateSummaryF") 118 } 119 } 120 121 // SendAcceptedStateSummary calls SendAcceptedStateSummaryF if it was 122 // initialized. If it wasn't initialized and this function shouldn't be called 123 // and testing was initialized, then testing will fail. 124 func (s *SenderTest) SendAcceptedStateSummary(ctx context.Context, validatorID ids.NodeID, requestID uint32, summaryIDs []ids.ID) { 125 if s.SendAcceptedStateSummaryF != nil { 126 s.SendAcceptedStateSummaryF(ctx, validatorID, requestID, summaryIDs) 127 } else if s.CantSendAcceptedStateSummary && s.T != nil { 128 require.FailNow(s.T, "Unexpectedly called SendAcceptedStateSummary") 129 } 130 } 131 132 // SendGetAcceptedFrontier calls SendGetAcceptedFrontierF if it was initialized. 133 // If it wasn't initialized and this function shouldn't be called and testing 134 // was initialized, then testing will fail. 135 func (s *SenderTest) SendGetAcceptedFrontier(ctx context.Context, validatorIDs set.Set[ids.NodeID], requestID uint32) { 136 if s.SendGetAcceptedFrontierF != nil { 137 s.SendGetAcceptedFrontierF(ctx, validatorIDs, requestID) 138 } else if s.CantSendGetAcceptedFrontier && s.T != nil { 139 require.FailNow(s.T, "Unexpectedly called SendGetAcceptedFrontier") 140 } 141 } 142 143 // SendAcceptedFrontier calls SendAcceptedFrontierF if it was initialized. If it 144 // wasn't initialized and this function shouldn't be called and testing was 145 // initialized, then testing will fail. 146 func (s *SenderTest) SendAcceptedFrontier(ctx context.Context, validatorID ids.NodeID, requestID uint32, containerID ids.ID) { 147 if s.SendAcceptedFrontierF != nil { 148 s.SendAcceptedFrontierF(ctx, validatorID, requestID, containerID) 149 } else if s.CantSendAcceptedFrontier && s.T != nil { 150 require.FailNow(s.T, "Unexpectedly called SendAcceptedFrontier") 151 } 152 } 153 154 // SendGetAccepted calls SendGetAcceptedF if it was initialized. If it wasn't 155 // initialized and this function shouldn't be called and testing was 156 // initialized, then testing will fail. 157 func (s *SenderTest) SendGetAccepted(ctx context.Context, nodeIDs set.Set[ids.NodeID], requestID uint32, containerIDs []ids.ID) { 158 if s.SendGetAcceptedF != nil { 159 s.SendGetAcceptedF(ctx, nodeIDs, requestID, containerIDs) 160 } else if s.CantSendGetAccepted && s.T != nil { 161 require.FailNow(s.T, "Unexpectedly called SendGetAccepted") 162 } 163 } 164 165 // SendAccepted calls SendAcceptedF if it was initialized. If it wasn't 166 // initialized and this function shouldn't be called and testing was 167 // initialized, then testing will fail. 168 func (s *SenderTest) SendAccepted(ctx context.Context, validatorID ids.NodeID, requestID uint32, containerIDs []ids.ID) { 169 if s.SendAcceptedF != nil { 170 s.SendAcceptedF(ctx, validatorID, requestID, containerIDs) 171 } else if s.CantSendAccepted && s.T != nil { 172 require.FailNow(s.T, "Unexpectedly called SendAccepted") 173 } 174 } 175 176 // SendGet calls SendGetF if it was initialized. If it wasn't initialized and 177 // this function shouldn't be called and testing was initialized, then testing 178 // will fail. 179 func (s *SenderTest) SendGet(ctx context.Context, vdr ids.NodeID, requestID uint32, containerID ids.ID) { 180 if s.SendGetF != nil { 181 s.SendGetF(ctx, vdr, requestID, containerID) 182 } else if s.CantSendGet && s.T != nil { 183 require.FailNow(s.T, "Unexpectedly called SendGet") 184 } 185 } 186 187 // SendGetAncestors calls SendGetAncestorsF if it was initialized. If it wasn't 188 // initialized and this function shouldn't be called and testing was 189 // initialized, then testing will fail. 190 func (s *SenderTest) SendGetAncestors(ctx context.Context, validatorID ids.NodeID, requestID uint32, containerID ids.ID) { 191 if s.SendGetAncestorsF != nil { 192 s.SendGetAncestorsF(ctx, validatorID, requestID, containerID) 193 } else if s.CantSendGetAncestors && s.T != nil { 194 require.FailNow(s.T, "Unexpectedly called SendCantSendGetAncestors") 195 } 196 } 197 198 // SendPut calls SendPutF if it was initialized. If it wasn't initialized and 199 // this function shouldn't be called and testing was initialized, then testing 200 // will fail. 201 func (s *SenderTest) SendPut(ctx context.Context, vdr ids.NodeID, requestID uint32, container []byte) { 202 if s.SendPutF != nil { 203 s.SendPutF(ctx, vdr, requestID, container) 204 } else if s.CantSendPut && s.T != nil { 205 require.FailNow(s.T, "Unexpectedly called SendPut") 206 } 207 } 208 209 // SendAncestors calls SendAncestorsF if it was initialized. If it wasn't 210 // initialized and this function shouldn't be called and testing was 211 // initialized, then testing will fail. 212 func (s *SenderTest) SendAncestors(ctx context.Context, vdr ids.NodeID, requestID uint32, containers [][]byte) { 213 if s.SendAncestorsF != nil { 214 s.SendAncestorsF(ctx, vdr, requestID, containers) 215 } else if s.CantSendAncestors && s.T != nil { 216 require.FailNow(s.T, "Unexpectedly called SendAncestors") 217 } 218 } 219 220 // SendPushQuery calls SendPushQueryF if it was initialized. If it wasn't 221 // initialized and this function shouldn't be called and testing was 222 // initialized, then testing will fail. 223 func (s *SenderTest) SendPushQuery(ctx context.Context, vdrs set.Set[ids.NodeID], requestID uint32, container []byte, requestedHeight uint64) { 224 if s.SendPushQueryF != nil { 225 s.SendPushQueryF(ctx, vdrs, requestID, container, requestedHeight) 226 } else if s.CantSendPushQuery && s.T != nil { 227 require.FailNow(s.T, "Unexpectedly called SendPushQuery") 228 } 229 } 230 231 // SendPullQuery calls SendPullQueryF if it was initialized. If it wasn't 232 // initialized and this function shouldn't be called and testing was 233 // initialized, then testing will fail. 234 func (s *SenderTest) SendPullQuery(ctx context.Context, vdrs set.Set[ids.NodeID], requestID uint32, containerID ids.ID, requestedHeight uint64) { 235 if s.SendPullQueryF != nil { 236 s.SendPullQueryF(ctx, vdrs, requestID, containerID, requestedHeight) 237 } else if s.CantSendPullQuery && s.T != nil { 238 require.FailNow(s.T, "Unexpectedly called SendPullQuery") 239 } 240 } 241 242 // SendChits calls SendChitsF if it was initialized. If it wasn't initialized 243 // and this function shouldn't be called and testing was initialized, then 244 // testing will fail. 245 func (s *SenderTest) SendChits(ctx context.Context, vdr ids.NodeID, requestID uint32, preferredID ids.ID, preferredIDAtHeight ids.ID, acceptedID ids.ID) { 246 if s.SendChitsF != nil { 247 s.SendChitsF(ctx, vdr, requestID, preferredID, preferredIDAtHeight, acceptedID) 248 } else if s.CantSendChits && s.T != nil { 249 require.FailNow(s.T, "Unexpectedly called SendChits") 250 } 251 } 252 253 // SendCrossChainAppRequest calls SendCrossChainAppRequestF if it was 254 // initialized. If it wasn't initialized and this function shouldn't be called 255 // and testing was initialized, then testing will fail. 256 func (s *SenderTest) SendCrossChainAppRequest(ctx context.Context, chainID ids.ID, requestID uint32, appRequestBytes []byte) error { 257 if s.SendCrossChainAppRequestF != nil { 258 s.SendCrossChainAppRequestF(ctx, chainID, requestID, appRequestBytes) 259 } else if s.CantSendCrossChainAppRequest && s.T != nil { 260 require.FailNow(s.T, "Unexpectedly called SendCrossChainAppRequest") 261 } 262 return nil 263 } 264 265 // SendCrossChainAppResponse calls SendCrossChainAppResponseF if it was 266 // initialized. If it wasn't initialized and this function shouldn't be called 267 // and testing was initialized, then testing will fail. 268 func (s *SenderTest) SendCrossChainAppResponse(ctx context.Context, chainID ids.ID, requestID uint32, appResponseBytes []byte) error { 269 if s.SendCrossChainAppResponseF != nil { 270 s.SendCrossChainAppResponseF(ctx, chainID, requestID, appResponseBytes) 271 } else if s.CantSendCrossChainAppResponse && s.T != nil { 272 require.FailNow(s.T, "Unexpectedly called SendCrossChainAppResponse") 273 } 274 return nil 275 } 276 277 // SendCrossChainAppError calls SendCrossChainAppErrorF if it was 278 // initialized. If it wasn't initialized and this function shouldn't be called 279 // and testing was initialized, then testing will fail. 280 func (s *SenderTest) SendCrossChainAppError(ctx context.Context, chainID ids.ID, requestID uint32, errorCode int32, errorMessage string) error { 281 if s.SendCrossChainAppErrorF != nil { 282 s.SendCrossChainAppErrorF(ctx, chainID, requestID, errorCode, errorMessage) 283 } else if s.CantSendCrossChainAppError && s.T != nil { 284 require.FailNow(s.T, "Unexpectedly called SendCrossChainAppError") 285 } 286 return nil 287 } 288 289 // SendAppRequest calls SendAppRequestF if it was initialized. If it wasn't 290 // initialized and this function shouldn't be called and testing was 291 // initialized, then testing will fail. 292 func (s *SenderTest) SendAppRequest(ctx context.Context, nodeIDs set.Set[ids.NodeID], requestID uint32, appRequestBytes []byte) error { 293 switch { 294 case s.SendAppRequestF != nil: 295 return s.SendAppRequestF(ctx, nodeIDs, requestID, appRequestBytes) 296 case s.CantSendAppRequest && s.T != nil: 297 require.FailNow(s.T, errSendAppRequest.Error()) 298 } 299 return errSendAppRequest 300 } 301 302 // SendAppResponse calls SendAppResponseF if it was initialized. If it wasn't 303 // initialized and this function shouldn't be called and testing was 304 // initialized, then testing will fail. 305 func (s *SenderTest) SendAppResponse(ctx context.Context, nodeID ids.NodeID, requestID uint32, appResponseBytes []byte) error { 306 switch { 307 case s.SendAppResponseF != nil: 308 return s.SendAppResponseF(ctx, nodeID, requestID, appResponseBytes) 309 case s.CantSendAppResponse && s.T != nil: 310 require.FailNow(s.T, errSendAppResponse.Error()) 311 } 312 return errSendAppResponse 313 } 314 315 // SendAppError calls SendAppErrorF if it was initialized. If it wasn't 316 // initialized and this function shouldn't be called and testing was 317 // initialized, then testing will fail. 318 func (s *SenderTest) SendAppError(ctx context.Context, nodeID ids.NodeID, requestID uint32, code int32, message string) error { 319 switch { 320 case s.SendAppErrorF != nil: 321 return s.SendAppErrorF(ctx, nodeID, requestID, code, message) 322 case s.CantSendAppError && s.T != nil: 323 require.FailNow(s.T, errSendAppError.Error()) 324 } 325 return errSendAppError 326 } 327 328 // SendAppGossip calls SendAppGossipF if it was initialized. If it wasn't 329 // initialized and this function shouldn't be called and testing was 330 // initialized, then testing will fail. 331 func (s *SenderTest) SendAppGossip( 332 ctx context.Context, 333 config SendConfig, 334 appGossipBytes []byte, 335 ) error { 336 switch { 337 case s.SendAppGossipF != nil: 338 return s.SendAppGossipF(ctx, config, appGossipBytes) 339 case s.CantSendAppGossip && s.T != nil: 340 require.FailNow(s.T, errSendAppGossip.Error()) 341 } 342 return errSendAppGossip 343 } 344 345 // FakeSender is used for testing 346 type FakeSender struct { 347 SentAppRequest, SentAppResponse, 348 SentAppGossip, 349 SentCrossChainAppRequest, SentCrossChainAppResponse chan []byte 350 351 SentAppError, SentCrossChainAppError chan *AppError 352 } 353 354 func (f FakeSender) SendAppRequest(_ context.Context, _ set.Set[ids.NodeID], _ uint32, bytes []byte) error { 355 if f.SentAppRequest == nil { 356 return nil 357 } 358 359 f.SentAppRequest <- bytes 360 return nil 361 } 362 363 func (f FakeSender) SendAppResponse(_ context.Context, _ ids.NodeID, _ uint32, bytes []byte) error { 364 if f.SentAppResponse == nil { 365 return nil 366 } 367 368 f.SentAppResponse <- bytes 369 return nil 370 } 371 372 func (f FakeSender) SendAppError(_ context.Context, _ ids.NodeID, _ uint32, errorCode int32, errorMessage string) error { 373 if f.SentAppError == nil { 374 return nil 375 } 376 377 f.SentAppError <- &AppError{ 378 Code: errorCode, 379 Message: errorMessage, 380 } 381 return nil 382 } 383 384 func (f FakeSender) SendAppGossip(_ context.Context, _ SendConfig, bytes []byte) error { 385 if f.SentAppGossip == nil { 386 return nil 387 } 388 389 f.SentAppGossip <- bytes 390 return nil 391 } 392 393 func (f FakeSender) SendCrossChainAppRequest(_ context.Context, _ ids.ID, _ uint32, bytes []byte) error { 394 if f.SentCrossChainAppRequest == nil { 395 return nil 396 } 397 398 f.SentCrossChainAppRequest <- bytes 399 return nil 400 } 401 402 func (f FakeSender) SendCrossChainAppResponse(_ context.Context, _ ids.ID, _ uint32, bytes []byte) error { 403 if f.SentCrossChainAppResponse == nil { 404 return nil 405 } 406 407 f.SentCrossChainAppResponse <- bytes 408 return nil 409 } 410 411 func (f FakeSender) SendCrossChainAppError(_ context.Context, _ ids.ID, _ uint32, errorCode int32, errorMessage string) error { 412 if f.SentCrossChainAppError == nil { 413 return nil 414 } 415 416 f.SentCrossChainAppError <- &AppError{ 417 Code: errorCode, 418 Message: errorMessage, 419 } 420 return nil 421 }