summaryrefslogtreecommitdiffhomepage
path: root/control/controlclient
diff options
context:
space:
mode:
authorKristoffer Dalby <kristoffer@tailscale.com>2026-03-12 11:15:04 +0000
committerKristoffer Dalby <kristoffer@tailscale.com>2026-03-12 11:15:04 +0000
commit9c5607138a850cd2eeac099aa22ae71c15699c38 (patch)
tree77870ccd86c7423e11de3f2e854e44dc46426f7c /control/controlclient
parent6fd492b7c814adb9e746ababfd56277f2cc40b30 (diff)
downloadtailscale-kradalby/disable-logtail-per-instance.tar.xz
tailscale-kradalby/disable-logtail-per-instance.zip
logtail,control/controlclient,ipn/ipnlocal: add tests for per-instance DisableLogTailkradalby/disable-logtail-per-instance
Add test coverage for the per-instance DisableLogTail feature: - TestEnableDisableRoundTrip: verify logtail.Enable/Disable toggle the global atomic bool correctly through multiple round-trips. - TestHandleDebugMessageDisableLogTail: verify handleDebugMessage fires the OnDisableLogTail callback, does NOT call envknob.SetNoLogsNoSupport, handles nil callback without panic, and does not fire the callback when DisableLogTail is false. - TestNoLogsNoSupportCombinesSources: verify LocalBackend.NoLogsNoSupport returns true when either the envknob or noLogsFromControl is set. - TestFlowLogsConflictCheck: verify that when logging is disabled and a netmap with CapabilityDataPlaneAuditLogs arrives, WantRunning is set to false with the correct error message (different for control-disabled vs user-disabled). - TestStartLockedClearsControlDisableLogTail: verify that Start clears noLogsFromControl and re-enables logtail. - TestProfileSwitchHeadscaleToTailscale: verify the full lifecycle of switching from a control server that disabled logging to one that requires flow logs. - TestGlobalNoLogsPreventReEnable: verify that when the global envknob is set, Start does NOT re-enable logtail, and the conflict check fires with the user-explicit error message.
Diffstat (limited to 'control/controlclient')
-rw-r--r--control/controlclient/direct_test.go82
1 files changed, 82 insertions, 0 deletions
diff --git a/control/controlclient/direct_test.go b/control/controlclient/direct_test.go
index d10b346ae..90500e9cf 100644
--- a/control/controlclient/direct_test.go
+++ b/control/controlclient/direct_test.go
@@ -4,15 +4,19 @@
package controlclient
import (
+ "context"
"encoding/json"
"net/http"
"net/http/httptest"
"net/netip"
+ "sync/atomic"
"testing"
"time"
+ "tailscale.com/envknob"
"tailscale.com/hostinfo"
"tailscale.com/ipn/ipnstate"
+ "tailscale.com/logtail"
"tailscale.com/net/netmon"
"tailscale.com/net/tsdial"
"tailscale.com/tailcfg"
@@ -181,3 +185,81 @@ func TestTsmpPing(t *testing.T) {
t.Fatal(err)
}
}
+
+func TestHandleDebugMessageDisableLogTail(t *testing.T) {
+ // This test mutates package-level logtail state and must not run in
+ // parallel with tests that depend on logtail being enabled.
+ t.Cleanup(func() { logtail.Enable() })
+
+ t.Run("callback_fires", func(t *testing.T) {
+ logtail.Enable() // reset from any prior subtest
+
+ var called atomic.Bool
+ c := &Direct{
+ logf: t.Logf,
+ onDisableLogTail: func() { called.Store(true) },
+ }
+
+ err := c.handleDebugMessage(context.Background(), &tailcfg.Debug{DisableLogTail: true})
+ if err != nil {
+ t.Fatalf("handleDebugMessage: %v", err)
+ }
+
+ if !called.Load() {
+ t.Error("onDisableLogTail callback was not called")
+ }
+ })
+
+ t.Run("envknob_not_set", func(t *testing.T) {
+ logtail.Enable() // reset
+ t.Setenv("TS_NO_LOGS_NO_SUPPORT", "")
+
+ c := &Direct{
+ logf: t.Logf,
+ onDisableLogTail: func() {},
+ }
+
+ err := c.handleDebugMessage(context.Background(), &tailcfg.Debug{DisableLogTail: true})
+ if err != nil {
+ t.Fatalf("handleDebugMessage: %v", err)
+ }
+
+ if envknob.NoLogsNoSupport() {
+ t.Error("envknob.NoLogsNoSupport() should be false; handleDebugMessage must not call envknob.SetNoLogsNoSupport()")
+ }
+ })
+
+ t.Run("nil_callback_no_panic", func(t *testing.T) {
+ logtail.Enable() // reset
+
+ c := &Direct{
+ logf: t.Logf,
+ onDisableLogTail: nil,
+ }
+
+ err := c.handleDebugMessage(context.Background(), &tailcfg.Debug{DisableLogTail: true})
+ if err != nil {
+ t.Fatalf("handleDebugMessage: %v", err)
+ }
+ // No panic means success.
+ })
+
+ t.Run("false_does_not_fire", func(t *testing.T) {
+ logtail.Enable() // reset
+
+ var called atomic.Bool
+ c := &Direct{
+ logf: t.Logf,
+ onDisableLogTail: func() { called.Store(true) },
+ }
+
+ err := c.handleDebugMessage(context.Background(), &tailcfg.Debug{DisableLogTail: false})
+ if err != nil {
+ t.Fatalf("handleDebugMessage: %v", err)
+ }
+
+ if called.Load() {
+ t.Error("onDisableLogTail should not be called when DisableLogTail is false")
+ }
+ })
+}