github.com/BlockABC/godash@v0.0.0-20191112120524-f4aa3a32c566/peer/mruinvmap_test.go (about)

     1  // Copyright (c) 2013-2015 The btcsuite developers
     2  // Copyright (c) 2016 The Dash developers
     3  // Use of this source code is governed by an ISC
     4  // license that can be found in the LICENSE file.
     5  
     6  package peer
     7  
     8  import (
     9  	"crypto/rand"
    10  	"fmt"
    11  	"testing"
    12  
    13  	"github.com/BlockABC/godash/wire"
    14  )
    15  
    16  // TestMruInventoryMap ensures the MruInventoryMap behaves as expected including
    17  // limiting, eviction of least-recently used entries, specific entry removal,
    18  // and existence tests.
    19  func TestMruInventoryMap(t *testing.T) {
    20  	// Create a bunch of fake inventory vectors to use in testing the mru
    21  	// inventory code.
    22  	numInvVects := 10
    23  	invVects := make([]*wire.InvVect, 0, numInvVects)
    24  	for i := 0; i < numInvVects; i++ {
    25  		hash := &wire.ShaHash{byte(i)}
    26  		iv := wire.NewInvVect(wire.InvTypeBlock, hash)
    27  		invVects = append(invVects, iv)
    28  	}
    29  
    30  	tests := []struct {
    31  		name  string
    32  		limit int
    33  	}{
    34  		{name: "limit 0", limit: 0},
    35  		{name: "limit 1", limit: 1},
    36  		{name: "limit 5", limit: 5},
    37  		{name: "limit 7", limit: 7},
    38  		{name: "limit one less than available", limit: numInvVects - 1},
    39  		{name: "limit all available", limit: numInvVects},
    40  	}
    41  
    42  testLoop:
    43  	for i, test := range tests {
    44  		// Create a new mru inventory map limited by the specified test
    45  		// limit and add all of the test inventory vectors.  This will
    46  		// cause evicition since there are more test inventory vectors
    47  		// than the limits.
    48  		mruInvMap := newMruInventoryMap(uint(test.limit))
    49  		for j := 0; j < numInvVects; j++ {
    50  			mruInvMap.Add(invVects[j])
    51  		}
    52  
    53  		// Ensure the limited number of most recent entries in the
    54  		// inventory vector list exist.
    55  		for j := numInvVects - test.limit; j < numInvVects; j++ {
    56  			if !mruInvMap.Exists(invVects[j]) {
    57  				t.Errorf("Exists #%d (%s) entry %s does not "+
    58  					"exist", i, test.name, *invVects[j])
    59  				continue testLoop
    60  			}
    61  		}
    62  
    63  		// Ensure the entries before the limited number of most recent
    64  		// entries in the inventory vector list do not exist.
    65  		for j := 0; j < numInvVects-test.limit; j++ {
    66  			if mruInvMap.Exists(invVects[j]) {
    67  				t.Errorf("Exists #%d (%s) entry %s exists", i,
    68  					test.name, *invVects[j])
    69  				continue testLoop
    70  			}
    71  		}
    72  
    73  		// Readd the entry that should currently be the least-recently
    74  		// used entry so it becomes the most-recently used entry, then
    75  		// force an eviction by adding an entry that doesn't exist and
    76  		// ensure the evicted entry is the new least-recently used
    77  		// entry.
    78  		//
    79  		// This check needs at least 2 entries.
    80  		if test.limit > 1 {
    81  			origLruIndex := numInvVects - test.limit
    82  			mruInvMap.Add(invVects[origLruIndex])
    83  
    84  			iv := wire.NewInvVect(wire.InvTypeBlock,
    85  				&wire.ShaHash{0x00, 0x01})
    86  			mruInvMap.Add(iv)
    87  
    88  			// Ensure the original lru entry still exists since it
    89  			// was updated and should've have become the mru entry.
    90  			if !mruInvMap.Exists(invVects[origLruIndex]) {
    91  				t.Errorf("MRU #%d (%s) entry %s does not exist",
    92  					i, test.name, *invVects[origLruIndex])
    93  				continue testLoop
    94  			}
    95  
    96  			// Ensure the entry that should've become the new lru
    97  			// entry was evicted.
    98  			newLruIndex := origLruIndex + 1
    99  			if mruInvMap.Exists(invVects[newLruIndex]) {
   100  				t.Errorf("MRU #%d (%s) entry %s exists", i,
   101  					test.name, *invVects[newLruIndex])
   102  				continue testLoop
   103  			}
   104  		}
   105  
   106  		// Delete all of the entries in the inventory vector list,
   107  		// including those that don't exist in the map, and ensure they
   108  		// no longer exist.
   109  		for j := 0; j < numInvVects; j++ {
   110  			mruInvMap.Delete(invVects[j])
   111  			if mruInvMap.Exists(invVects[j]) {
   112  				t.Errorf("Delete #%d (%s) entry %s exists", i,
   113  					test.name, *invVects[j])
   114  				continue testLoop
   115  			}
   116  		}
   117  	}
   118  }
   119  
   120  // TestMruInventoryMapStringer tests the stringized output for the
   121  // MruInventoryMap type.
   122  func TestMruInventoryMapStringer(t *testing.T) {
   123  	// Create a couple of fake inventory vectors to use in testing the mru
   124  	// inventory stringer code.
   125  	hash1 := &wire.ShaHash{0x01}
   126  	hash2 := &wire.ShaHash{0x02}
   127  	iv1 := wire.NewInvVect(wire.InvTypeBlock, hash1)
   128  	iv2 := wire.NewInvVect(wire.InvTypeBlock, hash2)
   129  
   130  	// Create new mru inventory map and add the inventory vectors.
   131  	mruInvMap := newMruInventoryMap(uint(2))
   132  	mruInvMap.Add(iv1)
   133  	mruInvMap.Add(iv2)
   134  
   135  	// Ensure the stringer gives the expected result.  Since map iteration
   136  	// is not ordered, either entry could be first, so account for both
   137  	// cases.
   138  	wantStr1 := fmt.Sprintf("<%d>[%s, %s]", 2, *iv1, *iv2)
   139  	wantStr2 := fmt.Sprintf("<%d>[%s, %s]", 2, *iv2, *iv1)
   140  	gotStr := mruInvMap.String()
   141  	if gotStr != wantStr1 && gotStr != wantStr2 {
   142  		t.Fatalf("unexpected string representation - got %q, want %q "+
   143  			"or %q", gotStr, wantStr1, wantStr2)
   144  	}
   145  }
   146  
   147  // BenchmarkMruInventoryList performs basic benchmarks on the most recently
   148  // used inventory handling.
   149  func BenchmarkMruInventoryList(b *testing.B) {
   150  	// Create a bunch of fake inventory vectors to use in benchmarking
   151  	// the mru inventory code.
   152  	b.StopTimer()
   153  	numInvVects := 100000
   154  	invVects := make([]*wire.InvVect, 0, numInvVects)
   155  	for i := 0; i < numInvVects; i++ {
   156  		hashBytes := make([]byte, wire.HashSize)
   157  		rand.Read(hashBytes)
   158  		hash, _ := wire.NewShaHash(hashBytes)
   159  		iv := wire.NewInvVect(wire.InvTypeBlock, hash)
   160  		invVects = append(invVects, iv)
   161  	}
   162  	b.StartTimer()
   163  
   164  	// Benchmark the add plus evicition code.
   165  	limit := 20000
   166  	mruInvMap := newMruInventoryMap(uint(limit))
   167  	for i := 0; i < b.N; i++ {
   168  		mruInvMap.Add(invVects[i%numInvVects])
   169  	}
   170  }