github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/whisper/whisperv5/filter_test.go (about)

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