github.com/ethersphere/bee/v2@v2.2.0/pkg/pss/pss_test.go (about)

     1  // Copyright 2020 The Swarm Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package pss_test
     6  
     7  import (
     8  	"bytes"
     9  	"context"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/ethersphere/bee/v2/pkg/crypto"
    14  	"github.com/ethersphere/bee/v2/pkg/log"
    15  	"github.com/ethersphere/bee/v2/pkg/postage"
    16  	postagetesting "github.com/ethersphere/bee/v2/pkg/postage/testing"
    17  	"github.com/ethersphere/bee/v2/pkg/pss"
    18  	"github.com/ethersphere/bee/v2/pkg/pushsync"
    19  	pushsyncmock "github.com/ethersphere/bee/v2/pkg/pushsync/mock"
    20  	"github.com/ethersphere/bee/v2/pkg/swarm"
    21  )
    22  
    23  // TestSend creates a trojan chunk and sends it using push sync
    24  func TestSend(t *testing.T) {
    25  	t.Parallel()
    26  
    27  	var err error
    28  	ctx := context.Background()
    29  
    30  	// create a mock pushsync service to push the chunk to its destination
    31  	var storedChunk swarm.Chunk
    32  	pushSyncService := pushsyncmock.New(func(ctx context.Context, chunk swarm.Chunk) (*pushsync.Receipt, error) {
    33  		storedChunk = chunk
    34  		return nil, nil
    35  	})
    36  	p := pss.New(nil, log.Noop)
    37  	p.SetPushSyncer(pushSyncService)
    38  
    39  	target := pss.Target([]byte{1}) // arbitrary test target
    40  	targets := pss.Targets([]pss.Target{target})
    41  	payload := []byte("some payload")
    42  	topic := pss.NewTopic("topic")
    43  	privkey, err := crypto.GenerateSecp256k1Key()
    44  	if err != nil {
    45  		t.Fatal(err)
    46  	}
    47  	recipient := &privkey.PublicKey
    48  	s := &stamper{}
    49  	// call Send to store trojan chunk in localstore
    50  	if err = p.Send(ctx, topic, payload, s, recipient, targets); err != nil {
    51  		t.Fatal(err)
    52  	}
    53  
    54  	topic1 := pss.NewTopic("topic-1")
    55  	topic2 := pss.NewTopic("topic-2")
    56  	topic3 := pss.NewTopic("topic-3")
    57  
    58  	topics := []pss.Topic{topic, topic1, topic2, topic3}
    59  	unwrapTopic, msg, err := pss.Unwrap(ctx, privkey, storedChunk, topics)
    60  	if err != nil {
    61  		t.Fatal(err)
    62  	}
    63  
    64  	if !bytes.Equal(msg, payload) {
    65  		t.Fatalf("message mismatch: expected %x, got %x", payload, msg)
    66  	}
    67  
    68  	if !bytes.Equal(unwrapTopic[:], topic[:]) {
    69  		t.Fatalf("topic mismatch: expected %x, got %x", topic[:], unwrapTopic[:])
    70  	}
    71  }
    72  
    73  type topicMessage struct {
    74  	topic pss.Topic
    75  	msg   []byte
    76  }
    77  
    78  // TestDeliver verifies that registering a handler on pss for a given topic and then submitting a trojan chunk with said topic to it
    79  // results in the execution of the expected handler func
    80  func TestDeliver(t *testing.T) {
    81  	t.Parallel()
    82  
    83  	privkey, err := crypto.GenerateSecp256k1Key()
    84  	if err != nil {
    85  		t.Fatal(err)
    86  	}
    87  	p := pss.New(privkey, log.Noop)
    88  
    89  	target := pss.Target([]byte{1}) // arbitrary test target
    90  	targets := pss.Targets([]pss.Target{target})
    91  	payload := []byte("some payload")
    92  	topic := pss.NewTopic("topic")
    93  
    94  	recipient := &privkey.PublicKey
    95  
    96  	// test chunk
    97  	chunk, err := pss.Wrap(context.Background(), topic, payload, recipient, targets)
    98  	if err != nil {
    99  		t.Fatal(err)
   100  	}
   101  
   102  	msgChan := make(chan topicMessage)
   103  
   104  	// create and register handler
   105  	handler := func(ctx context.Context, m []byte) {
   106  		msgChan <- topicMessage{
   107  			topic: topic,
   108  			msg:   m,
   109  		}
   110  	}
   111  	p.Register(topic, handler)
   112  
   113  	// call pss TryUnwrap on chunk and verify test topic variable value changes
   114  	p.TryUnwrap(chunk)
   115  
   116  	var message topicMessage
   117  	select {
   118  	case message = <-msgChan:
   119  		break
   120  	case <-time.After(1 * time.Second):
   121  		t.Fatal("reached timeout while waiting for message")
   122  	}
   123  
   124  	if !bytes.Equal(payload, message.msg) {
   125  		t.Fatalf("message mismatch: expected %x, got %x", payload, message.msg)
   126  	}
   127  
   128  	if !bytes.Equal(topic[:], message.topic[:]) {
   129  		t.Fatalf("topic mismatch: expected %x, got %x", topic[:], message.topic[:])
   130  	}
   131  }
   132  
   133  // TestRegister verifies that handler funcs are able to be registered correctly in pss
   134  func TestRegister(t *testing.T) {
   135  	t.Parallel()
   136  
   137  	privkey, err := crypto.GenerateSecp256k1Key()
   138  	if err != nil {
   139  		t.Fatal(err)
   140  	}
   141  	recipient := &privkey.PublicKey
   142  	var (
   143  		p       = pss.New(privkey, log.Noop)
   144  		h1Calls = 0
   145  		h2Calls = 0
   146  		h3Calls = 0
   147  
   148  		msgChan = make(chan struct{})
   149  
   150  		topic1  = pss.NewTopic("one")
   151  		topic2  = pss.NewTopic("two")
   152  		payload = []byte("payload")
   153  		target  = pss.Target([]byte{1})
   154  		targets = pss.Targets([]pss.Target{target})
   155  
   156  		h1 = func(_ context.Context, m []byte) {
   157  			h1Calls++
   158  			msgChan <- struct{}{}
   159  		}
   160  
   161  		h2 = func(_ context.Context, m []byte) {
   162  			h2Calls++
   163  			msgChan <- struct{}{}
   164  		}
   165  
   166  		h3 = func(_ context.Context, m []byte) {
   167  			h3Calls++
   168  			msgChan <- struct{}{}
   169  		}
   170  	)
   171  	_ = p.Register(topic1, h1)
   172  	_ = p.Register(topic2, h2)
   173  
   174  	// send a message on topic1, check that only h1 is called
   175  	chunk1, err := pss.Wrap(context.Background(), topic1, payload, recipient, targets)
   176  	if err != nil {
   177  		t.Fatal(err)
   178  	}
   179  	p.TryUnwrap(chunk1)
   180  
   181  	waitHandlerCallback(t, &msgChan, 1)
   182  
   183  	ensureCalls(t, &h1Calls, 1)
   184  	ensureCalls(t, &h2Calls, 0)
   185  
   186  	// register another topic handler on the same topic
   187  	cleanup := p.Register(topic1, h3)
   188  	p.TryUnwrap(chunk1)
   189  
   190  	waitHandlerCallback(t, &msgChan, 2)
   191  
   192  	ensureCalls(t, &h1Calls, 2)
   193  	ensureCalls(t, &h2Calls, 0)
   194  	ensureCalls(t, &h3Calls, 1)
   195  
   196  	cleanup() // remove the last handler
   197  
   198  	p.TryUnwrap(chunk1)
   199  
   200  	waitHandlerCallback(t, &msgChan, 1)
   201  
   202  	ensureCalls(t, &h1Calls, 3)
   203  	ensureCalls(t, &h2Calls, 0)
   204  	ensureCalls(t, &h3Calls, 1)
   205  
   206  	chunk2, err := pss.Wrap(context.Background(), topic2, payload, recipient, targets)
   207  	if err != nil {
   208  		t.Fatal(err)
   209  	}
   210  	p.TryUnwrap(chunk2)
   211  
   212  	waitHandlerCallback(t, &msgChan, 1)
   213  
   214  	ensureCalls(t, &h1Calls, 3)
   215  	ensureCalls(t, &h2Calls, 1)
   216  	ensureCalls(t, &h3Calls, 1)
   217  }
   218  
   219  func waitHandlerCallback(t *testing.T, msgChan *chan struct{}, count int) {
   220  	t.Helper()
   221  
   222  	for received := 0; received < count; received++ {
   223  		select {
   224  		case <-*msgChan:
   225  		case <-time.After(1 * time.Second):
   226  			t.Fatal("reached timeout while waiting for handler message")
   227  		}
   228  	}
   229  }
   230  
   231  func ensureCalls(t *testing.T, calls *int, exp int) {
   232  	t.Helper()
   233  
   234  	if exp != *calls {
   235  		t.Fatalf("expected %d calls, found %d", exp, *calls)
   236  	}
   237  }
   238  
   239  type stamper struct{}
   240  
   241  func (s *stamper) Stamp(_ swarm.Address) (*postage.Stamp, error) {
   242  	return postagetesting.MustNewStamp(), nil
   243  }