github.com/bcskill/bcschain/v3@v3.4.9-beta2/whisper/whisperv6/filter_test.go (about)

     1  // Copyright 2016 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package whisperv6
    18  
    19  import (
    20  	"math/big"
    21  	mrand "math/rand"
    22  	"testing"
    23  	"time"
    24  
    25  	"github.com/bcskill/bcschain/v3/common"
    26  	"github.com/bcskill/bcschain/v3/crypto"
    27  )
    28  
    29  var seed int64
    30  
    31  // InitSingleTest should be called in the beginning of every
    32  // test, which uses RNG, in order to make the tests
    33  // reproduciblity independent of their sequence.
    34  func InitSingleTest() {
    35  	seed = time.Now().Unix()
    36  	mrand.Seed(seed)
    37  }
    38  
    39  func InitDebugTest(i int64) {
    40  	seed = i
    41  	mrand.Seed(seed)
    42  }
    43  
    44  type FilterTestCase struct {
    45  	f      *Filter
    46  	id     string
    47  	alive  bool
    48  	msgCnt int
    49  }
    50  
    51  func generateFilter(t *testing.T, symmetric bool) (*Filter, error) {
    52  	var f Filter
    53  	f.Messages = make(map[common.Hash]*ReceivedMessage)
    54  
    55  	const topicNum = 8
    56  	f.Topics = make([][]byte, topicNum)
    57  	for i := 0; i < topicNum; i++ {
    58  		f.Topics[i] = make([]byte, 4)
    59  		mrand.Read(f.Topics[i][:])
    60  		f.Topics[i][0] = 0x01
    61  	}
    62  
    63  	key, err := crypto.GenerateKey()
    64  	if err != nil {
    65  		t.Fatalf("generateFilter 1 failed with seed %d.", seed)
    66  		return nil, err
    67  	}
    68  	f.Src = &key.PublicKey
    69  
    70  	if symmetric {
    71  		f.KeySym = make([]byte, aesKeyLength)
    72  		mrand.Read(f.KeySym)
    73  		f.SymKeyHash = crypto.Keccak256Hash(f.KeySym)
    74  	} else {
    75  		f.KeyAsym, err = crypto.GenerateKey()
    76  		if err != nil {
    77  			t.Fatalf("generateFilter 2 failed with seed %d.", seed)
    78  			return nil, err
    79  		}
    80  	}
    81  
    82  	// AcceptP2P & PoW are not set
    83  	return &f, nil
    84  }
    85  
    86  func generateTestCases(t *testing.T, SizeTestFilters int) []FilterTestCase {
    87  	cases := make([]FilterTestCase, SizeTestFilters)
    88  	for i := 0; i < SizeTestFilters; i++ {
    89  		f, _ := generateFilter(t, true)
    90  		cases[i].f = f
    91  		cases[i].alive = mrand.Int()&int(1) == 0
    92  	}
    93  	return cases
    94  }
    95  
    96  func TestInstallFilters(t *testing.T) {
    97  	InitSingleTest()
    98  
    99  	const SizeTestFilters = 256
   100  	w := New(&Config{})
   101  	filters := NewFilters(w)
   102  	tst := generateTestCases(t, SizeTestFilters)
   103  
   104  	var err error
   105  	var j string
   106  	for i := 0; i < SizeTestFilters; i++ {
   107  		j, err = filters.Install(tst[i].f)
   108  		if err != nil {
   109  			t.Fatalf("seed %d: failed to install filter: %s", seed, err)
   110  		}
   111  		tst[i].id = j
   112  		if len(j) != keyIDSize*2 {
   113  			t.Fatalf("seed %d: wrong filter id size [%d]", seed, len(j))
   114  		}
   115  	}
   116  
   117  	for _, testCase := range tst {
   118  		if !testCase.alive {
   119  			filters.Uninstall(testCase.id)
   120  		}
   121  	}
   122  
   123  	for i, testCase := range tst {
   124  		fil := filters.Get(testCase.id)
   125  		exist := fil != nil
   126  		if exist != testCase.alive {
   127  			t.Fatalf("seed %d: failed alive: %d, %v, %v", seed, i, exist, testCase.alive)
   128  		}
   129  		if exist && fil.PoW != testCase.f.PoW {
   130  			t.Fatalf("seed %d: failed Get: %d, %v, %v", seed, i, exist, testCase.alive)
   131  		}
   132  	}
   133  }
   134  
   135  func TestInstallSymKeyGeneratesHash(t *testing.T) {
   136  	InitSingleTest()
   137  
   138  	w := New(&Config{})
   139  	filters := NewFilters(w)
   140  	filter, _ := generateFilter(t, true)
   141  
   142  	// save the current SymKeyHash for comparison
   143  	initialSymKeyHash := filter.SymKeyHash
   144  
   145  	// ensure the SymKeyHash is invalid, for Install to recreate it
   146  	var invalid common.Hash
   147  	filter.SymKeyHash = invalid
   148  
   149  	_, err := filters.Install(filter)
   150  
   151  	if err != nil {
   152  		t.Fatalf("Error installing the filter: %s", err)
   153  	}
   154  
   155  	for i, b := range filter.SymKeyHash {
   156  		if b != initialSymKeyHash[i] {
   157  			t.Fatalf("The filter's symmetric key hash was not properly generated by Install")
   158  		}
   159  	}
   160  }
   161  
   162  func TestInstallIdenticalFilters(t *testing.T) {
   163  	InitSingleTest()
   164  
   165  	w := New(&Config{})
   166  	filters := NewFilters(w)
   167  	filter1, _ := generateFilter(t, true)
   168  
   169  	// Copy the first filter since some of its fields
   170  	// are randomly gnerated.
   171  	filter2 := &Filter{
   172  		KeySym:   filter1.KeySym,
   173  		Topics:   filter1.Topics,
   174  		PoW:      filter1.PoW,
   175  		AllowP2P: filter1.AllowP2P,
   176  		Messages: make(map[common.Hash]*ReceivedMessage),
   177  	}
   178  
   179  	_, err := filters.Install(filter1)
   180  
   181  	if err != nil {
   182  		t.Fatalf("Error installing the first filter with seed %d: %s", seed, err)
   183  	}
   184  
   185  	_, err = filters.Install(filter2)
   186  
   187  	if err != nil {
   188  		t.Fatalf("Error installing the second filter with seed %d: %s", seed, err)
   189  	}
   190  
   191  	params, err := generateMessageParams()
   192  	if err != nil {
   193  		t.Fatalf("Error generating message parameters with seed %d: %s", seed, err)
   194  	}
   195  
   196  	params.KeySym = filter1.KeySym
   197  	params.Topic = BytesToTopic(filter1.Topics[0])
   198  
   199  	filter1.Src = &params.Src.PublicKey
   200  	filter2.Src = &params.Src.PublicKey
   201  
   202  	sentMessage, err := NewSentMessage(params)
   203  	if err != nil {
   204  		t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
   205  	}
   206  	env, err := sentMessage.Wrap(params)
   207  	if err != nil {
   208  		t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
   209  	}
   210  	msg := env.Open(filter1)
   211  	if msg == nil {
   212  		t.Fatalf("failed to Open with filter1")
   213  	}
   214  
   215  	if !filter1.MatchEnvelope(env) {
   216  		t.Fatalf("failed matching with the first filter")
   217  	}
   218  
   219  	if !filter2.MatchEnvelope(env) {
   220  		t.Fatalf("failed matching with the first filter")
   221  	}
   222  
   223  	if !filter1.MatchMessage(msg) {
   224  		t.Fatalf("failed matching with the second filter")
   225  	}
   226  
   227  	if !filter2.MatchMessage(msg) {
   228  		t.Fatalf("failed matching with the second filter")
   229  	}
   230  }
   231  
   232  func TestInstallFilterWithSymAndAsymKeys(t *testing.T) {
   233  	InitSingleTest()
   234  
   235  	w := New(&Config{})
   236  	filters := NewFilters(w)
   237  	filter1, _ := generateFilter(t, true)
   238  
   239  	asymKey, err := crypto.GenerateKey()
   240  	if err != nil {
   241  		t.Fatalf("Unable to create asymetric keys: %v", err)
   242  	}
   243  
   244  	// Copy the first filter since some of its fields
   245  	// are randomly gnerated.
   246  	filter := &Filter{
   247  		KeySym:   filter1.KeySym,
   248  		KeyAsym:  asymKey,
   249  		Topics:   filter1.Topics,
   250  		PoW:      filter1.PoW,
   251  		AllowP2P: filter1.AllowP2P,
   252  		Messages: make(map[common.Hash]*ReceivedMessage),
   253  	}
   254  
   255  	_, err = filters.Install(filter)
   256  
   257  	if err == nil {
   258  		t.Fatalf("Error detecting that a filter had both an asymmetric and symmetric key, with seed %d", seed)
   259  	}
   260  }
   261  
   262  func TestComparePubKey(t *testing.T) {
   263  	InitSingleTest()
   264  
   265  	key1, err := crypto.GenerateKey()
   266  	if err != nil {
   267  		t.Fatalf("failed to generate first key with seed %d: %s.", seed, err)
   268  	}
   269  	key2, err := crypto.GenerateKey()
   270  	if err != nil {
   271  		t.Fatalf("failed to generate second key with seed %d: %s.", seed, err)
   272  	}
   273  	if IsPubKeyEqual(&key1.PublicKey, &key2.PublicKey) {
   274  		t.Fatalf("public keys are equal, seed %d.", seed)
   275  	}
   276  
   277  	// generate key3 == key1
   278  	mrand.Seed(seed)
   279  	key3, err := crypto.GenerateKey()
   280  	if err != nil {
   281  		t.Fatalf("failed to generate third key with seed %d: %s.", seed, err)
   282  	}
   283  	if IsPubKeyEqual(&key1.PublicKey, &key3.PublicKey) {
   284  		t.Fatalf("key1 == key3, seed %d.", seed)
   285  	}
   286  }
   287  
   288  func TestMatchEnvelope(t *testing.T) {
   289  	InitSingleTest()
   290  
   291  	fsym, err := generateFilter(t, true)
   292  	if err != nil {
   293  		t.Fatalf("failed generateFilter with seed %d: %s.", seed, err)
   294  	}
   295  
   296  	fasym, err := generateFilter(t, false)
   297  	if err != nil {
   298  		t.Fatalf("failed generateFilter() with seed %d: %s.", seed, err)
   299  	}
   300  
   301  	params, err := generateMessageParams()
   302  	if err != nil {
   303  		t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
   304  	}
   305  
   306  	params.Topic[0] = 0xFF // ensure mismatch
   307  
   308  	// mismatch with pseudo-random data
   309  	msg, err := NewSentMessage(params)
   310  	if err != nil {
   311  		t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
   312  	}
   313  	env, err := msg.Wrap(params)
   314  	if err != nil {
   315  		t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
   316  	}
   317  	match := fsym.MatchEnvelope(env)
   318  	if match {
   319  		t.Fatalf("failed MatchEnvelope symmetric with seed %d.", seed)
   320  	}
   321  	match = fasym.MatchEnvelope(env)
   322  	if match {
   323  		t.Fatalf("failed MatchEnvelope asymmetric with seed %d.", seed)
   324  	}
   325  
   326  	// encrypt symmetrically
   327  	i := mrand.Int() % 4
   328  	fsym.Topics[i] = params.Topic[:]
   329  	fasym.Topics[i] = params.Topic[:]
   330  	msg, err = NewSentMessage(params)
   331  	if err != nil {
   332  		t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
   333  	}
   334  	env, err = msg.Wrap(params)
   335  	if err != nil {
   336  		t.Fatalf("failed Wrap() with seed %d: %s.", seed, err)
   337  	}
   338  
   339  	// symmetric + matching topic: match
   340  	match = fsym.MatchEnvelope(env)
   341  	if !match {
   342  		t.Fatalf("failed MatchEnvelope() symmetric with seed %d.", seed)
   343  	}
   344  
   345  	// symmetric + matching topic + insufficient PoW: mismatch
   346  	fsym.PoW = env.PoW() + 1.0
   347  	match = fsym.MatchEnvelope(env)
   348  	if match {
   349  		t.Fatalf("failed MatchEnvelope(symmetric + matching topic + insufficient PoW) asymmetric with seed %d.", seed)
   350  	}
   351  
   352  	// symmetric + matching topic + sufficient PoW: match
   353  	fsym.PoW = env.PoW() / 2
   354  	match = fsym.MatchEnvelope(env)
   355  	if !match {
   356  		t.Fatalf("failed MatchEnvelope(symmetric + matching topic + sufficient PoW) with seed %d.", seed)
   357  	}
   358  
   359  	// symmetric + topics are nil (wildcard): match
   360  	prevTopics := fsym.Topics
   361  	fsym.Topics = nil
   362  	match = fsym.MatchEnvelope(env)
   363  	if !match {
   364  		t.Fatalf("failed MatchEnvelope(symmetric + topics are nil) with seed %d.", seed)
   365  	}
   366  	fsym.Topics = prevTopics
   367  
   368  	// encrypt asymmetrically
   369  	key, err := crypto.GenerateKey()
   370  	if err != nil {
   371  		t.Fatalf("failed GenerateKey with seed %d: %s.", seed, err)
   372  	}
   373  	params.KeySym = nil
   374  	params.Dst = &key.PublicKey
   375  	msg, err = NewSentMessage(params)
   376  	if err != nil {
   377  		t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
   378  	}
   379  	env, err = msg.Wrap(params)
   380  	if err != nil {
   381  		t.Fatalf("failed Wrap() with seed %d: %s.", seed, err)
   382  	}
   383  
   384  	// encryption method mismatch
   385  	match = fsym.MatchEnvelope(env)
   386  	if match {
   387  		t.Fatalf("failed MatchEnvelope(encryption method mismatch) with seed %d.", seed)
   388  	}
   389  
   390  	// asymmetric + mismatching topic: mismatch
   391  	match = fasym.MatchEnvelope(env)
   392  	if !match {
   393  		t.Fatalf("failed MatchEnvelope(asymmetric + mismatching topic) with seed %d.", seed)
   394  	}
   395  
   396  	// asymmetric + matching topic: match
   397  	fasym.Topics[i] = fasym.Topics[i+1]
   398  	match = fasym.MatchEnvelope(env)
   399  	if match {
   400  		t.Fatalf("failed MatchEnvelope(asymmetric + matching topic) with seed %d.", seed)
   401  	}
   402  
   403  	// asymmetric + filter without topic (wildcard): match
   404  	fasym.Topics = nil
   405  	match = fasym.MatchEnvelope(env)
   406  	if !match {
   407  		t.Fatalf("failed MatchEnvelope(asymmetric + filter without topic) with seed %d.", seed)
   408  	}
   409  
   410  	// asymmetric + insufficient PoW: mismatch
   411  	fasym.PoW = env.PoW() + 1.0
   412  	match = fasym.MatchEnvelope(env)
   413  	if match {
   414  		t.Fatalf("failed MatchEnvelope(asymmetric + insufficient PoW) with seed %d.", seed)
   415  	}
   416  
   417  	// asymmetric + sufficient PoW: match
   418  	fasym.PoW = env.PoW() / 2
   419  	match = fasym.MatchEnvelope(env)
   420  	if !match {
   421  		t.Fatalf("failed MatchEnvelope(asymmetric + sufficient PoW) with seed %d.", seed)
   422  	}
   423  
   424  	// filter without topic + envelope without topic: match
   425  	env.Topic = TopicType{}
   426  	match = fasym.MatchEnvelope(env)
   427  	if !match {
   428  		t.Fatalf("failed MatchEnvelope(filter without topic + envelope without topic) with seed %d.", seed)
   429  	}
   430  
   431  	// filter with topic + envelope without topic: mismatch
   432  	fasym.Topics = fsym.Topics
   433  	match = fasym.MatchEnvelope(env)
   434  	if match {
   435  		t.Fatalf("failed MatchEnvelope(filter without topic + envelope without topic) with seed %d.", seed)
   436  	}
   437  }
   438  
   439  func TestMatchMessageSym(t *testing.T) {
   440  	InitSingleTest()
   441  
   442  	params, err := generateMessageParams()
   443  	if err != nil {
   444  		t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
   445  	}
   446  
   447  	f, err := generateFilter(t, true)
   448  	if err != nil {
   449  		t.Fatalf("failed generateFilter with seed %d: %s.", seed, err)
   450  	}
   451  
   452  	const index = 1
   453  	params.KeySym = f.KeySym
   454  	params.Topic = BytesToTopic(f.Topics[index])
   455  
   456  	sentMessage, err := NewSentMessage(params)
   457  	if err != nil {
   458  		t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
   459  	}
   460  	env, err := sentMessage.Wrap(params)
   461  	if err != nil {
   462  		t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
   463  	}
   464  	msg := env.Open(f)
   465  	if msg == nil {
   466  		t.Fatalf("failed Open with seed %d.", seed)
   467  	}
   468  
   469  	// Src: match
   470  	*f.Src.X = *params.Src.PublicKey.X
   471  	*f.Src.Y = *params.Src.PublicKey.Y
   472  	if !f.MatchMessage(msg) {
   473  		t.Fatalf("failed MatchEnvelope(src match) with seed %d.", seed)
   474  	}
   475  
   476  	// insufficient PoW: mismatch
   477  	f.PoW = msg.PoW + 1.0
   478  	if f.MatchMessage(msg) {
   479  		t.Fatalf("failed MatchEnvelope(insufficient PoW) with seed %d.", seed)
   480  	}
   481  
   482  	// sufficient PoW: match
   483  	f.PoW = msg.PoW / 2
   484  	if !f.MatchMessage(msg) {
   485  		t.Fatalf("failed MatchEnvelope(sufficient PoW) with seed %d.", seed)
   486  	}
   487  
   488  	// topic mismatch
   489  	f.Topics[index][0]++
   490  	if f.MatchMessage(msg) {
   491  		t.Fatalf("failed MatchEnvelope(topic mismatch) with seed %d.", seed)
   492  	}
   493  	f.Topics[index][0]--
   494  
   495  	// key mismatch
   496  	f.SymKeyHash[0]++
   497  	if f.MatchMessage(msg) {
   498  		t.Fatalf("failed MatchEnvelope(key mismatch) with seed %d.", seed)
   499  	}
   500  	f.SymKeyHash[0]--
   501  
   502  	// Src absent: match
   503  	f.Src = nil
   504  	if !f.MatchMessage(msg) {
   505  		t.Fatalf("failed MatchEnvelope(src absent) with seed %d.", seed)
   506  	}
   507  
   508  	// key hash mismatch
   509  	h := f.SymKeyHash
   510  	f.SymKeyHash = common.Hash{}
   511  	if f.MatchMessage(msg) {
   512  		t.Fatalf("failed MatchEnvelope(key hash mismatch) with seed %d.", seed)
   513  	}
   514  	f.SymKeyHash = h
   515  	if !f.MatchMessage(msg) {
   516  		t.Fatalf("failed MatchEnvelope(key hash match) with seed %d.", seed)
   517  	}
   518  
   519  	// encryption method mismatch
   520  	f.KeySym = nil
   521  	f.KeyAsym, err = crypto.GenerateKey()
   522  	if err != nil {
   523  		t.Fatalf("failed GenerateKey with seed %d: %s.", seed, err)
   524  	}
   525  	if f.MatchMessage(msg) {
   526  		t.Fatalf("failed MatchEnvelope(encryption method mismatch) with seed %d.", seed)
   527  	}
   528  }
   529  
   530  func TestMatchMessageAsym(t *testing.T) {
   531  	InitSingleTest()
   532  
   533  	f, err := generateFilter(t, false)
   534  	if err != nil {
   535  		t.Fatalf("failed generateFilter with seed %d: %s.", seed, err)
   536  	}
   537  
   538  	params, err := generateMessageParams()
   539  	if err != nil {
   540  		t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
   541  	}
   542  
   543  	const index = 1
   544  	params.Topic = BytesToTopic(f.Topics[index])
   545  	params.Dst = &f.KeyAsym.PublicKey
   546  	keySymOrig := params.KeySym
   547  	params.KeySym = nil
   548  
   549  	sentMessage, err := NewSentMessage(params)
   550  	if err != nil {
   551  		t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
   552  	}
   553  	env, err := sentMessage.Wrap(params)
   554  	if err != nil {
   555  		t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
   556  	}
   557  	msg := env.Open(f)
   558  	if msg == nil {
   559  		t.Fatalf("failed to open with seed %d.", seed)
   560  	}
   561  
   562  	// Src: match
   563  	*f.Src.X = *params.Src.PublicKey.X
   564  	*f.Src.Y = *params.Src.PublicKey.Y
   565  	if !f.MatchMessage(msg) {
   566  		t.Fatalf("failed MatchMessage(src match) with seed %d.", seed)
   567  	}
   568  
   569  	// insufficient PoW: mismatch
   570  	f.PoW = msg.PoW + 1.0
   571  	if f.MatchMessage(msg) {
   572  		t.Fatalf("failed MatchEnvelope(insufficient PoW) with seed %d.", seed)
   573  	}
   574  
   575  	// sufficient PoW: match
   576  	f.PoW = msg.PoW / 2
   577  	if !f.MatchMessage(msg) {
   578  		t.Fatalf("failed MatchEnvelope(sufficient PoW) with seed %d.", seed)
   579  	}
   580  
   581  	// topic mismatch
   582  	f.Topics[index][0]++
   583  	if f.MatchMessage(msg) {
   584  		t.Fatalf("failed MatchEnvelope(topic mismatch) with seed %d.", seed)
   585  	}
   586  	f.Topics[index][0]--
   587  
   588  	// key mismatch
   589  	prev := *f.KeyAsym.PublicKey.X
   590  	zero := *big.NewInt(0)
   591  	*f.KeyAsym.PublicKey.X = zero
   592  	if f.MatchMessage(msg) {
   593  		t.Fatalf("failed MatchEnvelope(key mismatch) with seed %d.", seed)
   594  	}
   595  	*f.KeyAsym.PublicKey.X = prev
   596  
   597  	// Src absent: match
   598  	f.Src = nil
   599  	if !f.MatchMessage(msg) {
   600  		t.Fatalf("failed MatchEnvelope(src absent) with seed %d.", seed)
   601  	}
   602  
   603  	// encryption method mismatch
   604  	f.KeySym = keySymOrig
   605  	f.KeyAsym = nil
   606  	if f.MatchMessage(msg) {
   607  		t.Fatalf("failed MatchEnvelope(encryption method mismatch) with seed %d.", seed)
   608  	}
   609  }
   610  
   611  func cloneFilter(orig *Filter) *Filter {
   612  	var clone Filter
   613  	clone.Messages = make(map[common.Hash]*ReceivedMessage)
   614  	clone.Src = orig.Src
   615  	clone.KeyAsym = orig.KeyAsym
   616  	clone.KeySym = orig.KeySym
   617  	clone.Topics = orig.Topics
   618  	clone.PoW = orig.PoW
   619  	clone.AllowP2P = orig.AllowP2P
   620  	clone.SymKeyHash = orig.SymKeyHash
   621  	return &clone
   622  }
   623  
   624  func generateCompatibeEnvelope(t *testing.T, f *Filter) *Envelope {
   625  	params, err := generateMessageParams()
   626  	if err != nil {
   627  		t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
   628  		return nil
   629  	}
   630  
   631  	params.KeySym = f.KeySym
   632  	params.Topic = BytesToTopic(f.Topics[2])
   633  	sentMessage, err := NewSentMessage(params)
   634  	if err != nil {
   635  		t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
   636  	}
   637  	env, err := sentMessage.Wrap(params)
   638  	if err != nil {
   639  		t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
   640  		return nil
   641  	}
   642  	return env
   643  }
   644  
   645  func TestWatchers(t *testing.T) {
   646  	InitSingleTest()
   647  
   648  	const NumFilters = 16
   649  	const NumMessages = 256
   650  	var i int
   651  	var j uint32
   652  	var e *Envelope
   653  	var x, firstID string
   654  	var err error
   655  
   656  	w := New(&Config{})
   657  	filters := NewFilters(w)
   658  	tst := generateTestCases(t, NumFilters)
   659  	for i = 0; i < NumFilters; i++ {
   660  		tst[i].f.Src = nil
   661  		x, err = filters.Install(tst[i].f)
   662  		if err != nil {
   663  			t.Fatalf("failed to install filter with seed %d: %s.", seed, err)
   664  		}
   665  		tst[i].id = x
   666  		if len(firstID) == 0 {
   667  			firstID = x
   668  		}
   669  	}
   670  
   671  	lastID := x
   672  
   673  	var envelopes [NumMessages]*Envelope
   674  	for i = 0; i < NumMessages; i++ {
   675  		j = mrand.Uint32() % NumFilters
   676  		e = generateCompatibeEnvelope(t, tst[j].f)
   677  		envelopes[i] = e
   678  		tst[j].msgCnt++
   679  	}
   680  
   681  	for i = 0; i < NumMessages; i++ {
   682  		filters.NotifyWatchers(envelopes[i], false)
   683  	}
   684  
   685  	var total int
   686  	var mail []*ReceivedMessage
   687  	var count [NumFilters]int
   688  
   689  	for i = 0; i < NumFilters; i++ {
   690  		mail = tst[i].f.Retrieve()
   691  		count[i] = len(mail)
   692  		total += len(mail)
   693  	}
   694  
   695  	if total != NumMessages {
   696  		t.Fatalf("failed with seed %d: total = %d, want: %d.", seed, total, NumMessages)
   697  	}
   698  
   699  	for i = 0; i < NumFilters; i++ {
   700  		mail = tst[i].f.Retrieve()
   701  		if len(mail) != 0 {
   702  			t.Fatalf("failed with seed %d: i = %d.", seed, i)
   703  		}
   704  
   705  		if tst[i].msgCnt != count[i] {
   706  			t.Fatalf("failed with seed %d: count[%d]: get %d, want %d.", seed, i, tst[i].msgCnt, count[i])
   707  		}
   708  	}
   709  
   710  	// another round with a cloned filter
   711  
   712  	clone := cloneFilter(tst[0].f)
   713  	filters.Uninstall(lastID)
   714  	total = 0
   715  	last := NumFilters - 1
   716  	tst[last].f = clone
   717  	filters.Install(clone)
   718  	for i = 0; i < NumFilters; i++ {
   719  		tst[i].msgCnt = 0
   720  		count[i] = 0
   721  	}
   722  
   723  	// make sure that the first watcher receives at least one message
   724  	e = generateCompatibeEnvelope(t, tst[0].f)
   725  	envelopes[0] = e
   726  	tst[0].msgCnt++
   727  	for i = 1; i < NumMessages; i++ {
   728  		j = mrand.Uint32() % NumFilters
   729  		e = generateCompatibeEnvelope(t, tst[j].f)
   730  		envelopes[i] = e
   731  		tst[j].msgCnt++
   732  	}
   733  
   734  	for i = 0; i < NumMessages; i++ {
   735  		filters.NotifyWatchers(envelopes[i], false)
   736  	}
   737  
   738  	for i = 0; i < NumFilters; i++ {
   739  		mail = tst[i].f.Retrieve()
   740  		count[i] = len(mail)
   741  		total += len(mail)
   742  	}
   743  
   744  	combined := tst[0].msgCnt + tst[last].msgCnt
   745  	if total != NumMessages+count[0] {
   746  		t.Fatalf("failed with seed %d: total = %d, count[0] = %d.", seed, total, count[0])
   747  	}
   748  
   749  	if combined != count[0] {
   750  		t.Fatalf("failed with seed %d: combined = %d, count[0] = %d.", seed, combined, count[0])
   751  	}
   752  
   753  	if combined != count[last] {
   754  		t.Fatalf("failed with seed %d: combined = %d, count[last] = %d.", seed, combined, count[last])
   755  	}
   756  
   757  	for i = 1; i < NumFilters-1; i++ {
   758  		mail = tst[i].f.Retrieve()
   759  		if len(mail) != 0 {
   760  			t.Fatalf("failed with seed %d: i = %d.", seed, i)
   761  		}
   762  
   763  		if tst[i].msgCnt != count[i] {
   764  			t.Fatalf("failed with seed %d: i = %d, get %d, want %d.", seed, i, tst[i].msgCnt, count[i])
   765  		}
   766  	}
   767  
   768  	// test AcceptP2P
   769  
   770  	total = 0
   771  	filters.NotifyWatchers(envelopes[0], true)
   772  
   773  	for i = 0; i < NumFilters; i++ {
   774  		mail = tst[i].f.Retrieve()
   775  		total += len(mail)
   776  	}
   777  
   778  	if total != 0 {
   779  		t.Fatalf("failed with seed %d: total: got %d, want 0.", seed, total)
   780  	}
   781  
   782  	f := filters.Get(firstID)
   783  	if f == nil {
   784  		t.Fatalf("failed to get the filter with seed %d.", seed)
   785  	}
   786  	f.AllowP2P = true
   787  	total = 0
   788  	filters.NotifyWatchers(envelopes[0], true)
   789  
   790  	for i = 0; i < NumFilters; i++ {
   791  		mail = tst[i].f.Retrieve()
   792  		total += len(mail)
   793  	}
   794  
   795  	if total != 1 {
   796  		t.Fatalf("failed with seed %d: total: got %d, want 1.", seed, total)
   797  	}
   798  }
   799  
   800  func TestVariableTopics(t *testing.T) {
   801  	InitSingleTest()
   802  
   803  	const lastTopicByte = 3
   804  	var match bool
   805  	params, err := generateMessageParams()
   806  	if err != nil {
   807  		t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
   808  	}
   809  	msg, err := NewSentMessage(params)
   810  	if err != nil {
   811  		t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
   812  	}
   813  	env, err := msg.Wrap(params)
   814  	if err != nil {
   815  		t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
   816  	}
   817  
   818  	f, err := generateFilter(t, true)
   819  	if err != nil {
   820  		t.Fatalf("failed generateFilter with seed %d: %s.", seed, err)
   821  	}
   822  
   823  	for i := 0; i < 4; i++ {
   824  		env.Topic = BytesToTopic(f.Topics[i])
   825  		match = f.MatchEnvelope(env)
   826  		if !match {
   827  			t.Fatalf("failed MatchEnvelope symmetric with seed %d, step %d.", seed, i)
   828  		}
   829  
   830  		f.Topics[i][lastTopicByte]++
   831  		match = f.MatchEnvelope(env)
   832  		if match {
   833  			t.Fatalf("MatchEnvelope symmetric with seed %d, step %d: false positive.", seed, i)
   834  		}
   835  	}
   836  }
   837  
   838  func TestMatchSingleTopic_ReturnTrue(t *testing.T) {
   839  	bt := []byte("test")
   840  	topic := BytesToTopic(bt)
   841  
   842  	if !matchSingleTopic(topic, bt) {
   843  		t.FailNow()
   844  	}
   845  }
   846  
   847  func TestMatchSingleTopic_WithTail_ReturnTrue(t *testing.T) {
   848  	bt := []byte("test with tail")
   849  	topic := BytesToTopic([]byte("test"))
   850  
   851  	if !matchSingleTopic(topic, bt) {
   852  		t.FailNow()
   853  	}
   854  }
   855  
   856  func TestMatchSingleTopic_NotEquals_ReturnFalse(t *testing.T) {
   857  	bt := []byte("tes")
   858  	topic := BytesToTopic(bt)
   859  
   860  	if matchSingleTopic(topic, bt) {
   861  		t.FailNow()
   862  	}
   863  }
   864  
   865  func TestMatchSingleTopic_InsufficientLength_ReturnFalse(t *testing.T) {
   866  	bt := []byte("test")
   867  	topic := BytesToTopic([]byte("not_equal"))
   868  
   869  	if matchSingleTopic(topic, bt) {
   870  		t.FailNow()
   871  	}
   872  }