Files
tailscale/feature/tailnetlock/tailnetlock_test.go
Brad Fitzpatrick 4bb6f35c1f ipn/ipnlocal: consolidate test-only LocalBackend methods behind ForTest
Move all the FooForTest methods on LocalBackend to instead be
methods on a new unexported forTest type which is then given out
to callers in other packages via an exported ForTest method
(panicking in non-test contexts) that returns that unexported type.

This is unusual style (exported returning unexported) but declutters
godoc and makes call sites both more explicit and easier to read
without the "ForTest" suffix polluting the symbols. Now FooForTest()
changes into ForTest().Foo().

This was motivated by a pending change moving a bunch of code out of
LocalBackend into other packages that required adding more ForTest
methods to LocalBackend to keep the tests (now in other packages)
working. Instead, do this refactor now so the future change is prettier.

Updates #12614
Updates #cleanup

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Change-Id: Ib25e6d76d48dc8622ac3a955e0b1220d582e63a8
2026-06-27 16:11:42 -07:00

144 lines
3.7 KiB
Go

// Copyright (c) Tailscale Inc & contributors
// SPDX-License-Identifier: BSD-3-Clause
package tailnetlock
import (
"bytes"
"encoding/json"
"net/http/httptest"
"strings"
"testing"
"tailscale.com/ipn/ipnlocal"
"tailscale.com/tka"
"tailscale.com/types/key"
"tailscale.com/util/must"
)
func TestHandleC2NDebugTKA(t *testing.T) {
makeTKA := func(length int) (tka.CompactableChonk, *tka.Authority) {
if length == 0 {
return nil, nil
}
signerKey := key.NewNLPrivate()
key1 := tka.Key{Kind: tka.Key25519, Public: signerKey.Public().Verifier(), Votes: 2}
state := tka.CreateStateForTest(key1)
chonk := tka.ChonkMem()
authority, _, err := tka.Create(chonk, state, signerKey)
if err != nil {
t.Fatalf("tka.Create() failed: %v", err)
}
for range length - 1 {
updater := authority.NewUpdater(signerKey)
key2 := tka.Key{Kind: tka.Key25519, Public: key.NewNLPrivate().Public().Verifier(), Votes: 2}
updater.AddKey(key2)
aums := must.Get(updater.Finalize(chonk))
must.Do(authority.Inform(chonk, aums))
}
return chonk, authority
}
bodyHead := func(body *bytes.Buffer) string {
count := 0
var sb strings.Builder
for line := range strings.Lines(body.String()) {
if count == 10 {
sb.WriteString("...")
break
}
sb.WriteString(line)
count++
}
return sb.String()
}
// matches [jsonoutput.PrintTailnetLockLogJSONV1]
type response struct {
SchemaVersion string
Messages []any
}
t.Run("tailnet-lock-disabled", func(t *testing.T) {
b := ipnlocal.LocalBackendWithTKAForTest(nil, nil)
req := httptest.NewRequest("GET", "/debug/tka/log", nil)
rec := httptest.NewRecorder()
b.ForTest().HandleC2N(rec, req)
if rec.Code != 400 {
t.Fatalf("got status code: %v, want: 400\nBody: %s", rec.Code, rec.Body)
}
})
t.Run("tailnet-lock-enabled", func(t *testing.T) {
chonk, authority := makeTKA(2)
b := ipnlocal.LocalBackendWithTKAForTest(chonk, authority)
req := httptest.NewRequest("GET", "/debug/tka/log", nil)
rec := httptest.NewRecorder()
b.ForTest().HandleC2N(rec, req)
if rec.Code != 200 {
t.Fatalf("got status code: %v, want: 200\nBody: %s", rec.Code, bodyHead(rec.Body))
}
var got response
if err := json.Unmarshal(rec.Body.Bytes(), &got); err != nil {
t.Fatalf("couldn't parse JSON: %v\nbody: %s", err, bodyHead(rec.Body))
}
if len(got.Messages) != 2 {
t.Fatalf("got %d items, want 2", len(got.Messages))
}
})
t.Run("default-limit", func(t *testing.T) {
chonk, authority := makeTKA(60)
b := ipnlocal.LocalBackendWithTKAForTest(chonk, authority)
req := httptest.NewRequest("GET", "/debug/tka/log", nil)
rec := httptest.NewRecorder()
b.ForTest().HandleC2N(rec, req)
if rec.Code != 200 {
t.Fatalf("got status code: %v, want: 200\nBody: %s", rec.Code, bodyHead(rec.Body))
}
var got response
if err := json.Unmarshal(rec.Body.Bytes(), &got); err != nil {
t.Fatalf("couldn't parse JSON: %v\nbody: %s", err, bodyHead(rec.Body))
}
if len(got.Messages) != 50 {
t.Fatalf("got %d items, want 50", len(got.Messages))
}
})
t.Run("override-limit", func(t *testing.T) {
chonk, authority := makeTKA(65)
b := ipnlocal.LocalBackendWithTKAForTest(chonk, authority)
req := httptest.NewRequest("GET", "/debug/tka/log?limit=60", nil)
rec := httptest.NewRecorder()
b.ForTest().HandleC2N(rec, req)
if rec.Code != 200 {
t.Fatalf("got status code: %v, want: 200\nBody: %s", rec.Code, bodyHead(rec.Body))
}
var got response
if err := json.Unmarshal(rec.Body.Bytes(), &got); err != nil {
t.Fatalf("couldn't parse JSON: %v\nbody: %s", err, bodyHead(rec.Body))
}
if len(got.Messages) != 60 {
t.Fatalf("got %d items, want 60", len(got.Messages))
}
})
}