|
|
@@ -0,0 +1,707 @@
|
|
|
+// Copyright 2016 The go-ethereum Authors
|
|
|
+// This file is part of the go-ethereum library.
|
|
|
+//
|
|
|
+// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
|
+// it under the terms of the GNU Lesser General Public License as published by
|
|
|
+// the Free Software Foundation, either version 3 of the License, or
|
|
|
+// (at your option) any later version.
|
|
|
+//
|
|
|
+// The go-ethereum library is distributed in the hope that it will be useful,
|
|
|
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
+// GNU Lesser General Public License for more details.
|
|
|
+//
|
|
|
+// You should have received a copy of the GNU Lesser General Public License
|
|
|
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
+
|
|
|
+package whisperv5
|
|
|
+
|
|
|
+import (
|
|
|
+ "math/big"
|
|
|
+ "math/rand"
|
|
|
+ "testing"
|
|
|
+ "time"
|
|
|
+
|
|
|
+ "github.com/ethereum/go-ethereum/common"
|
|
|
+ "github.com/ethereum/go-ethereum/crypto"
|
|
|
+)
|
|
|
+
|
|
|
+var seed int64
|
|
|
+
|
|
|
+// InitSingleTest should be called in the beginning of every
|
|
|
+// test, which uses RNG, in order to make the tests
|
|
|
+// reproduciblity independent of their sequence.
|
|
|
+func InitSingleTest() {
|
|
|
+ seed = time.Now().Unix()
|
|
|
+ rand.Seed(seed)
|
|
|
+}
|
|
|
+
|
|
|
+func InitDebugTest(i int64) {
|
|
|
+ seed = i
|
|
|
+ rand.Seed(seed)
|
|
|
+}
|
|
|
+
|
|
|
+type FilterTestCase struct {
|
|
|
+ f *Filter
|
|
|
+ id int
|
|
|
+ alive bool
|
|
|
+ msgCnt int
|
|
|
+}
|
|
|
+
|
|
|
+func generateFilter(x *testing.T, symmetric bool) (*Filter, error) {
|
|
|
+ var f Filter
|
|
|
+ f.Messages = make(map[common.Hash]*ReceivedMessage)
|
|
|
+
|
|
|
+ const topicNum = 8
|
|
|
+ f.Topics = make([]TopicType, topicNum)
|
|
|
+ for i := 0; i < topicNum; i++ {
|
|
|
+ randomize(f.Topics[i][:])
|
|
|
+ f.Topics[i][0] = 0x01
|
|
|
+ }
|
|
|
+
|
|
|
+ key, err := crypto.GenerateKey()
|
|
|
+ if err != nil {
|
|
|
+ x.Errorf("generateFilter failed 1 with seed %d.", seed)
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ f.Src = &key.PublicKey
|
|
|
+
|
|
|
+ if symmetric {
|
|
|
+ f.KeySym = make([]byte, 12)
|
|
|
+ randomize(f.KeySym)
|
|
|
+ f.SymKeyHash = crypto.Keccak256Hash(f.KeySym)
|
|
|
+ } else {
|
|
|
+ f.KeyAsym, err = crypto.GenerateKey()
|
|
|
+ if err != nil {
|
|
|
+ x.Errorf("generateFilter failed 2 with seed %d.", seed)
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // AcceptP2P & PoW are not set
|
|
|
+ return &f, nil
|
|
|
+}
|
|
|
+
|
|
|
+func generateTestCases(x *testing.T, SizeTestFilters int) []FilterTestCase {
|
|
|
+ cases := make([]FilterTestCase, SizeTestFilters)
|
|
|
+ for i := 0; i < SizeTestFilters; i++ {
|
|
|
+ f, _ := generateFilter(x, true)
|
|
|
+ cases[i].f = f
|
|
|
+ cases[i].alive = (rand.Int()&int(1) == 0)
|
|
|
+ }
|
|
|
+ return cases
|
|
|
+}
|
|
|
+
|
|
|
+func TestInstallFilters(x *testing.T) {
|
|
|
+ InitSingleTest()
|
|
|
+
|
|
|
+ const SizeTestFilters = 256
|
|
|
+ w := NewWhisper(nil)
|
|
|
+ filters := NewFilters(w)
|
|
|
+ tst := generateTestCases(x, SizeTestFilters)
|
|
|
+
|
|
|
+ var j int
|
|
|
+ for i := 0; i < SizeTestFilters; i++ {
|
|
|
+ j = filters.Install(tst[i].f)
|
|
|
+ tst[i].id = j
|
|
|
+ }
|
|
|
+
|
|
|
+ if j < SizeTestFilters-1 {
|
|
|
+ x.Errorf("seed %d: wrong index %d", seed, j)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, t := range tst {
|
|
|
+ if !t.alive {
|
|
|
+ filters.Uninstall(t.id)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for i, t := range tst {
|
|
|
+ fil := filters.Get(t.id)
|
|
|
+ exist := (fil != nil)
|
|
|
+ if exist != t.alive {
|
|
|
+ x.Errorf("seed %d: failed alive: %d, %v, %v", seed, i, exist, t.alive)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if exist && fil.PoW != t.f.PoW {
|
|
|
+ x.Errorf("seed %d: failed Get: %d, %v, %v", seed, i, exist, t.alive)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestComparePubKey(x *testing.T) {
|
|
|
+ InitSingleTest()
|
|
|
+
|
|
|
+ key1, err := crypto.GenerateKey()
|
|
|
+ if err != nil {
|
|
|
+ x.Errorf("failed GenerateKey 1 with seed %d: %s.", seed, err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ key2, err := crypto.GenerateKey()
|
|
|
+ if err != nil {
|
|
|
+ x.Errorf("failed GenerateKey 2 with seed %d: %s.", seed, err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if isPubKeyEqual(&key1.PublicKey, &key2.PublicKey) {
|
|
|
+ x.Errorf("failed !equal with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // generate key3 == key1
|
|
|
+ rand.Seed(seed)
|
|
|
+ key3, err := crypto.GenerateKey()
|
|
|
+ if err != nil {
|
|
|
+ x.Errorf("failed GenerateKey 3 with seed %d: %s.", seed, err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if isPubKeyEqual(&key1.PublicKey, &key3.PublicKey) {
|
|
|
+ x.Errorf("failed equal with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestMatchEnvelope(x *testing.T) {
|
|
|
+ InitSingleTest()
|
|
|
+
|
|
|
+ fsym, err := generateFilter(x, true)
|
|
|
+ if err != nil {
|
|
|
+ x.Errorf("failed generateFilter 1 with seed %d: %s.", seed, err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ fasym, err := generateFilter(x, false)
|
|
|
+ if err != nil {
|
|
|
+ x.Errorf("failed generateFilter 2 with seed %d: %s.", seed, err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ params, err := generateMessageParams()
|
|
|
+ if err != nil {
|
|
|
+ x.Errorf("failed generateMessageParams 3 with seed %d: %s.", seed, err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ params.Topic[0] = 0xFF // ensure mismatch
|
|
|
+
|
|
|
+ // mismatch with pseudo-random data
|
|
|
+ msg := NewSentMessage(params)
|
|
|
+ env, err := msg.Wrap(params)
|
|
|
+ if err != nil {
|
|
|
+ x.Errorf("failed Wrap 4 with seed %d: %s.", seed, err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ match := fsym.MatchEnvelope(env)
|
|
|
+ if match {
|
|
|
+ x.Errorf("failed test case 5 with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ match = fasym.MatchEnvelope(env)
|
|
|
+ if match {
|
|
|
+ x.Errorf("failed test case 6 with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // encrypt symmetrically
|
|
|
+ i := rand.Int() % 4
|
|
|
+ fsym.Topics[i] = params.Topic
|
|
|
+ fasym.Topics[i] = params.Topic
|
|
|
+ msg = NewSentMessage(params)
|
|
|
+ env, err = msg.Wrap(params)
|
|
|
+ if err != nil {
|
|
|
+ x.Errorf("failed test case 7 with seed %d, test case 3: %s.", seed, err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // symmetric + matching topic: match
|
|
|
+ match = fsym.MatchEnvelope(env)
|
|
|
+ if !match {
|
|
|
+ x.Errorf("failed test case 8 with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // asymmetric + matching topic: mismatch
|
|
|
+ match = fasym.MatchEnvelope(env)
|
|
|
+ if match {
|
|
|
+ x.Errorf("failed test case 9 with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // symmetric + matching topic + insufficient PoW: mismatch
|
|
|
+ fsym.PoW = env.PoW() + 1.0
|
|
|
+ match = fsym.MatchEnvelope(env)
|
|
|
+ if match {
|
|
|
+ x.Errorf("failed test case 10 with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // symmetric + matching topic + sufficient PoW: match
|
|
|
+ fsym.PoW = env.PoW() / 2
|
|
|
+ match = fsym.MatchEnvelope(env)
|
|
|
+ if !match {
|
|
|
+ x.Errorf("failed test case 11 with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // symmetric + topics are nil: mismatch
|
|
|
+ prevTopics := fsym.Topics
|
|
|
+ fsym.Topics = nil
|
|
|
+ match = fasym.MatchEnvelope(env)
|
|
|
+ if match {
|
|
|
+ x.Errorf("failed test case 12 with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ fsym.Topics = prevTopics
|
|
|
+
|
|
|
+ // encrypt asymmetrically
|
|
|
+ key, err := crypto.GenerateKey()
|
|
|
+ if err != nil {
|
|
|
+ x.Errorf("failed GenerateKey 13 with seed %d: %s.", seed, err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ params.KeySym = nil
|
|
|
+ params.Dst = &key.PublicKey
|
|
|
+ msg = NewSentMessage(params)
|
|
|
+ env, err = msg.Wrap(params)
|
|
|
+ if err != nil {
|
|
|
+ x.Errorf("failed test case 14 with seed %d, test case 3: %s.", seed, err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // encryption method mismatch
|
|
|
+ match = fsym.MatchEnvelope(env)
|
|
|
+ if match {
|
|
|
+ x.Errorf("failed test case 15 with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // asymmetric + mismatching topic: mismatch
|
|
|
+ match = fasym.MatchEnvelope(env)
|
|
|
+ if !match {
|
|
|
+ x.Errorf("failed test case 16 with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // asymmetric + matching topic: match
|
|
|
+ fasym.Topics[i] = fasym.Topics[i+1]
|
|
|
+ match = fasym.MatchEnvelope(env)
|
|
|
+ if match {
|
|
|
+ x.Errorf("failed test case 17 with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // asymmetric + topic is nil (wildcard): match
|
|
|
+ fasym.Topics = nil
|
|
|
+ match = fasym.MatchEnvelope(env)
|
|
|
+ if !match {
|
|
|
+ x.Errorf("failed test case 18 with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // asymmetric + insufficient PoW: mismatch
|
|
|
+ fasym.PoW = env.PoW() + 1.0
|
|
|
+ match = fasym.MatchEnvelope(env)
|
|
|
+ if match {
|
|
|
+ x.Errorf("failed test case 19 with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // asymmetric + sufficient PoW: match
|
|
|
+ fasym.PoW = env.PoW() / 2
|
|
|
+ match = fasym.MatchEnvelope(env)
|
|
|
+ if !match {
|
|
|
+ x.Errorf("failed test case 20 with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestMatchMessageSym(x *testing.T) {
|
|
|
+ InitSingleTest()
|
|
|
+
|
|
|
+ params, err := generateMessageParams()
|
|
|
+ if err != nil {
|
|
|
+ x.Errorf("failed generateMessageParams with seed %d: %s.", seed, err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ f, err := generateFilter(x, true)
|
|
|
+ if err != nil {
|
|
|
+ x.Errorf("failed generateFilter 1 with seed %d: %s.", seed, err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ const index = 1
|
|
|
+ params.KeySym = f.KeySym
|
|
|
+ params.Topic = f.Topics[index]
|
|
|
+
|
|
|
+ sentMessage := NewSentMessage(params)
|
|
|
+ env, err := sentMessage.Wrap(params)
|
|
|
+ if err != nil {
|
|
|
+ x.Errorf("failed Wrap 2 with seed %d: %s.", seed, err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ msg := env.Open(f)
|
|
|
+ if msg == nil {
|
|
|
+ x.Errorf("failed to open 3 with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // Src mismatch
|
|
|
+ if f.MatchMessage(msg) {
|
|
|
+ x.Errorf("failed test case 4 with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // Src: match
|
|
|
+ *f.Src.X = *params.Src.PublicKey.X
|
|
|
+ *f.Src.Y = *params.Src.PublicKey.Y
|
|
|
+ if !f.MatchMessage(msg) {
|
|
|
+ x.Errorf("failed test case 5 with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // insufficient PoW: mismatch
|
|
|
+ f.PoW = msg.PoW + 1.0
|
|
|
+ if f.MatchMessage(msg) {
|
|
|
+ x.Errorf("failed test case 6 with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // sufficient PoW: match
|
|
|
+ f.PoW = msg.PoW / 2
|
|
|
+ if !f.MatchMessage(msg) {
|
|
|
+ x.Errorf("failed test case 7 with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // topic mismatch
|
|
|
+ f.Topics[index][0]++
|
|
|
+ if f.MatchMessage(msg) {
|
|
|
+ x.Errorf("failed test case 8 with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ f.Topics[index][0]--
|
|
|
+
|
|
|
+ // key mismatch
|
|
|
+ f.SymKeyHash[0]++
|
|
|
+ if f.MatchMessage(msg) {
|
|
|
+ x.Errorf("failed test case 9 with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ f.SymKeyHash[0]--
|
|
|
+
|
|
|
+ // Src absent: match
|
|
|
+ f.Src = nil
|
|
|
+ if !f.MatchMessage(msg) {
|
|
|
+ x.Errorf("failed test case 10 with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // key hash mismatch mismatch
|
|
|
+ h := f.SymKeyHash
|
|
|
+ f.SymKeyHash = common.Hash{}
|
|
|
+ if f.MatchMessage(msg) {
|
|
|
+ x.Errorf("failed test case 11 with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ f.SymKeyHash = h
|
|
|
+ if !f.MatchMessage(msg) {
|
|
|
+ x.Errorf("failed test case 12 with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // encryption method mismatch
|
|
|
+ f.KeySym = nil
|
|
|
+ f.KeyAsym, err = crypto.GenerateKey()
|
|
|
+ if err != nil {
|
|
|
+ x.Errorf("failed GenerateKey 13 with seed %d: %s.", seed, err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if f.MatchMessage(msg) {
|
|
|
+ x.Errorf("failed test case 14 with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestMatchMessageAsym(x *testing.T) {
|
|
|
+ InitSingleTest()
|
|
|
+
|
|
|
+ f, err := generateFilter(x, false)
|
|
|
+ if err != nil {
|
|
|
+ x.Errorf("failed generateFilter with seed %d: %s.", seed, err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ params, err := generateMessageParams()
|
|
|
+ if err != nil {
|
|
|
+ x.Errorf("failed generateMessageParams with seed %d: %s.", seed, err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ const index = 1
|
|
|
+ params.Topic = f.Topics[index]
|
|
|
+ params.Dst = &f.KeyAsym.PublicKey
|
|
|
+ keySymOrig := params.KeySym
|
|
|
+ params.KeySym = nil
|
|
|
+
|
|
|
+ sentMessage := NewSentMessage(params)
|
|
|
+ env, err := sentMessage.Wrap(params)
|
|
|
+ if err != nil {
|
|
|
+ x.Errorf("failed Wrap with seed %d: %s.", seed, err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ msg := env.Open(f)
|
|
|
+ if msg == nil {
|
|
|
+ x.Errorf("failed to open with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // Src mismatch
|
|
|
+ if f.MatchMessage(msg) {
|
|
|
+ x.Errorf("failed test case 4 with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // Src: match
|
|
|
+ *f.Src.X = *params.Src.PublicKey.X
|
|
|
+ *f.Src.Y = *params.Src.PublicKey.Y
|
|
|
+ if !f.MatchMessage(msg) {
|
|
|
+ x.Errorf("failed test case 5 with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // insufficient PoW: mismatch
|
|
|
+ f.PoW = msg.PoW + 1.0
|
|
|
+ if f.MatchMessage(msg) {
|
|
|
+ x.Errorf("failed test case 6 with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // sufficient PoW: match
|
|
|
+ f.PoW = msg.PoW / 2
|
|
|
+ if !f.MatchMessage(msg) {
|
|
|
+ x.Errorf("failed test case 7 with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // topic mismatch, but still match, because for asymmetric encryption
|
|
|
+ // only private key matters (in case the message is already decrypted)
|
|
|
+ f.Topics[index][0]++
|
|
|
+ if !f.MatchMessage(msg) {
|
|
|
+ x.Errorf("failed test case 8 with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ f.Topics[index][0]--
|
|
|
+
|
|
|
+ // key mismatch
|
|
|
+ prev := *f.KeyAsym.PublicKey.X
|
|
|
+ zero := *big.NewInt(0)
|
|
|
+ *f.KeyAsym.PublicKey.X = zero
|
|
|
+ if f.MatchMessage(msg) {
|
|
|
+ x.Errorf("failed test case 9 with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ *f.KeyAsym.PublicKey.X = prev
|
|
|
+
|
|
|
+ // Src absent: match
|
|
|
+ f.Src = nil
|
|
|
+ if !f.MatchMessage(msg) {
|
|
|
+ x.Errorf("failed test case 10 with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // encryption method mismatch
|
|
|
+ f.KeySym = keySymOrig
|
|
|
+ f.KeyAsym = nil
|
|
|
+ if f.MatchMessage(msg) {
|
|
|
+ x.Errorf("failed test case 11 with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func cloneFilter(orig *Filter) *Filter {
|
|
|
+ var clone Filter
|
|
|
+ clone.Messages = make(map[common.Hash]*ReceivedMessage)
|
|
|
+ clone.Src = orig.Src
|
|
|
+ clone.KeyAsym = orig.KeyAsym
|
|
|
+ clone.KeySym = orig.KeySym
|
|
|
+ clone.Topics = orig.Topics
|
|
|
+ clone.PoW = orig.PoW
|
|
|
+ clone.AcceptP2P = orig.AcceptP2P
|
|
|
+ clone.SymKeyHash = orig.SymKeyHash
|
|
|
+ return &clone
|
|
|
+}
|
|
|
+
|
|
|
+func generateCompatibeEnvelope(x *testing.T, f *Filter) *Envelope {
|
|
|
+ params, err := generateMessageParams()
|
|
|
+ if err != nil {
|
|
|
+ x.Errorf("failed generateMessageParams 77 with seed %d: %s.", seed, err)
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ params.KeySym = f.KeySym
|
|
|
+ params.Topic = f.Topics[2]
|
|
|
+ sentMessage := NewSentMessage(params)
|
|
|
+ env, err := sentMessage.Wrap(params)
|
|
|
+ if err != nil {
|
|
|
+ x.Errorf("failed Wrap 78 with seed %d: %s.", seed, err)
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ return env
|
|
|
+}
|
|
|
+
|
|
|
+func TestWatchers(x *testing.T) {
|
|
|
+ InitSingleTest()
|
|
|
+
|
|
|
+ const NumFilters = 16
|
|
|
+ const NumMessages = 256
|
|
|
+ var i, j int
|
|
|
+ var e *Envelope
|
|
|
+
|
|
|
+ w := NewWhisper(nil)
|
|
|
+ filters := NewFilters(w)
|
|
|
+ tst := generateTestCases(x, NumFilters)
|
|
|
+ for i = 0; i < NumFilters; i++ {
|
|
|
+ tst[i].f.Src = nil
|
|
|
+ j = filters.Install(tst[i].f)
|
|
|
+ tst[i].id = j
|
|
|
+ }
|
|
|
+
|
|
|
+ last := j
|
|
|
+
|
|
|
+ var envelopes [NumMessages]*Envelope
|
|
|
+ for i = 0; i < NumMessages; i++ {
|
|
|
+ j = rand.Int() % NumFilters
|
|
|
+ e = generateCompatibeEnvelope(x, tst[j].f)
|
|
|
+ envelopes[i] = e
|
|
|
+ tst[j].msgCnt++
|
|
|
+ }
|
|
|
+
|
|
|
+ for i = 0; i < NumMessages; i++ {
|
|
|
+ filters.NotifyWatchers(envelopes[i], messagesCode)
|
|
|
+ }
|
|
|
+
|
|
|
+ var total int
|
|
|
+ var mail []*ReceivedMessage
|
|
|
+ var count [NumFilters]int
|
|
|
+
|
|
|
+ for i = 0; i < NumFilters; i++ {
|
|
|
+ mail = tst[i].f.Retrieve()
|
|
|
+ count[i] = len(mail)
|
|
|
+ total += len(mail)
|
|
|
+ }
|
|
|
+
|
|
|
+ if total != NumMessages {
|
|
|
+ x.Errorf("failed test case 1 with seed %d: total = %d, want: %d.", seed, total, NumMessages)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ for i = 0; i < NumFilters; i++ {
|
|
|
+ mail = tst[i].f.Retrieve()
|
|
|
+ if len(mail) != 0 {
|
|
|
+ x.Errorf("failed test case 2 with seed %d: i = %d.", seed, i)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if tst[i].msgCnt != count[i] {
|
|
|
+ x.Errorf("failed test case 3 with seed %d: i = %d, get %d, want %d.", seed, i, tst[i].msgCnt, count[i])
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // another round with a cloned filter
|
|
|
+
|
|
|
+ clone := cloneFilter(tst[0].f)
|
|
|
+ filters.Uninstall(last)
|
|
|
+ total = 0
|
|
|
+ last = NumFilters - 1
|
|
|
+ tst[last].f = clone
|
|
|
+ filters.Install(clone)
|
|
|
+ for i = 0; i < NumFilters; i++ {
|
|
|
+ tst[i].msgCnt = 0
|
|
|
+ count[i] = 0
|
|
|
+ }
|
|
|
+
|
|
|
+ // make sure that the first watcher receives at least one message
|
|
|
+ e = generateCompatibeEnvelope(x, tst[0].f)
|
|
|
+ envelopes[0] = e
|
|
|
+ tst[0].msgCnt++
|
|
|
+ for i = 1; i < NumMessages; i++ {
|
|
|
+ j = rand.Int() % NumFilters
|
|
|
+ e = generateCompatibeEnvelope(x, tst[j].f)
|
|
|
+ envelopes[i] = e
|
|
|
+ tst[j].msgCnt++
|
|
|
+ }
|
|
|
+
|
|
|
+ for i = 0; i < NumMessages; i++ {
|
|
|
+ filters.NotifyWatchers(envelopes[i], messagesCode)
|
|
|
+ }
|
|
|
+
|
|
|
+ for i = 0; i < NumFilters; i++ {
|
|
|
+ mail = tst[i].f.Retrieve()
|
|
|
+ count[i] = len(mail)
|
|
|
+ total += len(mail)
|
|
|
+ }
|
|
|
+
|
|
|
+ combined := tst[0].msgCnt + tst[last].msgCnt
|
|
|
+ if total != NumMessages+count[0] {
|
|
|
+ x.Errorf("failed test case 4 with seed %d: total = %d, count[0] = %d.", seed, total, count[0])
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if combined != count[0] {
|
|
|
+ x.Errorf("failed test case 5 with seed %d: combined = %d, count[0] = %d.", seed, combined, count[0])
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if combined != count[last] {
|
|
|
+ x.Errorf("failed test case 6 with seed %d: combined = %d, count[last] = %d.", seed, combined, count[last])
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ for i = 1; i < NumFilters-1; i++ {
|
|
|
+ mail = tst[i].f.Retrieve()
|
|
|
+ if len(mail) != 0 {
|
|
|
+ x.Errorf("failed test case 7 with seed %d: i = %d.", seed, i)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if tst[i].msgCnt != count[i] {
|
|
|
+ x.Errorf("failed test case 8 with seed %d: i = %d, get %d, want %d.", seed, i, tst[i].msgCnt, count[i])
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // test AcceptP2P
|
|
|
+
|
|
|
+ total = 0
|
|
|
+ filters.NotifyWatchers(envelopes[0], p2pCode)
|
|
|
+
|
|
|
+ for i = 0; i < NumFilters; i++ {
|
|
|
+ mail = tst[i].f.Retrieve()
|
|
|
+ total += len(mail)
|
|
|
+ }
|
|
|
+
|
|
|
+ if total != 0 {
|
|
|
+ x.Errorf("failed test case 9 with seed %d.", seed)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ f := filters.Get(0)
|
|
|
+ f.AcceptP2P = true
|
|
|
+ total = 0
|
|
|
+ filters.NotifyWatchers(envelopes[0], p2pCode)
|
|
|
+
|
|
|
+ for i = 0; i < NumFilters; i++ {
|
|
|
+ mail = tst[i].f.Retrieve()
|
|
|
+ total += len(mail)
|
|
|
+ }
|
|
|
+
|
|
|
+ if total != 1 {
|
|
|
+ x.Errorf("failed test case 10 with seed %d: total = %d.", seed, total)
|
|
|
+ return
|
|
|
+ }
|
|
|
+}
|