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 }