| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- // Copyright (c) Tailscale Inc & AUTHORS
- // SPDX-License-Identifier: BSD-3-Clause
- package flowtrack
- import (
- "encoding/json"
- "net/netip"
- "testing"
- "tailscale.com/tstest"
- "tailscale.com/types/ipproto"
- )
- func TestCache(t *testing.T) {
- c := &Cache[int]{MaxEntries: 2}
- k1 := MakeTuple(0, netip.MustParseAddrPort("1.1.1.1:1"), netip.MustParseAddrPort("1.1.1.1:1"))
- k2 := MakeTuple(0, netip.MustParseAddrPort("1.1.1.1:1"), netip.MustParseAddrPort("2.2.2.2:2"))
- k3 := MakeTuple(0, netip.MustParseAddrPort("1.1.1.1:1"), netip.MustParseAddrPort("3.3.3.3:3"))
- k4 := MakeTuple(0, netip.MustParseAddrPort("1.1.1.1:1"), netip.MustParseAddrPort("4.4.4.4:4"))
- wantLen := func(want int) {
- t.Helper()
- if got := c.Len(); got != want {
- t.Fatalf("Len = %d; want %d", got, want)
- }
- }
- wantVal := func(key Tuple, want int) {
- t.Helper()
- got, ok := c.Get(key)
- if !ok {
- t.Fatalf("Get(%q) failed; want value %v", key, want)
- }
- if *got != want {
- t.Fatalf("Get(%q) = %v; want %v", key, got, want)
- }
- }
- wantMissing := func(key Tuple) {
- t.Helper()
- if got, ok := c.Get(key); ok {
- t.Fatalf("Get(%q) = %v; want absent from cache", key, got)
- }
- }
- wantLen(0)
- c.RemoveOldest() // shouldn't panic
- c.Remove(k4) // shouldn't panic
- c.Add(k1, 1)
- wantLen(1)
- c.Add(k2, 2)
- wantLen(2)
- c.Add(k3, 3)
- wantLen(2) // hit the max
- wantMissing(k1)
- c.Remove(k1)
- wantLen(2) // no change; k1 should've been the deleted one per LRU
- wantVal(k3, 3)
- wantVal(k2, 2)
- c.Remove(k2)
- wantLen(1)
- wantMissing(k2)
- c.Add(k3, 30)
- wantVal(k3, 30)
- wantLen(1)
- err := tstest.MinAllocsPerRun(t, 0, func() {
- got, ok := c.Get(k3)
- if !ok {
- t.Fatal("missing k3")
- }
- if *got != 30 {
- t.Fatalf("got = %d; want 30", got)
- }
- })
- if err != nil {
- t.Error(err)
- }
- }
- func BenchmarkMapKeys(b *testing.B) {
- b.Run("typed", func(b *testing.B) {
- c := &Cache[struct{}]{MaxEntries: 1000}
- var t Tuple
- for proto := range 20 {
- t = Tuple{proto: ipproto.Proto(proto), src: netip.MustParseAddr("1.1.1.1").As16(), srcPort: 1, dst: netip.MustParseAddr("1.1.1.1").As16(), dstPort: 1}
- c.Add(t, struct{}{})
- }
- for i := 0; i < b.N; i++ {
- _, ok := c.Get(t)
- if !ok {
- b.Fatal("missing key")
- }
- }
- })
- }
- func TestStringJSON(t *testing.T) {
- v := MakeTuple(123,
- netip.MustParseAddrPort("1.2.3.4:5"),
- netip.MustParseAddrPort("6.7.8.9:10"))
- if got, want := v.String(), "(IPProto-123 1.2.3.4:5 => 6.7.8.9:10)"; got != want {
- t.Errorf("String = %q; want %q", got, want)
- }
- got, err := json.Marshal(v)
- if err != nil {
- t.Fatal(err)
- }
- const want = `{"proto":123,"src":"1.2.3.4:5","dst":"6.7.8.9:10"}`
- if string(got) != want {
- t.Errorf("Marshal = %q; want %q", got, want)
- }
- var back Tuple
- if err := json.Unmarshal(got, &back); err != nil {
- t.Fatal(err)
- }
- if back != v {
- t.Errorf("back = %v; want %v", back, v)
- }
- }
|