mirror of
				https://github.com/tailscale/tailscale.git
				synced 2025-10-31 08:11:32 +01:00 
			
		
		
		
	This is step 1 of ~3, breaking up #14720 into reviewable chunks, with the aim to make syspolicy be a build-time configurable feature. In this first (very noisy) step, all the syspolicy string key constants move to a new constant-only (code-free) package. This will make future steps more reviewable, without this movement noise. There are no code or behavior changes here. The future steps of this series can be seen in #14720: removing global funcs from syspolicy resolution and using an interface that's plumbed around instead. Then adding build tags. Updates #12614 Change-Id: If73bf2c28b9c9b1a408fe868b0b6a25b03eeabd1 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
		
			
				
	
	
		
			425 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			425 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright (c) Tailscale Inc & AUTHORS
 | |
| // SPDX-License-Identifier: BSD-3-Clause
 | |
| 
 | |
| package metrics
 | |
| 
 | |
| import (
 | |
| 	"errors"
 | |
| 	"testing"
 | |
| 
 | |
| 	"tailscale.com/types/lazy"
 | |
| 	"tailscale.com/util/clientmetric"
 | |
| 	"tailscale.com/util/syspolicy/internal"
 | |
| 	"tailscale.com/util/syspolicy/pkey"
 | |
| 	"tailscale.com/util/syspolicy/setting"
 | |
| )
 | |
| 
 | |
