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