util/syspolicy/setting: add package that contains types for the next syspolicy PRs
Package setting contains types for defining and representing policy settings. It facilitates the registration of setting definitions using Register and RegisterDefinition, and the retrieval of registered setting definitions via Definitions and DefinitionOf. This package is intended for use primarily within the syspolicy package hierarchy, and added in a preparation for the next PRs. Updates #12687 Signed-off-by: Nick Khyl <nickk@tailscale.com>
This commit is contained in:
@@ -0,0 +1,435 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package setting
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestMergeSnapshots(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
s1, s2 *Snapshot
|
||||
want *Snapshot
|
||||
}{
|
||||
{
|
||||
name: "both-nil",
|
||||
s1: nil,
|
||||
s2: nil,
|
||||
want: NewSnapshot(map[Key]RawItem{}),
|
||||
},
|
||||
{
|
||||
name: "both-empty",
|
||||
s1: NewSnapshot(map[Key]RawItem{}),
|
||||
s2: NewSnapshot(map[Key]RawItem{}),
|
||||
want: NewSnapshot(map[Key]RawItem{}),
|
||||
},
|
||||
{
|
||||
name: "first-nil",
|
||||
s1: nil,
|
||||
s2: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 123},
|
||||
"Setting2": {value: "String"},
|
||||
"Setting3": {value: true},
|
||||
}),
|
||||
want: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 123},
|
||||
"Setting2": {value: "String"},
|
||||
"Setting3": {value: true},
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "first-empty",
|
||||
s1: NewSnapshot(map[Key]RawItem{}),
|
||||
s2: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 123},
|
||||
"Setting2": {value: "String"},
|
||||
"Setting3": {value: false},
|
||||
}),
|
||||
want: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 123},
|
||||
"Setting2": {value: "String"},
|
||||
"Setting3": {value: false},
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "second-nil",
|
||||
s1: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 123},
|
||||
"Setting2": {value: "String"},
|
||||
"Setting3": {value: true},
|
||||
}),
|
||||
s2: nil,
|
||||
want: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 123},
|
||||
"Setting2": {value: "String"},
|
||||
"Setting3": {value: true},
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "second-empty",
|
||||
s1: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 123},
|
||||
"Setting2": {value: "String"},
|
||||
"Setting3": {value: false},
|
||||
}),
|
||||
s2: NewSnapshot(map[Key]RawItem{}),
|
||||
want: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 123},
|
||||
"Setting2": {value: "String"},
|
||||
"Setting3": {value: false},
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "no-conflicts",
|
||||
s1: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 123},
|
||||
"Setting2": {value: "String"},
|
||||
"Setting3": {value: false},
|
||||
}),
|
||||
s2: NewSnapshot(map[Key]RawItem{
|
||||
"Setting4": {value: 2 * time.Hour},
|
||||
"Setting5": {value: VisibleByPolicy},
|
||||
"Setting6": {value: ShowChoiceByPolicy},
|
||||
}),
|
||||
want: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 123},
|
||||
"Setting2": {value: "String"},
|
||||
"Setting3": {value: false},
|
||||
"Setting4": {value: 2 * time.Hour},
|
||||
"Setting5": {value: VisibleByPolicy},
|
||||
"Setting6": {value: ShowChoiceByPolicy},
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "with-conflicts",
|
||||
s1: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 123},
|
||||
"Setting2": {value: "String"},
|
||||
"Setting3": {value: true},
|
||||
}),
|
||||
s2: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 456},
|
||||
"Setting3": {value: false},
|
||||
"Setting4": {value: 2 * time.Hour},
|
||||
}),
|
||||
want: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 456},
|
||||
"Setting2": {value: "String"},
|
||||
"Setting3": {value: false},
|
||||
"Setting4": {value: 2 * time.Hour},
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "with-scope-first-wins",
|
||||
s1: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 123},
|
||||
"Setting2": {value: "String"},
|
||||
"Setting3": {value: true},
|
||||
}, DeviceScope),
|
||||
s2: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 456},
|
||||
"Setting3": {value: false},
|
||||
"Setting4": {value: 2 * time.Hour},
|
||||
}, CurrentUserScope),
|
||||
want: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 123},
|
||||
"Setting2": {value: "String"},
|
||||
"Setting3": {value: true},
|
||||
"Setting4": {value: 2 * time.Hour},
|
||||
}, CurrentUserScope),
|
||||
},
|
||||
{
|
||||
name: "with-scope-second-wins",
|
||||
s1: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 123},
|
||||
"Setting2": {value: "String"},
|
||||
"Setting3": {value: true},
|
||||
}, CurrentUserScope),
|
||||
s2: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 456},
|
||||
"Setting3": {value: false},
|
||||
"Setting4": {value: 2 * time.Hour},
|
||||
}, DeviceScope),
|
||||
want: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 456},
|
||||
"Setting2": {value: "String"},
|
||||
"Setting3": {value: false},
|
||||
"Setting4": {value: 2 * time.Hour},
|
||||
}, CurrentUserScope),
|
||||
},
|
||||
{
|
||||
name: "with-scope-both-empty",
|
||||
s1: NewSnapshot(map[Key]RawItem{}, CurrentUserScope),
|
||||
s2: NewSnapshot(map[Key]RawItem{}, DeviceScope),
|
||||
want: NewSnapshot(map[Key]RawItem{}, CurrentUserScope),
|
||||
},
|
||||
{
|
||||
name: "with-scope-first-empty",
|
||||
s1: NewSnapshot(map[Key]RawItem{}, CurrentUserScope),
|
||||
s2: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 123},
|
||||
"Setting2": {value: "String"},
|
||||
"Setting3": {value: true}},
|
||||
DeviceScope, NewNamedOrigin("TestPolicy", DeviceScope)),
|
||||
want: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 123},
|
||||
"Setting2": {value: "String"},
|
||||
"Setting3": {value: true},
|
||||
}, CurrentUserScope, NewNamedOrigin("TestPolicy", DeviceScope)),
|
||||
},
|
||||
{
|
||||
name: "with-scope-second-empty",
|
||||
s1: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 123},
|
||||
"Setting2": {value: "String"},
|
||||
"Setting3": {value: true},
|
||||
}, CurrentUserScope),
|
||||
s2: NewSnapshot(map[Key]RawItem{}),
|
||||
want: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 123},
|
||||
"Setting2": {value: "String"},
|
||||
"Setting3": {value: true},
|
||||
}, CurrentUserScope),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := MergeSnapshots(tt.s1, tt.s2)
|
||||
if !got.Equal(tt.want) {
|
||||
t.Errorf("got %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSnapshotEqual(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
s1, s2 *Snapshot
|
||||
wantEqual bool
|
||||
wantEqualItems bool
|
||||
}{
|
||||
{
|
||||
name: "nil-nil",
|
||||
s1: nil,
|
||||
s2: nil,
|
||||
wantEqual: true,
|
||||
wantEqualItems: true,
|
||||
},
|
||||
{
|
||||
name: "nil-empty",
|
||||
s1: nil,
|
||||
s2: NewSnapshot(map[Key]RawItem{}),
|
||||
wantEqual: true,
|
||||
wantEqualItems: true,
|
||||
},
|
||||
{
|
||||
name: "empty-nil",
|
||||
s1: NewSnapshot(map[Key]RawItem{}),
|
||||
s2: nil,
|
||||
wantEqual: true,
|
||||
wantEqualItems: true,
|
||||
},
|
||||
{
|
||||
name: "empty-empty",
|
||||
s1: NewSnapshot(map[Key]RawItem{}),
|
||||
s2: NewSnapshot(map[Key]RawItem{}),
|
||||
wantEqual: true,
|
||||
wantEqualItems: true,
|
||||
},
|
||||
{
|
||||
name: "first-nil",
|
||||
s1: nil,
|
||||
s2: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 123},
|
||||
"Setting2": {value: "String"},
|
||||
"Setting3": {value: false},
|
||||
}),
|
||||
wantEqual: false,
|
||||
wantEqualItems: false,
|
||||
},
|
||||
{
|
||||
name: "first-empty",
|
||||
s1: NewSnapshot(map[Key]RawItem{}),
|
||||
s2: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 123},
|
||||
"Setting2": {value: "String"},
|
||||
"Setting3": {value: false},
|
||||
}),
|
||||
wantEqual: false,
|
||||
wantEqualItems: false,
|
||||
},
|
||||
{
|
||||
name: "second-nil",
|
||||
s1: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 123},
|
||||
"Setting2": {value: "String"},
|
||||
"Setting3": {value: true},
|
||||
}),
|
||||
s2: nil,
|
||||
wantEqual: false,
|
||||
wantEqualItems: false,
|
||||
},
|
||||
{
|
||||
name: "second-empty",
|
||||
s1: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 123},
|
||||
"Setting2": {value: "String"},
|
||||
"Setting3": {value: false},
|
||||
}),
|
||||
s2: NewSnapshot(map[Key]RawItem{}),
|
||||
wantEqual: false,
|
||||
wantEqualItems: false,
|
||||
},
|
||||
{
|
||||
name: "same-items-same-order-no-scope",
|
||||
s1: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 123},
|
||||
"Setting2": {value: "String"},
|
||||
"Setting3": {value: false},
|
||||
}),
|
||||
s2: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 123},
|
||||
"Setting2": {value: "String"},
|
||||
"Setting3": {value: false},
|
||||
}),
|
||||
wantEqual: true,
|
||||
wantEqualItems: true,
|
||||
},
|
||||
{
|
||||
name: "same-items-same-order-same-scope",
|
||||
s1: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 123},
|
||||
"Setting2": {value: "String"},
|
||||
"Setting3": {value: false},
|
||||
}, DeviceScope),
|
||||
s2: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 123},
|
||||
"Setting2": {value: "String"},
|
||||
"Setting3": {value: false},
|
||||
}, DeviceScope),
|
||||
wantEqual: true,
|
||||
wantEqualItems: true,
|
||||
},
|
||||
{
|
||||
name: "same-items-different-order-same-scope",
|
||||
s1: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 123},
|
||||
"Setting2": {value: "String"},
|
||||
"Setting3": {value: false},
|
||||
}, DeviceScope),
|
||||
s2: NewSnapshot(map[Key]RawItem{
|
||||
"Setting3": {value: false},
|
||||
"Setting1": {value: 123},
|
||||
"Setting2": {value: "String"},
|
||||
}, DeviceScope),
|
||||
wantEqual: true,
|
||||
wantEqualItems: true,
|
||||
},
|
||||
{
|
||||
name: "same-items-same-order-different-scope",
|
||||
s1: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 123},
|
||||
"Setting2": {value: "String"},
|
||||
"Setting3": {value: false},
|
||||
}, DeviceScope),
|
||||
s2: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 123},
|
||||
"Setting2": {value: "String"},
|
||||
"Setting3": {value: false},
|
||||
}, CurrentUserScope),
|
||||
wantEqual: false,
|
||||
wantEqualItems: true,
|
||||
},
|
||||
{
|
||||
name: "different-items-same-scope",
|
||||
s1: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 123},
|
||||
"Setting2": {value: "String"},
|
||||
"Setting3": {value: false},
|
||||
}, DeviceScope),
|
||||
s2: NewSnapshot(map[Key]RawItem{
|
||||
"Setting4": {value: 2 * time.Hour},
|
||||
"Setting5": {value: VisibleByPolicy},
|
||||
"Setting6": {value: ShowChoiceByPolicy},
|
||||
}, DeviceScope),
|
||||
wantEqual: false,
|
||||
wantEqualItems: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if gotEqual := tt.s1.Equal(tt.s2); gotEqual != tt.wantEqual {
|
||||
t.Errorf("WantEqual: got %v, want %v", gotEqual, tt.wantEqual)
|
||||
}
|
||||
if gotEqualItems := tt.s1.EqualItems(tt.s2); gotEqualItems != tt.wantEqualItems {
|
||||
t.Errorf("WantEqualItems: got %v, want %v", gotEqualItems, tt.wantEqualItems)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSnapshotString(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
snapshot *Snapshot
|
||||
wantString string
|
||||
}{
|
||||
{
|
||||
name: "nil",
|
||||
snapshot: nil,
|
||||
wantString: "{Empty}",
|
||||
},
|
||||
{
|
||||
name: "empty",
|
||||
snapshot: NewSnapshot(nil),
|
||||
wantString: "{Empty}",
|
||||
},
|
||||
{
|
||||
name: "empty-with-scope",
|
||||
snapshot: NewSnapshot(nil, DeviceScope),
|
||||
wantString: "{Empty, Device}",
|
||||
},
|
||||
{
|
||||
name: "empty-with-origin",
|
||||
snapshot: NewSnapshot(nil, NewNamedOrigin("Test Policy", DeviceScope)),
|
||||
wantString: "{Empty, Test Policy (Device)}",
|
||||
},
|
||||
{
|
||||
name: "non-empty",
|
||||
snapshot: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 2 * time.Hour},
|
||||
"Setting2": {value: VisibleByPolicy},
|
||||
"Setting3": {value: ShowChoiceByPolicy},
|
||||
}, NewNamedOrigin("Test Policy", DeviceScope)),
|
||||
wantString: `{Test Policy (Device)}
|
||||
Setting1 = 2h0m0s
|
||||
Setting2 = show
|
||||
Setting3 = user-decides`,
|
||||
},
|
||||
{
|
||||
name: "non-empty-with-item-origin",
|
||||
snapshot: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {value: 42, origin: NewNamedOrigin("Test Policy", DeviceScope)},
|
||||
}),
|
||||
wantString: `Setting1 = 42 - {Test Policy (Device)}`,
|
||||
},
|
||||
{
|
||||
name: "non-empty-with-item-error",
|
||||
snapshot: NewSnapshot(map[Key]RawItem{
|
||||
"Setting1": {err: NewErrorText("bang!")},
|
||||
}),
|
||||
wantString: `Setting1 = Error{"bang!"}`,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if gotString := tt.snapshot.String(); gotString != tt.wantString {
|
||||
t.Errorf("got %v\nwant %v", gotString, tt.wantString)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user