| func TestSettingMetricNames(t *testing.T) {
 | |
| 	tests := []struct {
 | |
| 		name           string
 | |
| 		key            pkey.Key
 | |
| 		scope          setting.Scope
 | |
| 		suffix         string
 | |
| 		typ            clientmetric.Type
 | |
| 		osOverride     string
 | |
| 		wantMetricName string
 | |
| 	}{
 | |
| 		{
 | |
| 			name:           "windows-device-no-suffix",
 | |
| 			key:            "AdminConsole",
 | |
| 			scope:          setting.DeviceSetting,
 | |
| 			suffix:         "",
 | |
| 			typ:            clientmetric.TypeCounter,
 | |
| 			osOverride:     "windows",
 | |
| 			wantMetricName: "windows_syspolicy_AdminConsole",
 | |
| 		},
 | |
| 		{
 | |
| 			name:           "windows-user-no-suffix",
 | |
| 			key:            "AdminConsole",
 | |
| 			scope:          setting.UserSetting,
 | |
| 			suffix:         "",
 | |
| 			typ:            clientmetric.TypeCounter,
 | |
| 			osOverride:     "windows",
 | |
| 			wantMetricName: "windows_syspolicy_AdminConsole_user",
 | |
| 		},
 | |
| 		{
 | |
| 			name:           "windows-profile-no-suffix",
 | |
| 			key:            "AdminConsole",
 | |
| 			scope:          setting.ProfileSetting,
 | |
| 			suffix:         "",
 | |
| 			typ:            clientmetric.TypeCounter,
 | |
| 			osOverride:     "windows",
 | |
| 			wantMetricName: "windows_syspolicy_AdminConsole_profile",
 | |
| 		},
 | |
| 		{
 | |
| 			name:           "windows-profile-err",
 | |
| 			key:            "AdminConsole",
 | |
| 			scope:          setting.ProfileSetting,
 | |
| 			suffix:         "error",
 | |
| 			typ:            clientmetric.TypeCounter,
 | |
| 			osOverride:     "windows",
 | |
| 			wantMetricName: "windows_syspolicy_AdminConsole_profile_error",
 | |
| 		},
 | |
| 		{
 | |
| 			name:           "android-device-no-suffix",
 | |
| 			key:            "AdminConsole",
 | |
| 			scope:          setting.DeviceSetting,
 | |
| 			suffix:         "",
 | |
| 			typ:            clientmetric.TypeCounter,
 | |
| 			osOverride:     "android",
 | |
| 			wantMetricName: "android_syspolicy_AdminConsole",
 | |
| 		},
 | |
| 		{
 | |
| 			name:           "key-path",
 | |
| 			key:            "category/subcategory/setting",
 | |
| 			scope:          setting.DeviceSetting,
 | |
| 			suffix:         "",
 | |
| 			typ:            clientmetric.TypeCounter,
 | |
| 			osOverride:     "fakeos",
 | |
| 			wantMetricName: "fakeos_syspolicy_category_subcategory_setting",
 | |
| 		},
 | |
| 	}
 | |
| 	for _, tt := range tests {
 | |
| 		t.Run(tt.name, func(t *testing.T) {
 | |
| 			internal.OSForTesting.SetForTest(t, tt.osOverride, nil)
 | |
| 			metric, ok := newSettingMetric(tt.key, tt.scope, tt.suffix, tt.typ).(*funcMetric)
 | |
| 			if !ok {
 | |
| 				t.Fatal("metric is not a funcMetric")
 | |
| 			}
 | |
| 			if metric.name != tt.wantMetricName {
 | |
| 				t.Errorf("got %q, want %q", metric.name, tt.wantMetricName)
 | |
| 			}
 | |
| 		})
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestScopeMetrics(t *testing.T) {
 | |
| 	tests := []struct {
 | |
| 		name               string
 | |
| 		scope              setting.Scope
 | |
| 		osOverride         string
 | |
| 		wantHasAnyName     string
 | |
| 		wantNumErroredName string
 | |
| 		wantHasAnyType     clientmetric.Type
 | |
| 		wantNumErroredType clientmetric.Type
 | |
| 	}{
 | |
| 		{
 | |
| 			name:               "windows-device",
 | |
| 			scope:              setting.DeviceSetting,
 | |
| 			osOverride:         "windows",
 | |
| 			wantHasAnyName:     "windows_syspolicy_any",
 | |
| 			wantHasAnyType:     clientmetric.TypeGauge,
 | |
| 			wantNumErroredName: "windows_syspolicy_errors",
 | |
| 			wantNumErroredType: clientmetric.TypeCounter,
 | |
| 		},
 | |
| 		{
 | |
| 			name:               "windows-profile",
 | |
| 			scope:              setting.ProfileSetting,
 | |
| 			osOverride:         "windows",
 | |
| 			wantHasAnyName:     "windows_syspolicy_profile_any",
 | |
| 			wantHasAnyType:     clientmetric.TypeGauge,
 | |
| 			wantNumErroredName: "windows_syspolicy_profile_errors",
 | |
| 			wantNumErroredType: clientmetric.TypeCounter,
 | |
| 		},
 | |
| 		{
 | |
| 			name:               "windows-user",
 | |
| 			scope:              setting.UserSetting,
 | |
| 			osOverride:         "windows",
 | |
| 			wantHasAnyName:     "windows_syspolicy_user_any",
 | |
| 			wantHasAnyType:     clientmetric.TypeGauge,
 | |
| 			wantNumErroredName: "windows_syspolicy_user_errors",
 | |
| 			wantNumErroredType: clientmetric.TypeCounter,
 | |
| 		},
 | |
| 		{
 | |
| 			name:               "android-device",
 | |
| 			scope:              setting.DeviceSetting,
 | |
| 			osOverride:         "android",
 | |
| 			wantHasAnyName:     "android_syspolicy_any",
 | |
| 			wantHasAnyType:     clientmetric.TypeGauge,
 | |
| 			wantNumErroredName: "android_syspolicy_errors",
 | |
| 			wantNumErroredType: clientmetric.TypeCounter,
 | |
| 		},
 | |
| 	}
 | |
| 	for _, tt := range tests {
 | |
| 		t.Run(tt.name, func(t *testing.T) {
 | |
| 			internal.OSForTesting.SetForTest(t, tt.osOverride, nil)
 | |
| 			metrics := newScopeMetrics(tt.scope)
 | |
| 			hasAny, ok := metrics.hasAny.(*funcMetric)
 | |
| 			if !ok {
 | |
| 				t.Fatal("hasAny is not a funcMetric")
 | |
| 			}
 | |
| 			numErrored, ok := metrics.numErrored.(*funcMetric)
 | |
| 			if !ok {
 | |
| 				t.Fatal("numErrored is not a funcMetric")
 | |
| 			}
 | |
| 			if hasAny.name != tt.wantHasAnyName {
 | |
| 				t.Errorf("hasAny.Name: got %q, want %q", hasAny.name, tt.wantHasAnyName)
 | |
| 			}
 | |
| 			if hasAny.typ != tt.wantHasAnyType {
 | |
| 				t.Errorf("hasAny.Type: got %q, want %q", hasAny.typ, tt.wantHasAnyType)
 | |
| 			}
 | |
| 			if numErrored.name != tt.wantNumErroredName {
 | |
| 				t.Errorf("numErrored.Name: got %q, want %q", numErrored.name, tt.wantNumErroredName)
 | |
| 			}
 | |
| 			if numErrored.typ != tt.wantNumErroredType {
 | |
| 				t.Errorf("hasAny.Type: got %q, want %q", numErrored.typ, tt.wantNumErroredType)
 | |
| 			}
 | |
| 		})
 | |
| 	}
 | |
| }
 | |
| 
 | |
| type testSettingDetails struct {
 | |
| 	definition *setting.Definition
 | |
| 	origin     *setting.Origin
 | |
| 	value      any
 | |
| 	err        error
 | |
| }
 | |
| 
 | |
| func TestReportMetrics(t *testing.T) {
 | |
| 	tests := []struct {
 | |
| 		name             string
 | |
| 		osOverride       string
 | |
| 		useMetrics       bool
 | |
| 		settings         []testSettingDetails
 | |
| 		wantMetrics      []TestState
 | |
| 		wantResetMetrics []TestState
 | |
| 	}{
 | |
| 		{
 | |
| 			name:        "none",
 | |
| 			osOverride:  "windows",
 | |
| 			settings:    []testSettingDetails{},
 | |
| 			wantMetrics: []TestState{},
 | |
| 		},
 | |
| 		{
 | |
| 			name:       "single-value",
 | |
| 			osOverride: "windows",
 | |
| 			settings: []testSettingDetails{
 | |
| 				{
 | |
| 					definition: setting.NewDefinition("TestSetting01", setting.DeviceSetting, setting.IntegerValue),
 | |
| 					origin:     setting.NewOrigin(setting.DeviceScope),
 | |
| 					value:      42,
 | |
| 				},
 | |
| 			},
 | |
| 			wantMetrics: []TestState{
 | |
| 				{"windows_syspolicy_any", 1},
 | |
| 				{"windows_syspolicy_TestSetting01", 1},
 | |
| 			},
 | |
| 			wantResetMetrics: []TestState{
 | |
| 				{"windows_syspolicy_any", 0},
 | |
| 				{"windows_syspolicy_TestSetting01", 0},
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name:       "single-error",
 | |
| 			osOverride: "windows",
 | |
| 			settings: []testSettingDetails{
 | |
| 				{
 | |
| 					definition: setting.NewDefinition("TestSetting02", setting.DeviceSetting, setting.IntegerValue),
 | |
| 					origin:     setting.NewOrigin(setting.DeviceScope),
 | |
| 					err:        errors.New("bang!"),
 | |
| 				},
 | |
| 			},
 | |
| 			wantMetrics: []TestState{
 | |
| 				{"windows_syspolicy_errors", 1},
 | |
| 				{"windows_syspolicy_TestSetting02_error", 1},
 | |
| 			},
 | |
| 			wantResetMetrics: []TestState{
 | |
| 				{"windows_syspolicy_errors", 1},
 | |
| 				{"windows_syspolicy_TestSetting02_error", 0},
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name:       "value-and-error",
 | |
| 			osOverride: "windows",
 | |
| 			settings: []testSettingDetails{
 | |
| 				{
 | |
| 					definition: setting.NewDefinition("TestSetting01", setting.DeviceSetting, setting.IntegerValue),
 | |
| 					origin:     setting.NewOrigin(setting.DeviceScope),
 | |
| 					value:      42,
 | |
| 				},
 | |
| 				{
 | |
| 					definition: setting.NewDefinition("TestSetting02", setting.DeviceSetting, setting.IntegerValue),
 | |
| 					origin:     setting.NewOrigin(setting.DeviceScope),
 | |
| 					err:        errors.New("bang!"),
 | |
| 				},
 | |
| 			},
 | |
| 
 | |
| 			wantMetrics: []TestState{
 | |
| 				{"windows_syspolicy_any", 1},
 | |
| 				{"windows_syspolicy_errors", 1},
 | |
| 				{"windows_syspolicy_TestSetting01", 1},
 | |
| 				{"windows_syspolicy_TestSetting02_error", 1},
 | |
| 			},
 | |
| 			wantResetMetrics: []TestState{
 | |
| 				{"windows_syspolicy_any", 0},
 | |
| 				{"windows_syspolicy_errors", 1},
 | |
| 				{"windows_syspolicy_TestSetting01", 0},
 | |
| 				{"windows_syspolicy_TestSetting02_error", 0},
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name:       "two-values",
 | |
| 			osOverride: "windows",
 | |
| 			settings: []testSettingDetails{
 | |
| 				{
 | |
| 					definition: setting.NewDefinition("TestSetting01", setting.DeviceSetting, setting.IntegerValue),
 | |
| 					origin:     setting.NewOrigin(setting.DeviceScope),
 | |
| 					value:      42,
 | |
| 				},
 | |
| 				{
 | |
| 					definition: setting.NewDefinition("TestSetting02", setting.DeviceSetting, setting.IntegerValue),
 | |
| 					origin:     setting.NewOrigin(setting.DeviceScope),
 | |
| 					value:      17,
 | |
| 				},
 | |
| 			},
 | |
| 			wantMetrics: []TestState{
 | |
| 				{"windows_syspolicy_any", 1},
 | |
| 				{"windows_syspolicy_TestSetting01", 1},
 | |
| 				{"windows_syspolicy_TestSetting02", 1},
 | |
| 			},
 | |
| 			wantResetMetrics: []TestState{
 | |
| 				{"windows_syspolicy_any", 0},
 | |
| 				{"windows_syspolicy_TestSetting01", 0},
 | |
| 				{"windows_syspolicy_TestSetting02", 0},
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name:       "two-errors",
 | |
| 			osOverride: "windows",
 | |
| 			settings: []testSettingDetails{
 | |
| 				{
 | |
| 					definition: setting.NewDefinition("TestSetting01", setting.DeviceSetting, setting.IntegerValue),
 | |
| 					origin:     setting.NewOrigin(setting.DeviceScope),
 | |
| 					err:        errors.New("bang!"),
 | |
| 				},
 | |
| 				{
 | |
| 					definition: setting.NewDefinition("TestSetting02", setting.DeviceSetting, setting.IntegerValue),
 | |
| 					origin:     setting.NewOrigin(setting.DeviceScope),
 | |
| 					err:        errors.New("bang!"),
 | |
| 				},
 | |
| 			},
 | |
| 			wantMetrics: []TestState{
 | |
| 				{"windows_syspolicy_errors", 2},
 | |
| 				{"windows_syspolicy_TestSetting01_error", 1},
 | |
| 				{"windows_syspolicy_TestSetting02_error", 1},
 | |
| 			},
 | |
| 			wantResetMetrics: []TestState{
 | |
| 				{"windows_syspolicy_errors", 2},
 | |
| 				{"windows_syspolicy_TestSetting01_error", 0},
 | |
| 				{"windows_syspolicy_TestSetting02_error", 0},
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name:       "multi-scope",
 | |
| 			osOverride: "windows",
 | |
| 			settings: []testSettingDetails{
 | |
| 				{
 | |
| 					definition: setting.NewDefinition("TestSetting01", setting.ProfileSetting, setting.IntegerValue),
 | |
| 					origin:     setting.NewOrigin(setting.DeviceScope),
 | |
| 					value:      42,
 | |
| 				},
 | |
| 				{
 | |
| 					definition: setting.NewDefinition("TestSetting02", setting.ProfileSetting, setting.IntegerValue),
 | |
| 					origin:     setting.NewOrigin(setting.CurrentProfileScope),
 | |
| 					err:        errors.New("bang!"),
 | |
| 				},
 | |
| 				{
 | |
| 					definition: setting.NewDefinition("TestSetting03", setting.UserSetting, setting.IntegerValue),
 | |
| 					origin:     setting.NewOrigin(setting.CurrentUserScope),
 | |
| 					value:      17,
 | |
| 				},
 | |
| 			},
 | |
| 			wantMetrics: []TestState{
 | |
| 				{"windows_syspolicy_any", 1},
 | |
| 				{"windows_syspolicy_profile_errors", 1},
 | |
| 				{"windows_syspolicy_user_any", 1},
 | |
| 				{"windows_syspolicy_TestSetting01", 1},
 | |
| 				{"windows_syspolicy_TestSetting02_profile_error", 1},
 | |
| 				{"windows_syspolicy_TestSetting03_user", 1},
 | |
| 			},
 | |
| 			wantResetMetrics: []TestState{
 | |
| 				{"windows_syspolicy_any", 0},
 | |
| 				{"windows_syspolicy_profile_errors", 1},
 | |
| 				{"windows_syspolicy_user_any", 0},
 | |
| 				{"windows_syspolicy_TestSetting01", 0},
 | |
| 				{"windows_syspolicy_TestSetting02_profile_error", 0},
 | |
| 				{"windows_syspolicy_TestSetting03_user", 0},
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name:       "report-metrics-on-android",
 | |
| 			osOverride: "android",
 | |
| 			settings: []testSettingDetails{
 | |
| 				{
 | |
| 					definition: setting.NewDefinition("TestSetting01", setting.DeviceSetting, setting.IntegerValue),
 | |
| 					origin:     setting.NewOrigin(setting.DeviceScope),
 | |
| 					value:      42,
 | |
| 				},
 | |
| 			},
 | |
| 			wantMetrics: []TestState{
 | |
| 				{"android_syspolicy_any", 1},
 | |
| 				{"android_syspolicy_TestSetting01", 1},
 | |
| 			},
 | |
| 			wantResetMetrics: []TestState{
 | |
| 				{"android_syspolicy_any", 0},
 | |
| 				{"android_syspolicy_TestSetting01", 0},
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name:       "do-not-report-metrics-on-macos",
 | |
| 			osOverride: "macos",
 | |
| 			settings: []testSettingDetails{
 | |
| 				{
 | |
| 					definition: setting.NewDefinition("TestSetting01", setting.DeviceSetting, setting.IntegerValue),
 | |
| 					origin:     setting.NewOrigin(setting.DeviceScope),
 | |
| 					value:      42,
 | |
| 				},
 | |
| 			},
 | |
| 
 | |
| 			wantMetrics: []TestState{}, // none reported
 | |
| 		},
 | |
| 		{
 | |
| 			name:       "do-not-report-metrics-on-ios",
 | |
| 			osOverride: "ios",
 | |
| 			settings: []testSettingDetails{
 | |
| 				{
 | |
| 					definition: setting.NewDefinition("TestSetting01", setting.DeviceSetting, setting.IntegerValue),
 | |
| 					origin:     setting.NewOrigin(setting.DeviceScope),
 | |
| 					value:      42,
 | |
| 				},
 | |
| 			},
 | |
| 
 | |
| 			wantMetrics: []TestState{}, // none reported
 | |
| 		},
 | |
| 	}
 | |
| 	for _, tt := range tests {
 | |
| 		t.Run(tt.name, func(t *testing.T) {
 | |
| 			// Reset the lazy value so it'll be re-evaluated with the osOverride.
 | |
| 			lazyReportMetrics = lazy.SyncValue[bool]{}
 | |
| 			t.Cleanup(func() {
 | |
| 				// Also reset it during the cleanup.
 | |
| 				lazyReportMetrics = lazy.SyncValue[bool]{}
 | |
| 			})
 | |
| 			internal.OSForTesting.SetForTest(t, tt.osOverride, nil)
 | |
| 
 | |
| 			h := NewTestHandler(t)
 | |
| 			SetHooksForTest(t, h.AddMetric, h.SetMetric)
 | |
| 
 | |
| 			for _, s := range tt.settings {
 | |
| 				if s.err != nil {
 | |
| 					ReportError(s.origin, s.definition, s.err)
 | |
| 				} else {
 | |
| 					ReportConfigured(s.origin, s.definition, s.value)
 | |
| 				}
 | |
| 			}
 | |
| 			h.MustEqual(tt.wantMetrics...)
 | |
| 
 | |
| 			for _, s := range tt.settings {
 | |
| 				Reset(s.origin)
 | |
| 				ReportNotConfigured(s.origin, s.definition)
 | |
| 			}
 | |
| 			h.MustEqual(tt.wantResetMetrics...)
 | |
| 		})
 | |
| 	}
 | |
| }
 |