package peer import ( "fmt" "testing" ) // TestMruNonceMap ensures the mruNonceMap behaves as expected including limiting, eviction of least-recently used // entries, specific entry removal, and existence tests. func TestMruNonceMap(t *testing.T) { // Create a bunch of fake nonces to use in testing the mru Nonce code. numNonces := 10 nonces := make([]uint64, 0, numNonces) for i := 0; i < numNonces; i++ { nonces = append(nonces, uint64(i)) } tests := []struct { name string limit int }{ {name: "limit 0", limit: 0}, {name: "limit 1", limit: 1}, {name: "limit 5", limit: 5}, {name: "limit 7", limit: 7}, {name: "limit one less than available", limit: numNonces - 1}, {name: "limit all available", limit: numNonces}, } testLoop: for i, test := range tests { // Create a new mru Nonce map limited by the specified test limit and add all of the test nonces. This will // cause evicition since there are more test nonces than the limits. mruNonceMap := newMruNonceMap(uint(test.limit)) for j := 0; j < numNonces; j++ { mruNonceMap.Add(nonces[j]) } // Ensure the limited number of most recent entries in the list exist. for j := numNonces - test.limit; j < numNonces; j++ { if !mruNonceMap.Exists(nonces[j]) { t.Errorf("Exists #%d (%s) entry %d does not "+ "exist", i, test.name, nonces[j], ) continue testLoop } } // Ensure the entries before the limited number of most recent entries in the list do not exist. for j := 0; j < numNonces-test.limit; j++ { if mruNonceMap.Exists(nonces[j]) { t.Errorf("Exists #%d (%s) entry %d exists", i, test.name, nonces[j], ) continue testLoop } } // Readd the entry that should currently be the least-recently used entry so it becomes the most-recently used // entry, then force an eviction by adding an entry that doesn't exist and ensure the evicted entry is the new // least-recently used entry. This check needs at least 2 entries. if test.limit > 1 { origLruIndex := numNonces - test.limit mruNonceMap.Add(nonces[origLruIndex]) mruNonceMap.Add(uint64(numNonces) + 1) // Ensure the original lru entry still exists since it was updated and should've have become the mru entry. if !mruNonceMap.Exists(nonces[origLruIndex]) { t.Errorf("MRU #%d (%s) entry %d does not exist", i, test.name, nonces[origLruIndex], ) continue testLoop } // Ensure the entry that should've become the new lru entry was evicted. newLruIndex := origLruIndex + 1 if mruNonceMap.Exists(nonces[newLruIndex]) { t.Errorf("MRU #%d (%s) entry %d exists", i, test.name, nonces[newLruIndex], ) continue testLoop } } // Delete all of the entries in the list, including those that don't exist in the map, and ensure they no longer // exist. for j := 0; j < numNonces; j++ { mruNonceMap.Delete(nonces[j]) if mruNonceMap.Exists(nonces[j]) { t.Errorf("Delete #%d (%s) entry %d exists", i, test.name, nonces[j], ) continue testLoop } } } } // TestMruNonceMapStringer tests the stringized output for the mruNonceMap type. func TestMruNonceMapStringer(t *testing.T) { // Create a couple of fake nonces to use in testing the mru Nonce stringer code. nonce1 := uint64(10) nonce2 := uint64(20) // Create new mru Nonce map and add the nonces. mruNonceMap := newMruNonceMap(uint(2)) mruNonceMap.Add(nonce1) mruNonceMap.Add(nonce2) // Ensure the stringer gives the expected result. Since map iteration is not ordered, either entry could be first, // so account for both cases. wantStr1 := fmt.Sprintf("<%d>[%d, %d]", 2, nonce1, nonce2) wantStr2 := fmt.Sprintf("<%d>[%d, %d]", 2, nonce2, nonce1) gotStr := mruNonceMap.String() if gotStr != wantStr1 && gotStr != wantStr2 { t.Fatalf("unexpected string representation - got %q, want %q "+ "or %q", gotStr, wantStr1, wantStr2, ) } } // BenchmarkMruNonceList performs basic benchmarks on the most recently used Nonce handling. func BenchmarkMruNonceList(b *testing.B) { // Create a bunch of fake nonces to use in benchmarking the mru Nonce code. b.StopTimer() numNonces := 100000 nonces := make([]uint64, 0, numNonces) for i := 0; i < numNonces; i++ { nonces = append(nonces, uint64(i)) } b.StartTimer() // Benchmark the add plus evicition code. limit := 20000 mruNonceMap := newMruNonceMap(uint(limit)) for i := 0; i < b.N; i++ { mruNonceMap.Add(nonces[i%numNonces]) } }