github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/whisper/whisperv6/filter_test.go (about)

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