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  }