github.com/status-im/status-go@v1.1.0/protocol/messenger_mailserver_processMailserverBatch_test.go (about)

     1  package protocol
     2  
     3  import (
     4  	"context"
     5  	"crypto/rand"
     6  	"encoding/hex"
     7  	"errors"
     8  	"math/big"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/google/uuid"
    13  	"github.com/libp2p/go-libp2p/core/peer"
    14  	"github.com/stretchr/testify/require"
    15  
    16  	"github.com/status-im/status-go/eth-node/types"
    17  	"github.com/status-im/status-go/protocol/tt"
    18  )
    19  
    20  type queryResponse struct {
    21  	topics []types.TopicType
    22  	err    error // Indicates if this response will simulate an error returned by SendMessagesRequestForTopics
    23  	cursor []byte
    24  }
    25  
    26  type mockTransport struct {
    27  	queryResponses map[string]queryResponse
    28  }
    29  
    30  func newMockTransport() *mockTransport {
    31  	return &mockTransport{
    32  		queryResponses: make(map[string]queryResponse),
    33  	}
    34  }
    35  
    36  func getInitialResponseKey(topics []types.TopicType) string {
    37  	return hex.EncodeToString(append([]byte("start"), topics[0][:]...))
    38  }
    39  
    40  func (t *mockTransport) SendMessagesRequestForTopics(
    41  	ctx context.Context,
    42  	peerID peer.ID,
    43  	from, to uint32,
    44  	prevCursor types.StoreRequestCursor,
    45  	pubsubTopic string,
    46  	contentTopics []types.TopicType,
    47  	limit uint32,
    48  	waitForResponse bool,
    49  	processEnvelopes bool,
    50  ) (cursor types.StoreRequestCursor, envelopesCount int, err error) {
    51  	var response queryResponse
    52  	if prevCursor == nil {
    53  		initialResponse := getInitialResponseKey(contentTopics)
    54  		response = t.queryResponses[initialResponse]
    55  	} else {
    56  		response = t.queryResponses[hex.EncodeToString(prevCursor)]
    57  	}
    58  	return response.cursor, 0, response.err
    59  }
    60  
    61  func (t *mockTransport) Populate(topics []types.TopicType, responses int, includeRandomError bool) error {
    62  	if responses <= 0 || len(topics) == 0 {
    63  		return errors.New("invalid input parameters")
    64  	}
    65  
    66  	var topicBatches [][]types.TopicType
    67  
    68  	for i := 0; i < len(topics); i += maxTopicsPerRequest {
    69  		// Split batch in 10-contentTopic subbatches
    70  		j := i + maxTopicsPerRequest
    71  		if j > len(topics) {
    72  			j = len(topics)
    73  		}
    74  		topicBatches = append(topicBatches, topics[i:j])
    75  	}
    76  
    77  	randomErrIdx, err := rand.Int(rand.Reader, big.NewInt(int64(len(topicBatches))))
    78  	if err != nil {
    79  		return err
    80  	}
    81  	randomErrIdxInt := int(randomErrIdx.Int64())
    82  
    83  	for i, topicBatch := range topicBatches {
    84  		// Setup initial response
    85  		initialResponseKey := getInitialResponseKey(topicBatch)
    86  		t.queryResponses[initialResponseKey] = queryResponse{
    87  			topics: topicBatch,
    88  			err:    nil,
    89  		}
    90  
    91  		prevKey := initialResponseKey
    92  		for x := 0; x < responses-1; x++ {
    93  			newResponseCursor := []byte(uuid.New().String())
    94  			newResponseKey := hex.EncodeToString(newResponseCursor)
    95  
    96  			var err error
    97  			if includeRandomError && i == randomErrIdxInt && x == responses-2 { // Include an error in last request
    98  				err = errors.New("random error")
    99  			}
   100  
   101  			t.queryResponses[newResponseKey] = queryResponse{
   102  				topics: topicBatch,
   103  				err:    err,
   104  			}
   105  
   106  			// Updating prev response cursor to point to the new response
   107  			prevResponse := t.queryResponses[prevKey]
   108  			prevResponse.cursor = newResponseCursor
   109  			t.queryResponses[prevKey] = prevResponse
   110  
   111  			prevKey = newResponseKey
   112  		}
   113  
   114  	}
   115  
   116  	return nil
   117  }
   118  
   119  func TestProcessMailserverBatchHappyPath(t *testing.T) {
   120  	ctx, cancel := context.WithTimeout(context.TODO(), 5*time.Second)
   121  	defer cancel()
   122  
   123  	logger := tt.MustCreateTestLogger()
   124  
   125  	mailserverID, err := peer.Decode("16Uiu2HAkw3x97MbbZSWHbdF5bob45vcZvPPK4s4Mjyv2mxyB9GS3")
   126  	require.NoError(t, err)
   127  	topics := []types.TopicType{}
   128  	for i := 0; i < 22; i++ {
   129  		topics = append(topics, types.BytesToTopic([]byte{0, 0, 0, byte(i)}))
   130  	}
   131  
   132  	testTransport := newMockTransport()
   133  	err = testTransport.Populate(topics, 10, false)
   134  	require.NoError(t, err)
   135  
   136  	testBatch := MailserverBatch{
   137  		Topics: topics,
   138  	}
   139  
   140  	err = processMailserverBatch(ctx, testTransport, testBatch, mailserverID, logger, defaultStoreNodeRequestPageSize, nil, false)
   141  	require.NoError(t, err)
   142  }
   143  
   144  func TestProcessMailserverBatchFailure(t *testing.T) {
   145  	ctx, cancel := context.WithTimeout(context.TODO(), 5*time.Second)
   146  	defer cancel()
   147  
   148  	logger := tt.MustCreateTestLogger()
   149  
   150  	mailserverID, err := peer.Decode("16Uiu2HAkw3x97MbbZSWHbdF5bob45vcZvPPK4s4Mjyv2mxyB9GS3")
   151  	require.NoError(t, err)
   152  	topics := []types.TopicType{}
   153  	for i := 0; i < 5; i++ {
   154  		topics = append(topics, types.BytesToTopic([]byte{0, 0, 0, byte(i)}))
   155  	}
   156  
   157  	testTransport := newMockTransport()
   158  	err = testTransport.Populate(topics, 4, true)
   159  	require.NoError(t, err)
   160  
   161  	testBatch := MailserverBatch{
   162  		Topics: topics,
   163  	}
   164  
   165  	err = processMailserverBatch(ctx, testTransport, testBatch, mailserverID, logger, defaultStoreNodeRequestPageSize, nil, false)
   166  	require.Error(t, err)
   167  }