mirror of
https://github.com/tailscale/tailscale.git
synced 2026-05-05 04:06:35 +02:00
cmd/vet: add subtestnames analyzer; fix all existing violations
Add a new vet analyzer that checks t.Run subtest names don't contain characters requiring quoting when re-running via "go test -run". This enforces the style guide rule: don't use spaces or punctuation in subtest names. The analyzer flags: - Direct t.Run calls with string literal names containing spaces, regex metacharacters, quotes, or other problematic characters - Table-driven t.Run(tt.name, ...) calls where tt ranges over a slice/map literal with bad name field values Also fix all 978 existing violations across 81 test files, replacing spaces with hyphens and shortening long sentence-like names to concise hyphenated forms. Updates #19242 Change-Id: Ib0ad96a111bd8e764582d1d4902fe2599454ab65 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
parent
5ba3015b48
commit
0bc6c3b92f
4
.github/workflows/vet.yml
vendored
4
.github/workflows/vet.yml
vendored
@ -36,8 +36,10 @@ jobs:
|
||||
|
||||
- name: Run 'go vet'
|
||||
working-directory: src
|
||||
# Use listpkgs --ignore-3p to skip tempfork/ packages, which
|
||||
# intentionally match upstream and may not follow our style rules.
|
||||
# Must use ./... instead of tailscale.com/... because the latter will
|
||||
# include the v2 go client (tailscale.com/client/tailscale/v2) if it's
|
||||
# a dependency in our go.mod file. Possibly a go vet bug, but avoid
|
||||
# cross-repo vetting for now so we can safely add the dependency.
|
||||
run: ./tool/go vet -vettool=/tmp/vettool ./...
|
||||
run: ./tool/go vet -vettool=/tmp/vettool $(./tool/go run ./tool/listpkgs --ignore-3p ./...)
|
||||
|
||||
@ -13,12 +13,12 @@ func TestEscape(t *testing.T) {
|
||||
name, input, want string
|
||||
}{
|
||||
{
|
||||
name: "no illegal chars",
|
||||
name: "no-illegal-chars",
|
||||
input: "/home/user",
|
||||
want: "/home/user",
|
||||
},
|
||||
{
|
||||
name: "empty string",
|
||||
name: "empty-string",
|
||||
input: "",
|
||||
want: "\"\"",
|
||||
},
|
||||
@ -38,12 +38,12 @@ func TestEscape(t *testing.T) {
|
||||
want: "\"\n\"",
|
||||
},
|
||||
{
|
||||
name: "double quote",
|
||||
name: "double-quote",
|
||||
input: "\"",
|
||||
want: "\"\\\"\"",
|
||||
},
|
||||
{
|
||||
name: "single quote",
|
||||
name: "single-quote",
|
||||
input: "'",
|
||||
want: "\"'\"",
|
||||
},
|
||||
@ -53,12 +53,12 @@ func TestEscape(t *testing.T) {
|
||||
want: "\"\\\\\"",
|
||||
},
|
||||
{
|
||||
name: "greater than",
|
||||
name: "greater-than",
|
||||
input: ">",
|
||||
want: "\">\"",
|
||||
},
|
||||
{
|
||||
name: "less than",
|
||||
name: "less-than",
|
||||
input: "<",
|
||||
want: "\"<\"",
|
||||
},
|
||||
@ -93,7 +93,7 @@ func TestEscape(t *testing.T) {
|
||||
want: "\"*\"",
|
||||
},
|
||||
{
|
||||
name: "question mark",
|
||||
name: "question-mark",
|
||||
input: "?",
|
||||
want: "\"?\"",
|
||||
},
|
||||
@ -103,12 +103,12 @@ func TestEscape(t *testing.T) {
|
||||
want: "\"#\"",
|
||||
},
|
||||
{
|
||||
name: "open paren",
|
||||
name: "open-paren",
|
||||
input: "(",
|
||||
want: "\"(\"",
|
||||
},
|
||||
{
|
||||
name: "close paren",
|
||||
name: "close-paren",
|
||||
input: ")",
|
||||
want: "\")\"",
|
||||
},
|
||||
@ -118,17 +118,17 @@ func TestEscape(t *testing.T) {
|
||||
want: "\"\\`\"",
|
||||
},
|
||||
{
|
||||
name: "char without escape",
|
||||
name: "char-without-escape",
|
||||
input: "/home/user\t",
|
||||
want: "\"/home/user\t\"",
|
||||
},
|
||||
{
|
||||
name: "char with escape",
|
||||
name: "char-with-escape",
|
||||
input: "/home/user\\",
|
||||
want: "\"/home/user\\\\\"",
|
||||
},
|
||||
{
|
||||
name: "all illegal chars",
|
||||
name: "all-illegal-chars",
|
||||
input: "/home/user" + needsEscape,
|
||||
want: "\"/home/user \t\n\\\"'\\\\><~|&;\\$*?#()\\`\"",
|
||||
},
|
||||
|
||||
@ -31,7 +31,7 @@ func TestClientBuildURL(t *testing.T) {
|
||||
want: `http://127.0.0.1:1234/api/v2/tailnet/example%20dot%20com%3Ffoo=bar`,
|
||||
},
|
||||
{
|
||||
desc: "url.Values",
|
||||
desc: "url-Values",
|
||||
elements: []any{"tailnet", "example.com", "acl", url.Values{"details": {"1"}}},
|
||||
want: `http://127.0.0.1:1234/api/v2/tailnet/example.com/acl?details=1`,
|
||||
},
|
||||
@ -71,7 +71,7 @@ func TestClientBuildTailnetURL(t *testing.T) {
|
||||
want: `http://127.0.0.1:1234/api/v2/tailnet/example.com/foo%20bar%3Fbaz=qux`,
|
||||
},
|
||||
{
|
||||
desc: "url.Values",
|
||||
desc: "url-Values",
|
||||
elements: []any{"acl", url.Values{"details": {"1"}}},
|
||||
want: `http://127.0.0.1:1234/api/v2/tailnet/example.com/acl?details=1`,
|
||||
},
|
||||
|
||||
@ -41,37 +41,37 @@ func TestQnapAuthnURL(t *testing.T) {
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "localhost http",
|
||||
name: "localhost-http",
|
||||
in: "http://localhost:8088/",
|
||||
want: "http://localhost:8088/cgi-bin/authLogin.cgi?qtoken=token",
|
||||
},
|
||||
{
|
||||
name: "localhost https",
|
||||
name: "localhost-https",
|
||||
in: "https://localhost:5000/",
|
||||
want: "https://localhost:5000/cgi-bin/authLogin.cgi?qtoken=token",
|
||||
},
|
||||
{
|
||||
name: "IP http",
|
||||
name: "IP-http",
|
||||
in: "http://10.1.20.4:80/",
|
||||
want: "http://10.1.20.4:80/cgi-bin/authLogin.cgi?qtoken=token",
|
||||
},
|
||||
{
|
||||
name: "IP6 https",
|
||||
name: "IP6-https",
|
||||
in: "https://[ff7d:0:1:2::1]/",
|
||||
want: "https://[ff7d:0:1:2::1]/cgi-bin/authLogin.cgi?qtoken=token",
|
||||
},
|
||||
{
|
||||
name: "hostname https",
|
||||
name: "hostname-https",
|
||||
in: "https://qnap.example.com/",
|
||||
want: "https://qnap.example.com/cgi-bin/authLogin.cgi?qtoken=token",
|
||||
},
|
||||
{
|
||||
name: "invalid URL",
|
||||
name: "invalid-URL",
|
||||
in: "This is not a URL, it is a really really really really really really really really really really really really long string to exercise the URL truncation code in the error path.",
|
||||
want: "http://localhost/cgi-bin/authLogin.cgi?qtoken=token",
|
||||
},
|
||||
{
|
||||
name: "err != nil",
|
||||
name: "err-not-nil",
|
||||
in: "http://192.168.0.%31/",
|
||||
want: "http://localhost/cgi-bin/authLogin.cgi?qtoken=token",
|
||||
},
|
||||
@ -1516,47 +1516,47 @@ func TestCSRFProtect(t *testing.T) {
|
||||
wantError bool
|
||||
}{
|
||||
{
|
||||
name: "GET requests with no header are allowed",
|
||||
name: "GET-no-header-allowed", // GET requests with no header are allowed
|
||||
method: "GET",
|
||||
},
|
||||
{
|
||||
name: "POST requests with same-origin are allowed",
|
||||
name: "POST-same-origin-allowed",
|
||||
method: "POST",
|
||||
secFetchSite: "same-origin",
|
||||
},
|
||||
{
|
||||
name: "POST requests with cross-site are not allowed",
|
||||
name: "POST-cross-site-rejected",
|
||||
method: "POST",
|
||||
secFetchSite: "cross-site",
|
||||
wantError: true,
|
||||
},
|
||||
{
|
||||
name: "POST requests with unknown sec-fetch-site values are not allowed",
|
||||
name: "POST-unknown-sec-fetch-site-rejected",
|
||||
method: "POST",
|
||||
secFetchSite: "new-unknown-value",
|
||||
wantError: true,
|
||||
},
|
||||
{
|
||||
name: "POST requests with none are not allowed",
|
||||
name: "POST-sec-fetch-none-rejected",
|
||||
method: "POST",
|
||||
secFetchSite: "none",
|
||||
wantError: true,
|
||||
},
|
||||
{
|
||||
name: "POST requests with no sec-fetch-site header but matching host and origin are allowed",
|
||||
name: "POST-no-sec-fetch-site-matching-host-origin", // no sec-fetch-site header but matching host and origin are allowed
|
||||
method: "POST",
|
||||
host: "example.com",
|
||||
origin: "https://example.com",
|
||||
},
|
||||
{
|
||||
name: "POST requests with no sec-fetch-site and non-matching host and origin are not allowed",
|
||||
name: "POST-no-sec-fetch-site-mismatched-host-origin-rejected",
|
||||
method: "POST",
|
||||
host: "example.com",
|
||||
origin: "https://example.net",
|
||||
wantError: true,
|
||||
},
|
||||
{
|
||||
name: "POST requests with no sec-fetch-site and and origin that matches the override are allowed",
|
||||
name: "POST-no-sec-fetch-site-origin-override-allowed",
|
||||
method: "POST",
|
||||
originOverride: "example.net",
|
||||
host: "internal.example.foo", // Host can be changed by reverse proxies
|
||||
|
||||
@ -148,27 +148,27 @@ func TestUpdateYUMRepoTrack(t *testing.T) {
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "same track",
|
||||
desc: "same-track",
|
||||
before: YUMRepos[StableTrack],
|
||||
track: StableTrack,
|
||||
after: YUMRepos[StableTrack],
|
||||
},
|
||||
{
|
||||
desc: "change track",
|
||||
desc: "change-track",
|
||||
before: YUMRepos[StableTrack],
|
||||
track: UnstableTrack,
|
||||
after: YUMRepos[UnstableTrack],
|
||||
rewrote: true,
|
||||
},
|
||||
{
|
||||
desc: "change track RC",
|
||||
desc: "change-track-RC",
|
||||
before: YUMRepos[StableTrack],
|
||||
track: ReleaseCandidateTrack,
|
||||
after: YUMRepos[ReleaseCandidateTrack],
|
||||
rewrote: true,
|
||||
},
|
||||
{
|
||||
desc: "non-tailscale repo file",
|
||||
desc: "non-tailscale-repo-file",
|
||||
before: YUMRepos["FakeRepo"],
|
||||
track: StableTrack,
|
||||
wantErr: true,
|
||||
@ -215,7 +215,7 @@ func TestParseAlpinePackageVersion(t *testing.T) {
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "valid version",
|
||||
desc: "valid-version",
|
||||
out: `
|
||||
tailscale-1.44.2-r0 description:
|
||||
The easiest, most secure way to use WireGuard and 2FA
|
||||
@ -229,7 +229,7 @@ tailscale-1.44.2-r0 installed size:
|
||||
want: "1.44.2",
|
||||
},
|
||||
{
|
||||
desc: "wrong package output",
|
||||
desc: "wrong-package-output",
|
||||
out: `
|
||||
busybox-1.36.1-r0 description:
|
||||
Size optimized toolbox of many common UNIX utilities
|
||||
@ -243,7 +243,7 @@ busybox-1.36.1-r0 installed size:
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "missing version",
|
||||
desc: "missing-version",
|
||||
out: `
|
||||
tailscale description:
|
||||
The easiest, most secure way to use WireGuard and 2FA
|
||||
@ -257,12 +257,12 @@ tailscale installed size:
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "empty output",
|
||||
desc: "empty-output",
|
||||
out: "",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "multiple versions",
|
||||
desc: "multiple-versions",
|
||||
out: `
|
||||
tailscale-1.54.1-r0 description:
|
||||
The easiest, most secure way to use WireGuard and 2FA
|
||||
@ -322,14 +322,14 @@ func TestCheckOutdatedAlpineRepo(t *testing.T) {
|
||||
track string
|
||||
}{
|
||||
{
|
||||
name: "Up to date",
|
||||
name: "up-to-date",
|
||||
fileContent: "https://dl-cdn.alpinelinux.org/alpine/v3.20/main",
|
||||
latestHTTPVersion: "1.95.3",
|
||||
latestApkVersion: "1.95.3",
|
||||
track: "unstable",
|
||||
},
|
||||
{
|
||||
name: "Behind unstable",
|
||||
name: "behind-unstable",
|
||||
fileContent: "https://dl-cdn.alpinelinux.org/alpine/v3.20/main",
|
||||
latestHTTPVersion: "1.95.4",
|
||||
latestApkVersion: "1.95.3",
|
||||
@ -339,7 +339,7 @@ func TestCheckOutdatedAlpineRepo(t *testing.T) {
|
||||
track: "unstable",
|
||||
},
|
||||
{
|
||||
name: "Behind stable",
|
||||
name: "behind-stable",
|
||||
fileContent: "https://dl-cdn.alpinelinux.org/alpine/v2.40/main",
|
||||
latestHTTPVersion: "1.94.3",
|
||||
latestApkVersion: "1.92.1",
|
||||
@ -349,7 +349,7 @@ func TestCheckOutdatedAlpineRepo(t *testing.T) {
|
||||
track: "stable",
|
||||
},
|
||||
{
|
||||
name: "Nothing in dist file",
|
||||
name: "nothing-in-dist-file",
|
||||
fileContent: "",
|
||||
latestHTTPVersion: "1.94.3",
|
||||
latestApkVersion: "1.92.1",
|
||||
@ -505,14 +505,14 @@ unique=synology_88f6281_213air
|
||||
want: "88f6281",
|
||||
},
|
||||
{
|
||||
desc: "missing unique",
|
||||
desc: "missing-unique",
|
||||
content: `
|
||||
company_title="Synology"
|
||||
`,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "empty unique",
|
||||
desc: "empty-unique",
|
||||
content: `
|
||||
company_title="Synology"
|
||||
unique=
|
||||
@ -520,7 +520,7 @@ unique=
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "empty unique double-quoted",
|
||||
desc: "empty-unique-double-quoted",
|
||||
content: `
|
||||
company_title="Synology"
|
||||
unique=""
|
||||
@ -528,7 +528,7 @@ unique=""
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "empty unique single-quoted",
|
||||
desc: "empty-unique-single-quoted",
|
||||
content: `
|
||||
company_title="Synology"
|
||||
unique=''
|
||||
@ -536,7 +536,7 @@ unique=''
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "malformed unique",
|
||||
desc: "malformed-unique",
|
||||
content: `
|
||||
company_title="Synology"
|
||||
unique="synology_88f6281"
|
||||
@ -544,12 +544,12 @@ unique="synology_88f6281"
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "empty file",
|
||||
desc: "empty-file",
|
||||
content: ``,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "empty lines and comments",
|
||||
desc: "empty-lines-and-comments",
|
||||
content: `
|
||||
|
||||
# In a file named synoinfo? Shocking!
|
||||
@ -613,7 +613,7 @@ func TestUnpackLinuxTarball(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "don't touch unrelated files",
|
||||
desc: "skip-unrelated-files", // don't touch unrelated files
|
||||
before: map[string]string{
|
||||
"tailscale": "v1",
|
||||
"tailscaled": "v1",
|
||||
@ -645,7 +645,7 @@ func TestUnpackLinuxTarball(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "ignore extra tarball files",
|
||||
desc: "ignore-extra-tarball-files",
|
||||
before: map[string]string{
|
||||
"tailscale": "v1",
|
||||
"tailscaled": "v1",
|
||||
@ -661,7 +661,7 @@ func TestUnpackLinuxTarball(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "tarball missing tailscaled",
|
||||
desc: "tarball-missing-tailscaled",
|
||||
before: map[string]string{
|
||||
"tailscale": "v1",
|
||||
"tailscaled": "v1",
|
||||
@ -677,7 +677,7 @@ func TestUnpackLinuxTarball(t *testing.T) {
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "duplicate tailscale binary",
|
||||
desc: "duplicate-tailscale-binary",
|
||||
before: map[string]string{
|
||||
"tailscale": "v1",
|
||||
"tailscaled": "v1",
|
||||
@ -696,7 +696,7 @@ func TestUnpackLinuxTarball(t *testing.T) {
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "empty archive",
|
||||
desc: "empty-archive",
|
||||
before: map[string]string{
|
||||
"tailscale": "v1",
|
||||
"tailscaled": "v1",
|
||||
@ -952,17 +952,18 @@ func TestCleanupOldDownloads(t *testing.T) {
|
||||
|
||||
func TestParseUnraidPluginVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
plgPath string
|
||||
wantVer string
|
||||
wantErr string
|
||||
}{
|
||||
{plgPath: "testdata/tailscale-1.52.0.plg", wantVer: "1.52.0"},
|
||||
{plgPath: "testdata/tailscale-1.54.0.plg", wantVer: "1.54.0"},
|
||||
{plgPath: "testdata/tailscale-nover.plg", wantErr: "version not found in plg file"},
|
||||
{plgPath: "testdata/tailscale-nover-path-mentioned.plg", wantErr: "version not found in plg file"},
|
||||
{name: "v1_52_0", plgPath: "testdata/tailscale-1.52.0.plg", wantVer: "1.52.0"},
|
||||
{name: "v1_54_0", plgPath: "testdata/tailscale-1.54.0.plg", wantVer: "1.54.0"},
|
||||
{name: "nover", plgPath: "testdata/tailscale-nover.plg", wantErr: "version not found in plg file"},
|
||||
{name: "nover-path-mentioned", plgPath: "testdata/tailscale-nover-path-mentioned.plg", wantErr: "version not found in plg file"},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.plgPath, func(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := parseUnraidPluginVersion(tt.plgPath)
|
||||
if got != tt.wantVer {
|
||||
t.Errorf("got version: %q, want %q", got, tt.wantVer)
|
||||
@ -992,7 +993,7 @@ func TestConfirm(t *testing.T) {
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
desc: "on latest stable",
|
||||
desc: "on-latest-stable",
|
||||
fromTrack: StableTrack,
|
||||
toTrack: StableTrack,
|
||||
fromVer: "1.66.0",
|
||||
@ -1000,7 +1001,7 @@ func TestConfirm(t *testing.T) {
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
desc: "stable upgrade",
|
||||
desc: "stable-upgrade",
|
||||
fromTrack: StableTrack,
|
||||
toTrack: StableTrack,
|
||||
fromVer: "1.66.0",
|
||||
@ -1008,7 +1009,7 @@ func TestConfirm(t *testing.T) {
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
desc: "unstable upgrade",
|
||||
desc: "unstable-upgrade",
|
||||
fromTrack: UnstableTrack,
|
||||
toTrack: UnstableTrack,
|
||||
fromVer: "1.67.1",
|
||||
@ -1016,7 +1017,7 @@ func TestConfirm(t *testing.T) {
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
desc: "from stable to unstable",
|
||||
desc: "from-stable-to-unstable",
|
||||
fromTrack: StableTrack,
|
||||
toTrack: UnstableTrack,
|
||||
fromVer: "1.66.0",
|
||||
@ -1024,7 +1025,7 @@ func TestConfirm(t *testing.T) {
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
desc: "from unstable to stable",
|
||||
desc: "from-unstable-to-stable",
|
||||
fromTrack: UnstableTrack,
|
||||
toTrack: StableTrack,
|
||||
fromVer: "1.67.1",
|
||||
@ -1032,7 +1033,7 @@ func TestConfirm(t *testing.T) {
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
desc: "confirm callback rejects",
|
||||
desc: "confirm-callback-rejects",
|
||||
fromTrack: StableTrack,
|
||||
toTrack: StableTrack,
|
||||
fromVer: "1.66.0",
|
||||
@ -1043,7 +1044,7 @@ func TestConfirm(t *testing.T) {
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
desc: "confirm callback allows",
|
||||
desc: "confirm-callback-allows",
|
||||
fromTrack: StableTrack,
|
||||
toTrack: StableTrack,
|
||||
fromVer: "1.66.0",
|
||||
|
||||
@ -30,7 +30,7 @@ func TestDownload(t *testing.T) {
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "missing file",
|
||||
desc: "missing-file",
|
||||
before: func(*testing.T) {},
|
||||
src: "hello",
|
||||
wantErr: true,
|
||||
@ -44,7 +44,7 @@ func TestDownload(t *testing.T) {
|
||||
want: []byte("world"),
|
||||
},
|
||||
{
|
||||
desc: "no signature",
|
||||
desc: "no-signature",
|
||||
before: func(*testing.T) {
|
||||
srv.add("hello", []byte("world"))
|
||||
},
|
||||
@ -52,7 +52,7 @@ func TestDownload(t *testing.T) {
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "bad signature",
|
||||
desc: "bad-signature",
|
||||
before: func(*testing.T) {
|
||||
srv.add("hello", []byte("world"))
|
||||
srv.add("hello.sig", []byte("potato"))
|
||||
@ -61,7 +61,7 @@ func TestDownload(t *testing.T) {
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "signed with untrusted key",
|
||||
desc: "signed-untrusted-key",
|
||||
before: func(t *testing.T) {
|
||||
srv.add("hello", []byte("world"))
|
||||
srv.add("hello.sig", newSigningKeyPair(t).sign([]byte("world")))
|
||||
@ -70,7 +70,7 @@ func TestDownload(t *testing.T) {
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "signed with root key",
|
||||
desc: "signed-with-root-key",
|
||||
before: func(t *testing.T) {
|
||||
srv.add("hello", []byte("world"))
|
||||
srv.add("hello.sig", ed25519.Sign(srv.roots[0].k, []byte("world")))
|
||||
@ -79,7 +79,7 @@ func TestDownload(t *testing.T) {
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "bad signing key signature",
|
||||
desc: "bad-signing-key-signature",
|
||||
before: func(t *testing.T) {
|
||||
srv.add("distsign.pub.sig", []byte("potato"))
|
||||
srv.addSigned("hello", []byte("world"))
|
||||
@ -130,7 +130,7 @@ func TestValidateLocalBinary(t *testing.T) {
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "missing file",
|
||||
desc: "missing-file",
|
||||
before: func(*testing.T) {},
|
||||
src: "hello",
|
||||
wantErr: true,
|
||||
@ -143,7 +143,7 @@ func TestValidateLocalBinary(t *testing.T) {
|
||||
src: "hello",
|
||||
},
|
||||
{
|
||||
desc: "contents changed",
|
||||
desc: "contents-changed",
|
||||
before: func(*testing.T) {
|
||||
srv.addSigned("hello", []byte("new world"))
|
||||
},
|
||||
@ -151,7 +151,7 @@ func TestValidateLocalBinary(t *testing.T) {
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "no signature",
|
||||
desc: "no-signature",
|
||||
before: func(*testing.T) {
|
||||
srv.add("hello", []byte("world"))
|
||||
},
|
||||
@ -159,7 +159,7 @@ func TestValidateLocalBinary(t *testing.T) {
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "bad signature",
|
||||
desc: "bad-signature",
|
||||
before: func(*testing.T) {
|
||||
srv.add("hello", []byte("world"))
|
||||
srv.add("hello.sig", []byte("potato"))
|
||||
@ -168,7 +168,7 @@ func TestValidateLocalBinary(t *testing.T) {
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "signed with untrusted key",
|
||||
desc: "signed-untrusted-key",
|
||||
before: func(t *testing.T) {
|
||||
srv.add("hello", []byte("world"))
|
||||
srv.add("hello.sig", newSigningKeyPair(t).sign([]byte("world")))
|
||||
@ -177,7 +177,7 @@ func TestValidateLocalBinary(t *testing.T) {
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "signed with root key",
|
||||
desc: "signed-with-root-key",
|
||||
before: func(t *testing.T) {
|
||||
srv.add("hello", []byte("world"))
|
||||
srv.add("hello.sig", ed25519.Sign(srv.roots[0].k, []byte("world")))
|
||||
@ -186,7 +186,7 @@ func TestValidateLocalBinary(t *testing.T) {
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "bad signing key signature",
|
||||
desc: "bad-signing-key-signature",
|
||||
before: func(t *testing.T) {
|
||||
srv.add("distsign.pub.sig", []byte("potato"))
|
||||
srv.addSigned("hello", []byte("world"))
|
||||
@ -341,7 +341,7 @@ func TestParseRootKey(t *testing.T) {
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "invalid PEM tag",
|
||||
desc: "invalid-PEM-tag",
|
||||
generate: func() ([]byte, []byte, error) {
|
||||
priv, pub, err := GenerateRootKey()
|
||||
priv = bytes.Replace(priv, []byte("ROOT "), nil, -1)
|
||||
@ -350,7 +350,7 @@ func TestParseRootKey(t *testing.T) {
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "not PEM",
|
||||
desc: "not-PEM",
|
||||
generate: func() ([]byte, []byte, error) { return []byte("s3cr3t"), nil, nil },
|
||||
wantErr: true,
|
||||
},
|
||||
@ -399,7 +399,7 @@ func TestParseSigningKey(t *testing.T) {
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "invalid PEM tag",
|
||||
desc: "invalid-PEM-tag",
|
||||
generate: func() ([]byte, []byte, error) {
|
||||
priv, pub, err := GenerateSigningKey()
|
||||
priv = bytes.Replace(priv, []byte("SIGNING "), nil, -1)
|
||||
@ -408,7 +408,7 @@ func TestParseSigningKey(t *testing.T) {
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "not PEM",
|
||||
desc: "not-PEM",
|
||||
generate: func() ([]byte, []byte, error) { return []byte("s3cr3t"), nil, nil },
|
||||
wantErr: true,
|
||||
},
|
||||
|
||||
@ -31,7 +31,7 @@ func TestSetupKube(t *testing.T) {
|
||||
kc *kubeClient
|
||||
}{
|
||||
{
|
||||
name: "TS_AUTHKEY set, state Secret exists",
|
||||
name: "authkey-set-secret-exists",
|
||||
cfg: &settings{
|
||||
AuthKey: "foo",
|
||||
KubeSecret: "foo",
|
||||
@ -50,7 +50,7 @@ func TestSetupKube(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "TS_AUTHKEY set, state Secret does not exist, we have permissions to create it",
|
||||
name: "authkey-set-secret-missing-can-create",
|
||||
cfg: &settings{
|
||||
AuthKey: "foo",
|
||||
KubeSecret: "foo",
|
||||
@ -69,7 +69,7 @@ func TestSetupKube(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "TS_AUTHKEY set, state Secret does not exist, we do not have permissions to create it",
|
||||
name: "authkey-set-secret-missing-cannot-create",
|
||||
cfg: &settings{
|
||||
AuthKey: "foo",
|
||||
KubeSecret: "foo",
|
||||
@ -89,7 +89,7 @@ func TestSetupKube(t *testing.T) {
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "TS_AUTHKEY set, we encounter a non-404 error when trying to retrieve the state Secret",
|
||||
name: "authkey-set-get-secret-non-404-error",
|
||||
cfg: &settings{
|
||||
AuthKey: "foo",
|
||||
KubeSecret: "foo",
|
||||
@ -109,7 +109,7 @@ func TestSetupKube(t *testing.T) {
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "TS_AUTHKEY set, we encounter a non-404 error when trying to check Secret permissions",
|
||||
name: "authkey-set-check-perms-error",
|
||||
cfg: &settings{
|
||||
AuthKey: "foo",
|
||||
KubeSecret: "foo",
|
||||
@ -127,7 +127,7 @@ func TestSetupKube(t *testing.T) {
|
||||
},
|
||||
{
|
||||
// Interactive login using URL in Pod logs
|
||||
name: "TS_AUTHKEY not set, state Secret does not exist, we have permissions to create it",
|
||||
name: "no-authkey-secret-missing-can-create",
|
||||
cfg: &settings{
|
||||
KubeSecret: "foo",
|
||||
},
|
||||
@ -145,7 +145,7 @@ func TestSetupKube(t *testing.T) {
|
||||
},
|
||||
{
|
||||
// Interactive login using URL in Pod logs
|
||||
name: "TS_AUTHKEY not set, state Secret exists, but does not contain auth key",
|
||||
name: "no-authkey-secret-exists-no-key",
|
||||
cfg: &settings{
|
||||
KubeSecret: "foo",
|
||||
},
|
||||
@ -162,7 +162,7 @@ func TestSetupKube(t *testing.T) {
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "TS_AUTHKEY not set, state Secret contains auth key, we do not have RBAC to patch it",
|
||||
name: "no-authkey-secret-has-key-cannot-patch",
|
||||
cfg: &settings{
|
||||
KubeSecret: "foo",
|
||||
},
|
||||
@ -180,7 +180,7 @@ func TestSetupKube(t *testing.T) {
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "TS_AUTHKEY not set, state Secret contains auth key, we have RBAC to patch it",
|
||||
name: "no-authkey-secret-has-key-can-patch",
|
||||
cfg: &settings{
|
||||
KubeSecret: "foo",
|
||||
},
|
||||
|
||||
@ -89,24 +89,24 @@ type settings struct {
|
||||
|
||||
func configFromEnv() (*settings, error) {
|
||||
cfg := &settings{
|
||||
AuthKey: defaultEnvs([]string{"TS_AUTHKEY", "TS_AUTH_KEY"}, ""),
|
||||
ClientID: defaultEnv("TS_CLIENT_ID", ""),
|
||||
ClientSecret: defaultEnv("TS_CLIENT_SECRET", ""),
|
||||
IDToken: defaultEnv("TS_ID_TOKEN", ""),
|
||||
Audience: defaultEnv("TS_AUDIENCE", ""),
|
||||
Hostname: defaultEnv("TS_HOSTNAME", ""),
|
||||
Routes: defaultEnvStringPointer("TS_ROUTES"),
|
||||
ServeConfigPath: defaultEnv("TS_SERVE_CONFIG", ""),
|
||||
ProxyTargetIP: defaultEnv("TS_DEST_IP", ""),
|
||||
ProxyTargetDNSName: defaultEnv("TS_EXPERIMENTAL_DEST_DNS_NAME", ""),
|
||||
TailnetTargetIP: defaultEnv("TS_TAILNET_TARGET_IP", ""),
|
||||
TailnetTargetFQDN: defaultEnv("TS_TAILNET_TARGET_FQDN", ""),
|
||||
DaemonExtraArgs: defaultEnv("TS_TAILSCALED_EXTRA_ARGS", ""),
|
||||
ExtraArgs: defaultEnv("TS_EXTRA_ARGS", ""),
|
||||
InKubernetes: os.Getenv("KUBERNETES_SERVICE_HOST") != "",
|
||||
UserspaceMode: defaultBool("TS_USERSPACE", true),
|
||||
StateDir: defaultEnv("TS_STATE_DIR", ""),
|
||||
AcceptDNS: defaultEnvBoolPointer("TS_ACCEPT_DNS"),
|
||||
AuthKey: defaultEnvs([]string{"TS_AUTHKEY", "TS_AUTH_KEY"}, ""),
|
||||
ClientID: defaultEnv("TS_CLIENT_ID", ""),
|
||||
ClientSecret: defaultEnv("TS_CLIENT_SECRET", ""),
|
||||
IDToken: defaultEnv("TS_ID_TOKEN", ""),
|
||||
Audience: defaultEnv("TS_AUDIENCE", ""),
|
||||
Hostname: defaultEnv("TS_HOSTNAME", ""),
|
||||
Routes: defaultEnvStringPointer("TS_ROUTES"),
|
||||
ServeConfigPath: defaultEnv("TS_SERVE_CONFIG", ""),
|
||||
ProxyTargetIP: defaultEnv("TS_DEST_IP", ""),
|
||||
ProxyTargetDNSName: defaultEnv("TS_EXPERIMENTAL_DEST_DNS_NAME", ""),
|
||||
TailnetTargetIP: defaultEnv("TS_TAILNET_TARGET_IP", ""),
|
||||
TailnetTargetFQDN: defaultEnv("TS_TAILNET_TARGET_FQDN", ""),
|
||||
DaemonExtraArgs: defaultEnv("TS_TAILSCALED_EXTRA_ARGS", ""),
|
||||
ExtraArgs: defaultEnv("TS_EXTRA_ARGS", ""),
|
||||
InKubernetes: os.Getenv("KUBERNETES_SERVICE_HOST") != "",
|
||||
UserspaceMode: defaultBool("TS_USERSPACE", true),
|
||||
StateDir: defaultEnv("TS_STATE_DIR", ""),
|
||||
AcceptDNS: defaultEnvBoolPointer("TS_ACCEPT_DNS"),
|
||||
KubeSecret: func() string {
|
||||
if os.Getenv("KUBERNETES_SERVICE_HOST") != "" {
|
||||
return defaultEnv("TS_KUBE_SECRET", "tailscale")
|
||||
|
||||
@ -46,30 +46,30 @@ func TestNoContent(t *testing.T) {
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "no challenge",
|
||||
name: "no-challenge",
|
||||
},
|
||||
{
|
||||
name: "valid challenge",
|
||||
name: "valid-challenge",
|
||||
input: "input",
|
||||
want: "response input",
|
||||
},
|
||||
{
|
||||
name: "valid challenge hostname",
|
||||
name: "valid-challenge-hostname",
|
||||
input: "ts_derp99b.tailscale.com",
|
||||
want: "response ts_derp99b.tailscale.com",
|
||||
},
|
||||
{
|
||||
name: "invalid challenge",
|
||||
name: "invalid-challenge",
|
||||
input: "foo\x00bar",
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
name: "whitespace invalid challenge",
|
||||
name: "whitespace-invalid-challenge",
|
||||
input: "foo bar",
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
name: "long challenge",
|
||||
name: "long-challenge",
|
||||
input: strings.Repeat("x", 65),
|
||||
want: "",
|
||||
},
|
||||
|
||||
@ -30,7 +30,7 @@ func TestEmbeddedTypeUnmarshal(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
t.Run("unmarshal gitops type from acl type", func(t *testing.T) {
|
||||
t.Run("unmarshal-gitops-from-acl", func(t *testing.T) {
|
||||
b, _ := json.Marshal(aclTestErr)
|
||||
var e ACLGitopsTestError
|
||||
err := json.Unmarshal(b, &e)
|
||||
@ -41,7 +41,7 @@ func TestEmbeddedTypeUnmarshal(t *testing.T) {
|
||||
t.Fatalf("user heading for 'ACLError' not found in gitops error: %v", e.Error())
|
||||
}
|
||||
})
|
||||
t.Run("unmarshal acl type from gitops type", func(t *testing.T) {
|
||||
t.Run("unmarshal-acl-from-gitops", func(t *testing.T) {
|
||||
b, _ := json.Marshal(gitopsErr)
|
||||
var e tailscale.ACLTestError
|
||||
err := json.Unmarshal(b, &e)
|
||||
|
||||
@ -24,7 +24,7 @@ func TestNameserver(t *testing.T) {
|
||||
wantResp *dns.Msg
|
||||
}{
|
||||
{
|
||||
name: "A record query, record exists",
|
||||
name: "A-record-exists",
|
||||
ip4: map[dnsname.FQDN][]net.IP{dnsname.FQDN("foo.bar.com."): {{1, 2, 3, 4}}},
|
||||
query: &dns.Msg{
|
||||
Question: []dns.Question{{Name: "foo.bar.com", Qtype: dns.TypeA}},
|
||||
@ -46,7 +46,7 @@ func TestNameserver(t *testing.T) {
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "A record query, record does not exist",
|
||||
name: "A-record-not-exists",
|
||||
ip4: map[dnsname.FQDN][]net.IP{dnsname.FQDN("foo.bar.com."): {{1, 2, 3, 4}}},
|
||||
query: &dns.Msg{
|
||||
Question: []dns.Question{{Name: "baz.bar.com", Qtype: dns.TypeA}},
|
||||
@ -64,7 +64,7 @@ func TestNameserver(t *testing.T) {
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "A record query, but the name is not a valid FQDN",
|
||||
name: "A-record-invalid-FQDN",
|
||||
ip4: map[dnsname.FQDN][]net.IP{dnsname.FQDN("foo.bar.com."): {{1, 2, 3, 4}}},
|
||||
query: &dns.Msg{
|
||||
Question: []dns.Question{{Name: "foo..bar.com", Qtype: dns.TypeA}},
|
||||
@ -80,7 +80,7 @@ func TestNameserver(t *testing.T) {
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "AAAA record query, A record exists",
|
||||
name: "AAAA-query-A-record-exists",
|
||||
ip4: map[dnsname.FQDN][]net.IP{dnsname.FQDN("foo.bar.com."): {{1, 2, 3, 4}}},
|
||||
query: &dns.Msg{
|
||||
Question: []dns.Question{{Name: "foo.bar.com", Qtype: dns.TypeAAAA}},
|
||||
@ -97,7 +97,7 @@ func TestNameserver(t *testing.T) {
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "AAAA record query, A record does not exist",
|
||||
name: "AAAA-query-A-record-not-exists",
|
||||
ip4: map[dnsname.FQDN][]net.IP{dnsname.FQDN("foo.bar.com."): {{1, 2, 3, 4}}},
|
||||
query: &dns.Msg{
|
||||
Question: []dns.Question{{Name: "baz.bar.com", Qtype: dns.TypeAAAA}},
|
||||
@ -114,7 +114,7 @@ func TestNameserver(t *testing.T) {
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "AAAA record query with IPv6 record",
|
||||
name: "AAAA-query-ipv6-record",
|
||||
ip6: map[dnsname.FQDN][]net.IP{dnsname.FQDN("foo.bar.com."): {net.ParseIP("2001:db8::1")}},
|
||||
query: &dns.Msg{
|
||||
Question: []dns.Question{{Name: "foo.bar.com", Qtype: dns.TypeAAAA}},
|
||||
@ -136,7 +136,7 @@ func TestNameserver(t *testing.T) {
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "Dual-stack: both A and AAAA records exist",
|
||||
name: "dual-stack-A-and-AAAA",
|
||||
ip4: map[dnsname.FQDN][]net.IP{dnsname.FQDN("dual.bar.com."): {{10, 0, 0, 1}}},
|
||||
ip6: map[dnsname.FQDN][]net.IP{dnsname.FQDN("dual.bar.com."): {net.ParseIP("2001:db8::1")}},
|
||||
query: &dns.Msg{
|
||||
@ -157,7 +157,7 @@ func TestNameserver(t *testing.T) {
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "CNAME record query",
|
||||
name: "CNAME-query",
|
||||
ip4: map[dnsname.FQDN][]net.IP{dnsname.FQDN("foo.bar.com."): {{1, 2, 3, 4}}},
|
||||
query: &dns.Msg{
|
||||
Question: []dns.Question{{Name: "foo.bar.com", Qtype: dns.TypeCNAME}},
|
||||
@ -200,20 +200,20 @@ func TestResetRecords(t *testing.T) {
|
||||
wantsErr bool
|
||||
}{
|
||||
{
|
||||
name: "previously empty nameserver.ip4 gets set",
|
||||
name: "previously-empty-nameserver-ip4-gets-set",
|
||||
config: []byte(`{"version": "v1alpha1", "ip4": {"foo.bar.com": ["1.2.3.4"]}}`),
|
||||
wantsIp4: map[dnsname.FQDN][]net.IP{"foo.bar.com.": {{1, 2, 3, 4}}},
|
||||
wantsIp6: make(map[dnsname.FQDN][]net.IP),
|
||||
},
|
||||
{
|
||||
name: "nameserver.ip4 gets reset",
|
||||
name: "nameserver-ip4-gets-reset",
|
||||
hasIp4: map[dnsname.FQDN][]net.IP{"baz.bar.com.": {{1, 1, 3, 3}}},
|
||||
config: []byte(`{"version": "v1alpha1", "ip4": {"foo.bar.com": ["1.2.3.4"]}}`),
|
||||
wantsIp4: map[dnsname.FQDN][]net.IP{"foo.bar.com.": {{1, 2, 3, 4}}},
|
||||
wantsIp6: make(map[dnsname.FQDN][]net.IP),
|
||||
},
|
||||
{
|
||||
name: "configuration with incompatible version",
|
||||
name: "configuration-with-incompatible-version",
|
||||
hasIp4: map[dnsname.FQDN][]net.IP{"baz.bar.com.": {{1, 1, 3, 3}}},
|
||||
config: []byte(`{"version": "v1beta1", "ip4": {"foo.bar.com": ["1.2.3.4"]}}`),
|
||||
wantsIp4: map[dnsname.FQDN][]net.IP{"baz.bar.com.": {{1, 1, 3, 3}}},
|
||||
@ -221,26 +221,26 @@ func TestResetRecords(t *testing.T) {
|
||||
wantsErr: true,
|
||||
},
|
||||
{
|
||||
name: "nameserver.ip4 gets reset to empty config when no configuration is provided",
|
||||
name: "nameserver-ip4-gets-reset-to-empty-config-when-no-configuration-is-provided",
|
||||
hasIp4: map[dnsname.FQDN][]net.IP{"baz.bar.com.": {{1, 1, 3, 3}}},
|
||||
wantsIp4: make(map[dnsname.FQDN][]net.IP),
|
||||
wantsIp6: make(map[dnsname.FQDN][]net.IP),
|
||||
},
|
||||
{
|
||||
name: "nameserver.ip4 gets reset to empty config when the provided configuration is empty",
|
||||
name: "nameserver-ip4-gets-reset-to-empty-config-when-the-provided-configuration-is-empty",
|
||||
hasIp4: map[dnsname.FQDN][]net.IP{"baz.bar.com.": {{1, 1, 3, 3}}},
|
||||
config: []byte(`{"version": "v1alpha1", "ip4": {}}`),
|
||||
wantsIp4: make(map[dnsname.FQDN][]net.IP),
|
||||
wantsIp6: make(map[dnsname.FQDN][]net.IP),
|
||||
},
|
||||
{
|
||||
name: "nameserver.ip6 gets set",
|
||||
name: "nameserver-ip6-gets-set",
|
||||
config: []byte(`{"version": "v1alpha1", "ip6": {"foo.bar.com": ["2001:db8::1"]}}`),
|
||||
wantsIp4: make(map[dnsname.FQDN][]net.IP),
|
||||
wantsIp6: map[dnsname.FQDN][]net.IP{"foo.bar.com.": {net.ParseIP("2001:db8::1")}},
|
||||
},
|
||||
{
|
||||
name: "dual-stack configuration",
|
||||
name: "dual-stack-configuration",
|
||||
config: []byte(`{"version": "v1alpha1", "ip4": {"dual.bar.com": ["10.0.0.1"]}, "ip6": {"dual.bar.com": ["2001:db8::1"]}}`),
|
||||
wantsIp4: map[dnsname.FQDN][]net.IP{"dual.bar.com.": {{10, 0, 0, 1}}},
|
||||
wantsIp6: map[dnsname.FQDN][]net.IP{"dual.bar.com.": {net.ParseIP("2001:db8::1")}},
|
||||
|
||||
@ -80,7 +80,7 @@ func TestNameserverReconciler(t *testing.T) {
|
||||
nameserverLabels := nameserverResourceLabels(dnsConfig.Name, tsNamespace)
|
||||
|
||||
wantsDeploy := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "nameserver", Namespace: tsNamespace}, TypeMeta: metav1.TypeMeta{Kind: "Deployment", APIVersion: appsv1.SchemeGroupVersion.Identifier()}}
|
||||
t.Run("deployment has expected fields", func(t *testing.T) {
|
||||
t.Run("deployment-expected-fields", func(t *testing.T) {
|
||||
if err = yaml.Unmarshal(deployYaml, wantsDeploy); err != nil {
|
||||
t.Fatalf("unmarshalling yaml: %v", err)
|
||||
}
|
||||
@ -102,7 +102,7 @@ func TestNameserverReconciler(t *testing.T) {
|
||||
})
|
||||
|
||||
wantsSvc := &corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: "nameserver", Namespace: tsNamespace}, TypeMeta: metav1.TypeMeta{Kind: "Service", APIVersion: corev1.SchemeGroupVersion.Identifier()}}
|
||||
t.Run("service has expected fields", func(t *testing.T) {
|
||||
t.Run("service-expected-fields", func(t *testing.T) {
|
||||
if err = yaml.Unmarshal(svcYaml, wantsSvc); err != nil {
|
||||
t.Fatalf("unmarshalling yaml: %v", err)
|
||||
}
|
||||
@ -113,7 +113,7 @@ func TestNameserverReconciler(t *testing.T) {
|
||||
expectEqual(t, fc, wantsSvc)
|
||||
})
|
||||
|
||||
t.Run("dns config status is set", func(t *testing.T) {
|
||||
t.Run("dns-config-status-set", func(t *testing.T) {
|
||||
// Verify that DNSConfig advertizes the nameserver's Service IP address,
|
||||
// has the ready status condition and tailscale finalizer.
|
||||
mustUpdate(t, fc, "tailscale", "nameserver", func(svc *corev1.Service) {
|
||||
@ -136,7 +136,7 @@ func TestNameserverReconciler(t *testing.T) {
|
||||
expectEqual(t, fc, dnsConfig)
|
||||
})
|
||||
|
||||
t.Run("nameserver image can be updated", func(t *testing.T) {
|
||||
t.Run("nameserver-image-updated", func(t *testing.T) {
|
||||
// Verify that nameserver image gets updated to match DNSConfig spec.
|
||||
mustUpdate(t, fc, "", "test", func(dnsCfg *tsapi.DNSConfig) {
|
||||
dnsCfg.Spec.Nameserver.Image.Tag = "v0.0.2"
|
||||
@ -146,7 +146,7 @@ func TestNameserverReconciler(t *testing.T) {
|
||||
expectEqual(t, fc, wantsDeploy)
|
||||
})
|
||||
|
||||
t.Run("reconciler does not overwrite custom configuration", func(t *testing.T) {
|
||||
t.Run("reconciler-preserves-custom-config", func(t *testing.T) {
|
||||
// Verify that when another actor sets ConfigMap data, it does not get
|
||||
// overwritten by nameserver reconciler.
|
||||
dnsRecords := &operatorutils.Records{Version: "v1alpha1", IP4: map[string][]string{"foo.ts.net": {"1.2.3.4"}}}
|
||||
@ -175,7 +175,7 @@ func TestNameserverReconciler(t *testing.T) {
|
||||
expectEqual(t, fc, wantCm)
|
||||
})
|
||||
|
||||
t.Run("uses default nameserver image", func(t *testing.T) {
|
||||
t.Run("uses-default-nameserver-image", func(t *testing.T) {
|
||||
// Verify that if dnsconfig.spec.nameserver.image.{repo,tag} are unset,
|
||||
// the nameserver image defaults to tailscale/k8s-nameserver:unstable.
|
||||
mustUpdate(t, fc, "", "test", func(dnsCfg *tsapi.DNSConfig) {
|
||||
|
||||
@ -1498,24 +1498,28 @@ func TestProxyFirewallMode(t *testing.T) {
|
||||
|
||||
func Test_isMagicDNSName(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
in string
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "foo-tail4567-ts-net",
|
||||
in: "foo.tail4567.ts.net",
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "foo-tail4567-ts-net-trailing-dot",
|
||||
in: "foo.tail4567.ts.net.",
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "foo-tail4567",
|
||||
in: "foo.tail4567",
|
||||
want: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.in, func(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := isMagicDNSName(tt.in); got != tt.want {
|
||||
t.Errorf("isMagicDNSName(%q) = %v, want %v", tt.in, got, tt.want)
|
||||
}
|
||||
@ -1756,7 +1760,7 @@ func Test_clusterDomainFromResolverConf(t *testing.T) {
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "success- custom domain",
|
||||
name: "success-custom-domain",
|
||||
conf: &resolvconffile.Config{
|
||||
SearchDomains: []dnsname.FQDN{toFQDN(t, "foo.svc.department.org.io"), toFQDN(t, "svc.department.org.io"), toFQDN(t, "department.org.io")},
|
||||
},
|
||||
@ -1764,7 +1768,7 @@ func Test_clusterDomainFromResolverConf(t *testing.T) {
|
||||
want: "department.org.io",
|
||||
},
|
||||
{
|
||||
name: "success- default domain",
|
||||
name: "success-default-domain",
|
||||
conf: &resolvconffile.Config{
|
||||
SearchDomains: []dnsname.FQDN{toFQDN(t, "foo.svc.cluster.local."), toFQDN(t, "svc.cluster.local."), toFQDN(t, "cluster.local.")},
|
||||
},
|
||||
@ -1772,7 +1776,7 @@ func Test_clusterDomainFromResolverConf(t *testing.T) {
|
||||
want: "cluster.local",
|
||||
},
|
||||
{
|
||||
name: "only two search domains found",
|
||||
name: "only-two-search-domains",
|
||||
conf: &resolvconffile.Config{
|
||||
SearchDomains: []dnsname.FQDN{toFQDN(t, "svc.department.org.io"), toFQDN(t, "department.org.io")},
|
||||
},
|
||||
@ -1780,7 +1784,7 @@ func Test_clusterDomainFromResolverConf(t *testing.T) {
|
||||
want: "cluster.local",
|
||||
},
|
||||
{
|
||||
name: "first search domain does not match the expected structure",
|
||||
name: "first-search-domain-mismatch",
|
||||
conf: &resolvconffile.Config{
|
||||
SearchDomains: []dnsname.FQDN{toFQDN(t, "foo.bar.department.org.io"), toFQDN(t, "svc.department.org.io"), toFQDN(t, "some.other.fqdn")},
|
||||
},
|
||||
@ -1788,7 +1792,7 @@ func Test_clusterDomainFromResolverConf(t *testing.T) {
|
||||
want: "cluster.local",
|
||||
},
|
||||
{
|
||||
name: "second search domain does not match the expected structure",
|
||||
name: "second-search-domain-mismatch",
|
||||
conf: &resolvconffile.Config{
|
||||
SearchDomains: []dnsname.FQDN{toFQDN(t, "foo.svc.department.org.io"), toFQDN(t, "foo.department.org.io"), toFQDN(t, "some.other.fqdn")},
|
||||
},
|
||||
@ -1796,7 +1800,7 @@ func Test_clusterDomainFromResolverConf(t *testing.T) {
|
||||
want: "cluster.local",
|
||||
},
|
||||
{
|
||||
name: "third search domain does not match the expected structure",
|
||||
name: "third-search-domain-mismatch",
|
||||
conf: &resolvconffile.Config{
|
||||
SearchDomains: []dnsname.FQDN{toFQDN(t, "foo.svc.department.org.io"), toFQDN(t, "svc.department.org.io"), toFQDN(t, "some.other.fqdn")},
|
||||
},
|
||||
|
||||
@ -324,76 +324,76 @@ func Test_mergeStatefulSetLabelsOrAnnots(t *testing.T) {
|
||||
want map[string]string
|
||||
}{
|
||||
{
|
||||
name: "no custom labels specified and none present in current labels, return current labels",
|
||||
name: "no-custom-labels-none-present",
|
||||
current: map[string]string{kubetypes.LabelManaged: "true", LabelParentName: "foo", LabelParentType: "svc", LabelParentNamespace: "foo"},
|
||||
want: map[string]string{kubetypes.LabelManaged: "true", LabelParentName: "foo", LabelParentType: "svc", LabelParentNamespace: "foo"},
|
||||
managed: tailscaleManagedLabels,
|
||||
},
|
||||
{
|
||||
name: "no custom labels specified, but some present in current labels, return tailscale managed labels only from the current labels",
|
||||
name: "no-custom-labels-some-present",
|
||||
current: map[string]string{"foo": "bar", "something.io/foo": "bar", kubetypes.LabelManaged: "true", LabelParentName: "foo", LabelParentType: "svc", LabelParentNamespace: "foo"},
|
||||
want: map[string]string{kubetypes.LabelManaged: "true", LabelParentName: "foo", LabelParentType: "svc", LabelParentNamespace: "foo"},
|
||||
managed: tailscaleManagedLabels,
|
||||
},
|
||||
{
|
||||
name: "custom labels specified, current labels only contain tailscale managed labels, return a union of both",
|
||||
name: "custom-labels-with-managed-only",
|
||||
current: map[string]string{kubetypes.LabelManaged: "true", LabelParentName: "foo", LabelParentType: "svc", LabelParentNamespace: "foo"},
|
||||
custom: map[string]string{"foo": "bar", "something.io/foo": "bar"},
|
||||
want: map[string]string{"foo": "bar", "something.io/foo": "bar", kubetypes.LabelManaged: "true", LabelParentName: "foo", LabelParentType: "svc", LabelParentNamespace: "foo"},
|
||||
managed: tailscaleManagedLabels,
|
||||
},
|
||||
{
|
||||
name: "custom labels specified, current labels contain tailscale managed labels and custom labels, some of which re not present in the new custom labels, return a union of managed labels and the desired custom labels",
|
||||
name: "custom-labels-stale-removed",
|
||||
current: map[string]string{"foo": "bar", "bar": "baz", "app": "1234", kubetypes.LabelManaged: "true", LabelParentName: "foo", LabelParentType: "svc", LabelParentNamespace: "foo"},
|
||||
custom: map[string]string{"foo": "bar", "something.io/foo": "bar"},
|
||||
want: map[string]string{"foo": "bar", "something.io/foo": "bar", "app": "1234", kubetypes.LabelManaged: "true", LabelParentName: "foo", LabelParentType: "svc", LabelParentNamespace: "foo"},
|
||||
managed: tailscaleManagedLabels,
|
||||
},
|
||||
{
|
||||
name: "no current labels present, return custom labels only",
|
||||
name: "no-current-labels-return-custom",
|
||||
custom: map[string]string{"foo": "bar", "something.io/foo": "bar"},
|
||||
want: map[string]string{"foo": "bar", "something.io/foo": "bar"},
|
||||
managed: tailscaleManagedLabels,
|
||||
},
|
||||
{
|
||||
name: "no current labels present, no custom labels specified, return empty map",
|
||||
name: "no-current-no-custom-return-empty",
|
||||
want: map[string]string{},
|
||||
managed: tailscaleManagedLabels,
|
||||
},
|
||||
{
|
||||
name: "no custom annots specified and none present in current annots, return current annots",
|
||||
name: "no-custom-annots-none-present",
|
||||
current: map[string]string{podAnnotationLastSetClusterIP: "1.2.3.4"},
|
||||
want: map[string]string{podAnnotationLastSetClusterIP: "1.2.3.4"},
|
||||
managed: tailscaleManagedAnnotations,
|
||||
},
|
||||
{
|
||||
name: "no custom annots specified, but some present in current annots, return tailscale managed annots only from the current annots",
|
||||
name: "no-custom-annots-some-present",
|
||||
current: map[string]string{"foo": "bar", "something.io/foo": "bar", podAnnotationLastSetClusterIP: "1.2.3.4"},
|
||||
want: map[string]string{podAnnotationLastSetClusterIP: "1.2.3.4"},
|
||||
managed: tailscaleManagedAnnotations,
|
||||
},
|
||||
{
|
||||
name: "custom annots specified, current annots only contain tailscale managed annots, return a union of both",
|
||||
name: "custom-annots-with-managed-only",
|
||||
current: map[string]string{podAnnotationLastSetClusterIP: "1.2.3.4"},
|
||||
custom: map[string]string{"foo": "bar", "something.io/foo": "bar"},
|
||||
want: map[string]string{"foo": "bar", "something.io/foo": "bar", podAnnotationLastSetClusterIP: "1.2.3.4"},
|
||||
managed: tailscaleManagedAnnotations,
|
||||
},
|
||||
{
|
||||
name: "custom annots specified, current annots contain tailscale managed annots and custom annots, some of which are not present in the new custom annots, return a union of managed annots and the desired custom annots",
|
||||
name: "custom-annots-stale-removed",
|
||||
current: map[string]string{"foo": "bar", "something.io/foo": "bar", podAnnotationLastSetClusterIP: "1.2.3.4"},
|
||||
custom: map[string]string{"something.io/foo": "bar"},
|
||||
want: map[string]string{"something.io/foo": "bar", podAnnotationLastSetClusterIP: "1.2.3.4"},
|
||||
managed: tailscaleManagedAnnotations,
|
||||
},
|
||||
{
|
||||
name: "no current annots present, return custom annots only",
|
||||
name: "no-current-annots-return-custom",
|
||||
custom: map[string]string{"foo": "bar", "something.io/foo": "bar"},
|
||||
want: map[string]string{"foo": "bar", "something.io/foo": "bar"},
|
||||
managed: tailscaleManagedAnnotations,
|
||||
},
|
||||
{
|
||||
name: "no current labels present, no custom labels specified, return empty map",
|
||||
name: "no-current-annots-no-custom-return-empty",
|
||||
want: map[string]string{},
|
||||
managed: tailscaleManagedAnnotations,
|
||||
},
|
||||
|
||||
@ -17,7 +17,7 @@ import (
|
||||
)
|
||||
|
||||
func TestRecorderSpecs(t *testing.T) {
|
||||
t.Run("ensure spec fields are passed through correctly", func(t *testing.T) {
|
||||
t.Run("spec-fields-passthrough", func(t *testing.T) {
|
||||
tsr := &tsapi.Recorder{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test",
|
||||
|
||||
@ -1533,13 +1533,13 @@ func TestParseNLArgs(t *testing.T) {
|
||||
parseDisablements: true,
|
||||
},
|
||||
{
|
||||
name: "key no votes",
|
||||
name: "key-no-votes",
|
||||
input: []string{"nlpub:" + strings.Repeat("00", 32)},
|
||||
parseKeys: true,
|
||||
wantKeys: []tka.Key{{Kind: tka.Key25519, Votes: 1, Public: bytes.Repeat([]byte{0}, 32)}},
|
||||
},
|
||||
{
|
||||
name: "key with votes",
|
||||
name: "key-with-votes",
|
||||
input: []string{"nlpub:" + strings.Repeat("01", 32) + "?5"},
|
||||
parseKeys: true,
|
||||
wantKeys: []tka.Key{{Kind: tka.Key25519, Votes: 5, Public: bytes.Repeat([]byte{1}, 32)}},
|
||||
@ -1551,13 +1551,13 @@ func TestParseNLArgs(t *testing.T) {
|
||||
wantDisablements: [][]byte{bytes.Repeat([]byte{2}, 32), bytes.Repeat([]byte{3}, 32)},
|
||||
},
|
||||
{
|
||||
name: "disablements not allowed",
|
||||
name: "disablements-not-allowed",
|
||||
input: []string{"disablement:" + strings.Repeat("02", 32)},
|
||||
parseKeys: true,
|
||||
wantErr: fmt.Errorf("parsing key 1: key hex string doesn't have expected type prefix tlpub:"),
|
||||
},
|
||||
{
|
||||
name: "keys not allowed",
|
||||
name: "keys-not-allowed",
|
||||
input: []string{"nlpub:" + strings.Repeat("02", 32)},
|
||||
parseDisablements: true,
|
||||
wantErr: fmt.Errorf("parsing argument 1: expected value with \"disablement:\" or \"disablement-secret:\" prefix, got %q", "nlpub:0202020202020202020202020202020202020202020202020202020202020202"),
|
||||
|
||||
@ -76,7 +76,7 @@ users:
|
||||
token: unused`,
|
||||
},
|
||||
{
|
||||
name: "all configs, clusters, users have been deleted",
|
||||
name: "all-configs-clusters-users-deleted",
|
||||
in: `apiVersion: v1
|
||||
clusters: null
|
||||
contexts: null
|
||||
|
||||
@ -30,7 +30,7 @@ func Test_listCerts(t *testing.T) {
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "normal response",
|
||||
name: "normal-response",
|
||||
caller: fakeAPICaller{
|
||||
Data: json.RawMessage(`{
|
||||
"certificates" : [
|
||||
@ -117,12 +117,12 @@ func Test_listCerts(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "call error",
|
||||
name: "call-error",
|
||||
caller: fakeAPICaller{nil, fmt.Errorf("caller failed")},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "payload decode error",
|
||||
name: "payload-decode-error",
|
||||
caller: fakeAPICaller{json.RawMessage("This isn't JSON!"), nil},
|
||||
wantErr: true,
|
||||
},
|
||||
|
||||
@ -14,7 +14,7 @@ import (
|
||||
)
|
||||
|
||||
func TestFilterFormatAndSortExitNodes(t *testing.T) {
|
||||
t.Run("without filter", func(t *testing.T) {
|
||||
t.Run("without-filter", func(t *testing.T) {
|
||||
ps := []*ipnstate.PeerStatus{
|
||||
{
|
||||
HostName: "everest-1",
|
||||
@ -139,7 +139,7 @@ func TestFilterFormatAndSortExitNodes(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("with country filter", func(t *testing.T) {
|
||||
t.Run("with-country-filter", func(t *testing.T) {
|
||||
ps := []*ipnstate.PeerStatus{
|
||||
{
|
||||
HostName: "baker-1",
|
||||
|
||||
@ -1056,49 +1056,49 @@ func TestSrcTypeFromFlags(t *testing.T) {
|
||||
expectedErr bool
|
||||
}{
|
||||
{
|
||||
name: "only http set",
|
||||
name: "only-http-set",
|
||||
env: &serveEnv{http: 80},
|
||||
expectedType: serveTypeHTTP,
|
||||
expectedPort: 80,
|
||||
expectedErr: false,
|
||||
},
|
||||
{
|
||||
name: "only https set",
|
||||
name: "only-https-set",
|
||||
env: &serveEnv{https: 10000},
|
||||
expectedType: serveTypeHTTPS,
|
||||
expectedPort: 10000,
|
||||
expectedErr: false,
|
||||
},
|
||||
{
|
||||
name: "only tcp set",
|
||||
name: "only-tcp-set",
|
||||
env: &serveEnv{tcp: 8000},
|
||||
expectedType: serveTypeTCP,
|
||||
expectedPort: 8000,
|
||||
expectedErr: false,
|
||||
},
|
||||
{
|
||||
name: "only tls-terminated-tcp set",
|
||||
name: "only-tls-terminated-tcp-set",
|
||||
env: &serveEnv{tlsTerminatedTCP: 8080},
|
||||
expectedType: serveTypeTLSTerminatedTCP,
|
||||
expectedPort: 8080,
|
||||
expectedErr: false,
|
||||
},
|
||||
{
|
||||
name: "defaults to https, port 443",
|
||||
name: "defaults-to-https-443",
|
||||
env: &serveEnv{},
|
||||
expectedType: serveTypeHTTPS,
|
||||
expectedPort: 443,
|
||||
expectedErr: false,
|
||||
},
|
||||
{
|
||||
name: "defaults to https, port 443 for service",
|
||||
name: "defaults-to-https-443-for-service",
|
||||
env: &serveEnv{service: "svc:foo"},
|
||||
expectedType: serveTypeHTTPS,
|
||||
expectedPort: 443,
|
||||
expectedErr: false,
|
||||
},
|
||||
{
|
||||
name: "multiple types set",
|
||||
name: "multiple-types-set",
|
||||
env: &serveEnv{http: 80, https: 443},
|
||||
expectedPort: 0,
|
||||
expectedErr: true,
|
||||
@ -1235,19 +1235,20 @@ func TestAcceptSetAppCapsFlag(t *testing.T) {
|
||||
|
||||
func TestCleanURLPath(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
expected string
|
||||
wantErr bool
|
||||
}{
|
||||
{input: "", expected: "/"},
|
||||
{input: "/", expected: "/"},
|
||||
{input: "/foo", expected: "/foo"},
|
||||
{input: "/foo/", expected: "/foo/"},
|
||||
{input: "/../bar", wantErr: true},
|
||||
{name: "empty", input: "", expected: "/"},
|
||||
{name: "slash", input: "/", expected: "/"},
|
||||
{name: "foo", input: "/foo", expected: "/foo"},
|
||||
{name: "foo-trailing-slash", input: "/foo/", expected: "/foo/"},
|
||||
{name: "dotdot-bar", input: "/../bar", wantErr: true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.input, func(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
actual, err := cleanURLPath(tt.input)
|
||||
|
||||
if tt.wantErr == true && err == nil {
|
||||
@ -1275,18 +1276,18 @@ func TestAddServiceToPrefs(t *testing.T) {
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
name: "add service to empty prefs",
|
||||
name: "add-service-to-empty-prefs",
|
||||
svcName: "svc:foo",
|
||||
expected: []string{"svc:foo"},
|
||||
},
|
||||
{
|
||||
name: "add service to existing prefs",
|
||||
name: "add-service-to-existing-prefs",
|
||||
svcName: "svc:bar",
|
||||
startServices: []string{"svc:foo"},
|
||||
expected: []string{"svc:foo", "svc:bar"},
|
||||
},
|
||||
{
|
||||
name: "add existing service to prefs",
|
||||
name: "add-existing-service-to-prefs",
|
||||
svcName: "svc:foo",
|
||||
startServices: []string{"svc:foo"},
|
||||
expected: []string{"svc:foo"},
|
||||
@ -1323,18 +1324,18 @@ func TestRemoveServiceFromPrefs(t *testing.T) {
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
name: "remove service from empty prefs",
|
||||
name: "remove-service-from-empty-prefs",
|
||||
svcName: "svc:foo",
|
||||
expected: []string{},
|
||||
},
|
||||
{
|
||||
name: "remove existing service from prefs",
|
||||
name: "remove-existing-service-from-prefs",
|
||||
svcName: "svc:foo",
|
||||
startServices: []string{"svc:foo"},
|
||||
expected: []string{},
|
||||
},
|
||||
{
|
||||
name: "remove service not in prefs",
|
||||
name: "remove-service-not-in-prefs",
|
||||
svcName: "svc:bar",
|
||||
startServices: []string{"svc:foo"},
|
||||
expected: []string{"svc:foo"},
|
||||
@ -1446,7 +1447,7 @@ func TestMessageForPort(t *testing.T) {
|
||||
}, "\n"),
|
||||
},
|
||||
{
|
||||
name: "serve service http",
|
||||
name: "serve-service-http",
|
||||
subcmd: serve,
|
||||
serveConfig: &ipn.ServeConfig{
|
||||
Services: map[tailcfg.ServiceName]*ipn.ServiceConfig{
|
||||
@ -1490,7 +1491,7 @@ func TestMessageForPort(t *testing.T) {
|
||||
}, "\n"),
|
||||
},
|
||||
{
|
||||
name: "serve service no capmap",
|
||||
name: "serve-service-no-capmap",
|
||||
subcmd: serve,
|
||||
serveConfig: &ipn.ServeConfig{
|
||||
Services: map[tailcfg.ServiceName]*ipn.ServiceConfig{
|
||||
@ -1534,7 +1535,7 @@ func TestMessageForPort(t *testing.T) {
|
||||
}, "\n"),
|
||||
},
|
||||
{
|
||||
name: "serve service https non-default port",
|
||||
name: "serve-service-https-non-default-port",
|
||||
subcmd: serve,
|
||||
serveConfig: &ipn.ServeConfig{
|
||||
Services: map[tailcfg.ServiceName]*ipn.ServiceConfig{
|
||||
@ -1576,7 +1577,7 @@ func TestMessageForPort(t *testing.T) {
|
||||
}, "\n"),
|
||||
},
|
||||
{
|
||||
name: "serve service TCPForward",
|
||||
name: "serve-service-TCPForward",
|
||||
subcmd: serve,
|
||||
serveConfig: &ipn.ServeConfig{
|
||||
Services: map[tailcfg.ServiceName]*ipn.ServiceConfig{
|
||||
@ -1613,7 +1614,7 @@ func TestMessageForPort(t *testing.T) {
|
||||
}, "\n"),
|
||||
},
|
||||
{
|
||||
name: "serve service Tun",
|
||||
name: "serve-service-Tun",
|
||||
subcmd: serve,
|
||||
serveConfig: &ipn.ServeConfig{
|
||||
Services: map[tailcfg.ServiceName]*ipn.ServiceConfig{
|
||||
@ -1790,7 +1791,7 @@ func TestSetServe(t *testing.T) {
|
||||
expectErr bool
|
||||
}{
|
||||
{
|
||||
name: "add new handler",
|
||||
name: "add-new-handler",
|
||||
desc: "add a new http handler to empty config",
|
||||
cfg: &ipn.ServeConfig{},
|
||||
dnsName: "foo.test.ts.net",
|
||||
@ -1810,7 +1811,7 @@ func TestSetServe(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "update http handler",
|
||||
name: "update-http-handler",
|
||||
desc: "update an existing http handler on the same port to same type",
|
||||
cfg: &ipn.ServeConfig{
|
||||
TCP: map[uint16]*ipn.TCPPortHandler{80: {HTTP: true}},
|
||||
@ -1839,7 +1840,7 @@ func TestSetServe(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "update TCP handler",
|
||||
name: "update-TCP-handler",
|
||||
desc: "update an existing TCP handler on the same port to a http handler",
|
||||
cfg: &ipn.ServeConfig{
|
||||
TCP: map[uint16]*ipn.TCPPortHandler{80: {TCPForward: "http://localhost:3000"}},
|
||||
@ -1852,7 +1853,7 @@ func TestSetServe(t *testing.T) {
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "add new service handler",
|
||||
name: "add-new-service-handler",
|
||||
desc: "add a new service TCP handler to empty config",
|
||||
cfg: &ipn.ServeConfig{},
|
||||
|
||||
@ -1869,7 +1870,7 @@ func TestSetServe(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "update service handler",
|
||||
name: "update-service-handler",
|
||||
desc: "update an existing service TCP handler on the same port to same type",
|
||||
cfg: &ipn.ServeConfig{
|
||||
Services: map[tailcfg.ServiceName]*ipn.ServiceConfig{
|
||||
@ -1891,7 +1892,7 @@ func TestSetServe(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "update service handler",
|
||||
name: "update-service-handler",
|
||||
desc: "update an existing service TCP handler on the same port to a http handler",
|
||||
cfg: &ipn.ServeConfig{
|
||||
Services: map[tailcfg.ServiceName]*ipn.ServiceConfig{
|
||||
@ -1908,7 +1909,7 @@ func TestSetServe(t *testing.T) {
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "add new service handler",
|
||||
name: "add-new-service-handler",
|
||||
desc: "add a new service HTTP handler to empty config",
|
||||
cfg: &ipn.ServeConfig{},
|
||||
dnsName: "svc:bar",
|
||||
@ -1932,7 +1933,7 @@ func TestSetServe(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "update existing service handler",
|
||||
name: "update-existing-service-handler",
|
||||
desc: "update an existing service HTTP handler",
|
||||
cfg: &ipn.ServeConfig{
|
||||
Services: map[tailcfg.ServiceName]*ipn.ServiceConfig{
|
||||
@ -1969,7 +1970,7 @@ func TestSetServe(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "add new service handler",
|
||||
name: "add-new-service-handler",
|
||||
desc: "add a new service HTTP handler to existing service config",
|
||||
cfg: &ipn.ServeConfig{
|
||||
Services: map[tailcfg.ServiceName]*ipn.ServiceConfig{
|
||||
@ -2014,7 +2015,7 @@ func TestSetServe(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "add new service mount",
|
||||
name: "add-new-service-mount",
|
||||
desc: "add a new service mount to existing service config",
|
||||
cfg: &ipn.ServeConfig{
|
||||
Services: map[tailcfg.ServiceName]*ipn.ServiceConfig{
|
||||
@ -2054,7 +2055,7 @@ func TestSetServe(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "add new service handler",
|
||||
name: "add-new-service-handler",
|
||||
desc: "add a new service handler in tun mode to empty config",
|
||||
cfg: &ipn.ServeConfig{},
|
||||
dnsName: "svc:bar",
|
||||
@ -2103,7 +2104,7 @@ func TestUnsetServe(t *testing.T) {
|
||||
expectErr bool
|
||||
}{
|
||||
{
|
||||
name: "unset http handler",
|
||||
name: "unset-http-handler",
|
||||
desc: "remove an existing http handler",
|
||||
cfg: &ipn.ServeConfig{
|
||||
TCP: map[uint16]*ipn.TCPPortHandler{
|
||||
@ -2128,7 +2129,7 @@ func TestUnsetServe(t *testing.T) {
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
name: "unset service handler",
|
||||
name: "unset-service-handler",
|
||||
desc: "remove an existing service TCP handler",
|
||||
cfg: &ipn.ServeConfig{
|
||||
Services: map[tailcfg.ServiceName]*ipn.ServiceConfig{
|
||||
@ -2157,7 +2158,7 @@ func TestUnsetServe(t *testing.T) {
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
name: "unset service handler tun",
|
||||
name: "unset-service-handler-tun",
|
||||
desc: "remove an existing service handler in tun mode",
|
||||
cfg: &ipn.ServeConfig{
|
||||
Services: map[tailcfg.ServiceName]*ipn.ServiceConfig{
|
||||
@ -2175,7 +2176,7 @@ func TestUnsetServe(t *testing.T) {
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
name: "unset service handler tcp",
|
||||
name: "unset-service-handler-tcp",
|
||||
desc: "remove an existing service TCP handler",
|
||||
cfg: &ipn.ServeConfig{
|
||||
Services: map[tailcfg.ServiceName]*ipn.ServiceConfig{
|
||||
@ -2196,7 +2197,7 @@ func TestUnsetServe(t *testing.T) {
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
name: "unset http handler not found",
|
||||
name: "unset-http-handler-not-found",
|
||||
desc: "try to remove a non-existing http handler",
|
||||
cfg: &ipn.ServeConfig{
|
||||
TCP: map[uint16]*ipn.TCPPortHandler{
|
||||
@ -2221,7 +2222,7 @@ func TestUnsetServe(t *testing.T) {
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "unset service handler not found",
|
||||
name: "unset-service-handler-not-found",
|
||||
desc: "try to remove a non-existing service TCP handler",
|
||||
|
||||
cfg: &ipn.ServeConfig{
|
||||
@ -2253,7 +2254,7 @@ func TestUnsetServe(t *testing.T) {
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "unset service doesn't exist",
|
||||
name: "unset-service-doesnt-exist",
|
||||
desc: "try to remove a non-existing service's handler",
|
||||
cfg: &ipn.ServeConfig{
|
||||
Services: map[tailcfg.ServiceName]*ipn.ServiceConfig{
|
||||
@ -2273,7 +2274,7 @@ func TestUnsetServe(t *testing.T) {
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "unset tcp while port is in use",
|
||||
name: "unset-tcp-while-port-in-use",
|
||||
desc: "try to remove a TCP handler while the port is used for web",
|
||||
cfg: &ipn.ServeConfig{
|
||||
TCP: map[uint16]*ipn.TCPPortHandler{
|
||||
@ -2297,7 +2298,7 @@ func TestUnsetServe(t *testing.T) {
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "unset service tcp while port is in use",
|
||||
name: "unset-service-tcp-while-port-in-use",
|
||||
desc: "try to remove a service TCP handler while the port is used for web",
|
||||
cfg: &ipn.ServeConfig{
|
||||
Services: map[tailcfg.ServiceName]*ipn.ServiceConfig{
|
||||
|
||||
@ -58,7 +58,7 @@ func TestStateStoreError(t *testing.T) {
|
||||
args.statedir = t.TempDir()
|
||||
args.tunname = "userspace-networking"
|
||||
|
||||
t.Run("new state", func(t *testing.T) {
|
||||
t.Run("new-state", func(t *testing.T) {
|
||||
sys := tsd.NewSystem()
|
||||
sys.NetMon.Set(must.Get(netmon.New(sys.Bus.Get(), t.Logf)))
|
||||
lb, err := getLocalBackend(t.Context(), t.Logf, logID.Public(), sys)
|
||||
@ -70,7 +70,7 @@ func TestStateStoreError(t *testing.T) {
|
||||
t.Errorf("StateStoreHealth is unhealthy on fresh LocalBackend:\n%s", strings.Join(lb.HealthTracker().Strings(), "\n"))
|
||||
}
|
||||
})
|
||||
t.Run("corrupt state", func(t *testing.T) {
|
||||
t.Run("corrupt-state", func(t *testing.T) {
|
||||
sys := tsd.NewSystem()
|
||||
sys.NetMon.Set(must.Get(netmon.New(sys.Bus.Get(), t.Logf)))
|
||||
// Populate the state file with something that will fail to parse to
|
||||
|
||||
@ -137,14 +137,14 @@ func TestFlattenExtraClaims(t *testing.T) {
|
||||
expected map[string]any
|
||||
}{
|
||||
{
|
||||
name: "empty extra claims",
|
||||
name: "empty-extra-claims",
|
||||
input: []capRule{
|
||||
{ExtraClaims: map[string]any{}},
|
||||
},
|
||||
expected: map[string]any{},
|
||||
},
|
||||
{
|
||||
name: "string and number values",
|
||||
name: "string-and-number-values",
|
||||
input: []capRule{
|
||||
{
|
||||
ExtraClaims: map[string]any{
|
||||
@ -159,7 +159,7 @@ func TestFlattenExtraClaims(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "slice of strings and ints",
|
||||
name: "slice-of-strings-and-ints",
|
||||
input: []capRule{
|
||||
{
|
||||
ExtraClaims: map[string]any{
|
||||
@ -172,7 +172,8 @@ func TestFlattenExtraClaims(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "duplicate values deduplicated (slice input)",
|
||||
// duplicate values deduplicated via slice input
|
||||
name: "dedup-slice-input",
|
||||
input: []capRule{
|
||||
{
|
||||
ExtraClaims: map[string]any{
|
||||
@ -190,7 +191,8 @@ func TestFlattenExtraClaims(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ignore unsupported map type, keep valid scalar",
|
||||
// ignore unsupported map type, keep valid scalar
|
||||
name: "ignore-unsupported-map-keep-scalar",
|
||||
input: []capRule{
|
||||
{
|
||||
ExtraClaims: map[string]any{
|
||||
@ -204,7 +206,7 @@ func TestFlattenExtraClaims(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "scalar first, slice second",
|
||||
name: "scalar-first-slice-second",
|
||||
input: []capRule{
|
||||
{ExtraClaims: map[string]any{"foo": "bar"}},
|
||||
{ExtraClaims: map[string]any{"foo": []any{"baz"}}},
|
||||
@ -214,7 +216,7 @@ func TestFlattenExtraClaims(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "conflicting scalar and unsupported map",
|
||||
name: "conflicting-scalar-and-unsupported-map",
|
||||
input: []capRule{
|
||||
{ExtraClaims: map[string]any{"foo": "bar"}},
|
||||
{ExtraClaims: map[string]any{"foo": map[string]any{"bad": "entry"}}},
|
||||
@ -224,7 +226,7 @@ func TestFlattenExtraClaims(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple slices with overlap",
|
||||
name: "multiple-slices-with-overlap",
|
||||
input: []capRule{
|
||||
{ExtraClaims: map[string]any{"roles": []any{"admin", "user"}}},
|
||||
{ExtraClaims: map[string]any{"roles": []any{"admin", "guest"}}},
|
||||
@ -234,7 +236,7 @@ func TestFlattenExtraClaims(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "slice with unsupported values",
|
||||
name: "slice-with-unsupported-values",
|
||||
input: []capRule{
|
||||
{ExtraClaims: map[string]any{
|
||||
"mixed": []any{"ok", 42, map[string]string{"oops": "fail"}},
|
||||
@ -245,7 +247,7 @@ func TestFlattenExtraClaims(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "duplicate scalar value",
|
||||
name: "duplicate-scalar-value",
|
||||
input: []capRule{
|
||||
{ExtraClaims: map[string]any{"env": "prod"}},
|
||||
{ExtraClaims: map[string]any{"env": "prod"}},
|
||||
@ -279,7 +281,7 @@ func TestExtraClaims(t *testing.T) {
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
name: "extra claim",
|
||||
name: "extra-claim",
|
||||
claim: tailscaleClaims{
|
||||
Claims: jwt.Claims{},
|
||||
Nonce: "foobar",
|
||||
@ -312,7 +314,7 @@ func TestExtraClaims(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "duplicate claim distinct values",
|
||||
name: "duplicate-claim-distinct-values",
|
||||
claim: tailscaleClaims{
|
||||
Claims: jwt.Claims{},
|
||||
Nonce: "foobar",
|
||||
@ -350,7 +352,7 @@ func TestExtraClaims(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple extra claims",
|
||||
name: "multiple-extra-claims",
|
||||
claim: tailscaleClaims{
|
||||
Claims: jwt.Claims{},
|
||||
Nonce: "foobar",
|
||||
@ -389,7 +391,7 @@ func TestExtraClaims(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "overwrite claim",
|
||||
name: "overwrite-claim",
|
||||
claim: tailscaleClaims{
|
||||
Claims: jwt.Claims{},
|
||||
Nonce: "foobar",
|
||||
@ -422,7 +424,7 @@ func TestExtraClaims(t *testing.T) {
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "empty extra claims",
|
||||
name: "empty-extra-claims",
|
||||
claim: tailscaleClaims{
|
||||
Claims: jwt.Claims{},
|
||||
Nonce: "foobar",
|
||||
@ -496,21 +498,21 @@ func TestServeToken(t *testing.T) {
|
||||
expected map[string]any
|
||||
}{
|
||||
{
|
||||
name: "GET not allowed",
|
||||
name: "GET-not-allowed",
|
||||
method: "GET",
|
||||
grantType: "authorization_code",
|
||||
strictMode: false,
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "unsupported grant type",
|
||||
name: "unsupported-grant-type",
|
||||
method: "POST",
|
||||
grantType: "pkcs",
|
||||
strictMode: false,
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "invalid code",
|
||||
name: "invalid-code",
|
||||
method: "POST",
|
||||
grantType: "authorization_code",
|
||||
code: "invalid-code",
|
||||
@ -518,7 +520,7 @@ func TestServeToken(t *testing.T) {
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "omit code from form",
|
||||
name: "omit-code-from-form",
|
||||
method: "POST",
|
||||
grantType: "authorization_code",
|
||||
omitCode: true,
|
||||
@ -526,7 +528,7 @@ func TestServeToken(t *testing.T) {
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "invalid redirect uri",
|
||||
name: "invalid-redirect-uri",
|
||||
method: "POST",
|
||||
grantType: "authorization_code",
|
||||
code: "valid-code",
|
||||
@ -536,7 +538,7 @@ func TestServeToken(t *testing.T) {
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "invalid remoteAddr",
|
||||
name: "invalid-remoteAddr",
|
||||
method: "POST",
|
||||
grantType: "authorization_code",
|
||||
redirectURI: "https://rp.example.com/callback",
|
||||
@ -546,7 +548,7 @@ func TestServeToken(t *testing.T) {
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "extra claim included (non-strict)",
|
||||
name: "extra-claim-included-non-strict",
|
||||
method: "POST",
|
||||
grantType: "authorization_code",
|
||||
redirectURI: "https://rp.example.com/callback",
|
||||
@ -568,7 +570,8 @@ func TestServeToken(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "attempt to overwrite protected claim (non-strict)",
|
||||
// attempt to overwrite protected claim in non-strict mode
|
||||
name: "overwrite-protected-claim-non-strict",
|
||||
method: "POST",
|
||||
grantType: "authorization_code",
|
||||
redirectURI: "https://rp.example.com/callback",
|
||||
@ -708,7 +711,7 @@ func TestExtraUserInfo(t *testing.T) {
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
name: "extra claim",
|
||||
name: "extra-claim",
|
||||
tokenValidTill: time.Now().Add(1 * time.Minute),
|
||||
caps: tailcfg.PeerCapMap{
|
||||
tailcfg.PeerCapabilityTsIDP: {
|
||||
@ -725,7 +728,7 @@ func TestExtraUserInfo(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "duplicate claim distinct values",
|
||||
name: "duplicate-claim-distinct-values",
|
||||
tokenValidTill: time.Now().Add(1 * time.Minute),
|
||||
caps: tailcfg.PeerCapMap{
|
||||
tailcfg.PeerCapabilityTsIDP: {
|
||||
@ -742,7 +745,7 @@ func TestExtraUserInfo(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple extra claims",
|
||||
name: "multiple-extra-claims",
|
||||
tokenValidTill: time.Now().Add(1 * time.Minute),
|
||||
caps: tailcfg.PeerCapMap{
|
||||
tailcfg.PeerCapabilityTsIDP: {
|
||||
@ -761,13 +764,13 @@ func TestExtraUserInfo(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty extra claims",
|
||||
name: "empty-extra-claims",
|
||||
caps: tailcfg.PeerCapMap{},
|
||||
tokenValidTill: time.Now().Add(1 * time.Minute),
|
||||
expected: map[string]any{},
|
||||
},
|
||||
{
|
||||
name: "attempt to overwrite protected claim",
|
||||
name: "overwrite-protected-claim",
|
||||
tokenValidTill: time.Now().Add(1 * time.Minute),
|
||||
caps: tailcfg.PeerCapMap{
|
||||
tailcfg.PeerCapabilityTsIDP: {
|
||||
@ -783,7 +786,7 @@ func TestExtraUserInfo(t *testing.T) {
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "extra claim omitted",
|
||||
name: "extra-claim-omitted",
|
||||
tokenValidTill: time.Now().Add(1 * time.Minute),
|
||||
caps: tailcfg.PeerCapMap{
|
||||
tailcfg.PeerCapabilityTsIDP: {
|
||||
@ -798,7 +801,7 @@ func TestExtraUserInfo(t *testing.T) {
|
||||
expected: map[string]any{},
|
||||
},
|
||||
{
|
||||
name: "expired token",
|
||||
name: "expired-token",
|
||||
caps: tailcfg.PeerCapMap{},
|
||||
tokenValidTill: time.Now().Add(-1 * time.Minute),
|
||||
expected: map[string]any{},
|
||||
@ -1131,19 +1134,22 @@ func TestGetAllowInsecureRegistration(t *testing.T) {
|
||||
expectAllowInsecureRegistration bool
|
||||
}{
|
||||
{
|
||||
name: "flag explicitly set to false - insecure registration disabled (strict mode)",
|
||||
// flag explicitly set to false - insecure registration disabled (strict mode)
|
||||
name: "flag-false-insecure-disabled",
|
||||
flagSet: true,
|
||||
flagValue: false,
|
||||
expectAllowInsecureRegistration: false,
|
||||
},
|
||||
{
|
||||
name: "flag explicitly set to true - insecure registration enabled",
|
||||
// flag explicitly set to true - insecure registration enabled
|
||||
name: "flag-true-insecure-enabled",
|
||||
flagSet: true,
|
||||
flagValue: true,
|
||||
expectAllowInsecureRegistration: true,
|
||||
},
|
||||
{
|
||||
name: "flag unset - insecure registration enabled (default for backward compatibility)",
|
||||
// flag unset - insecure registration enabled (default for backward compatibility)
|
||||
name: "flag-unset-insecure-enabled-default",
|
||||
flagSet: false,
|
||||
flagValue: false, // not used when unset
|
||||
expectAllowInsecureRegistration: true,
|
||||
@ -1192,7 +1198,7 @@ func TestMigrateOAuthClients(t *testing.T) {
|
||||
expectOldRenamed bool
|
||||
}{
|
||||
{
|
||||
name: "migrate from old file to new file",
|
||||
name: "migrate-old-to-new",
|
||||
setupOldFile: true,
|
||||
oldFileContent: map[string]*funnelClient{
|
||||
"old-client": {
|
||||
@ -1206,7 +1212,7 @@ func TestMigrateOAuthClients(t *testing.T) {
|
||||
expectOldRenamed: true,
|
||||
},
|
||||
{
|
||||
name: "new file already exists - no migration",
|
||||
name: "new-file-exists-no-migration",
|
||||
setupNewFile: true,
|
||||
newFileContent: map[string]*funnelClient{
|
||||
"existing-client": {
|
||||
@ -1220,12 +1226,12 @@ func TestMigrateOAuthClients(t *testing.T) {
|
||||
expectOldRenamed: false,
|
||||
},
|
||||
{
|
||||
name: "neither file exists - create empty new file",
|
||||
name: "neither-exists-create-empty",
|
||||
expectNewFileExists: true,
|
||||
expectOldRenamed: false,
|
||||
},
|
||||
{
|
||||
name: "both files exist - prefer new file",
|
||||
name: "both-exist-prefer-new",
|
||||
setupOldFile: true,
|
||||
setupNewFile: true,
|
||||
oldFileContent: map[string]*funnelClient{
|
||||
@ -1373,19 +1379,19 @@ func TestGetConfigFilePath(t *testing.T) {
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
name: "file exists in current directory - use current directory",
|
||||
name: "file-in-cwd-use-cwd",
|
||||
fileName: "test-config.json",
|
||||
createInCwd: true,
|
||||
expectInCwd: true,
|
||||
},
|
||||
{
|
||||
name: "file does not exist - use root path",
|
||||
name: "file-missing-use-root",
|
||||
fileName: "test-config.json",
|
||||
createInCwd: false,
|
||||
expectInCwd: false,
|
||||
},
|
||||
{
|
||||
name: "file exists in both - prefer current directory",
|
||||
name: "file-in-both-prefer-cwd",
|
||||
fileName: "test-config.json",
|
||||
createInCwd: true,
|
||||
createInRoot: true,
|
||||
@ -1472,7 +1478,7 @@ func TestAuthorizeStrictMode(t *testing.T) {
|
||||
}{
|
||||
// Security boundary test: funnel rejection
|
||||
{
|
||||
name: "funnel requests are always rejected for security",
|
||||
name: "funnel-rejected",
|
||||
strictMode: true,
|
||||
clientID: "test-client",
|
||||
redirectURI: "https://rp.example.com/callback",
|
||||
@ -1487,7 +1493,7 @@ func TestAuthorizeStrictMode(t *testing.T) {
|
||||
|
||||
// Strict mode parameter validation tests (non-funnel)
|
||||
{
|
||||
name: "strict mode - missing client_id",
|
||||
name: "strict-missing-client_id",
|
||||
strictMode: true,
|
||||
clientID: "",
|
||||
redirectURI: "https://rp.example.com/callback",
|
||||
@ -1496,7 +1502,7 @@ func TestAuthorizeStrictMode(t *testing.T) {
|
||||
expectCode: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
name: "strict mode - missing redirect_uri",
|
||||
name: "strict-missing-redirect_uri",
|
||||
strictMode: true,
|
||||
clientID: "test-client",
|
||||
redirectURI: "",
|
||||
@ -1507,7 +1513,7 @@ func TestAuthorizeStrictMode(t *testing.T) {
|
||||
|
||||
// Strict mode client validation tests (non-funnel)
|
||||
{
|
||||
name: "strict mode - invalid client_id",
|
||||
name: "strict-invalid-client_id",
|
||||
strictMode: true,
|
||||
clientID: "invalid-client",
|
||||
redirectURI: "https://rp.example.com/callback",
|
||||
@ -1517,7 +1523,7 @@ func TestAuthorizeStrictMode(t *testing.T) {
|
||||
expectCode: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
name: "strict mode - redirect_uri mismatch",
|
||||
name: "strict-redirect_uri-mismatch",
|
||||
strictMode: true,
|
||||
clientID: "test-client",
|
||||
redirectURI: "https://wrong.example.com/callback",
|
||||
@ -1666,7 +1672,7 @@ func TestServeTokenWithClientValidation(t *testing.T) {
|
||||
expectIDToken bool
|
||||
}{
|
||||
{
|
||||
name: "strict mode - valid token exchange with form credentials",
|
||||
name: "strict-token-exchange-form-creds",
|
||||
strictMode: true,
|
||||
method: "POST",
|
||||
grantType: "authorization_code",
|
||||
@ -1680,7 +1686,7 @@ func TestServeTokenWithClientValidation(t *testing.T) {
|
||||
expectIDToken: true,
|
||||
},
|
||||
{
|
||||
name: "strict mode - valid token exchange with basic auth",
|
||||
name: "strict-token-exchange-basic-auth",
|
||||
strictMode: true,
|
||||
method: "POST",
|
||||
grantType: "authorization_code",
|
||||
@ -1695,7 +1701,7 @@ func TestServeTokenWithClientValidation(t *testing.T) {
|
||||
expectIDToken: true,
|
||||
},
|
||||
{
|
||||
name: "strict mode - missing client credentials",
|
||||
name: "strict-missing-client-creds",
|
||||
strictMode: true,
|
||||
method: "POST",
|
||||
grantType: "authorization_code",
|
||||
@ -1708,7 +1714,7 @@ func TestServeTokenWithClientValidation(t *testing.T) {
|
||||
expectCode: http.StatusUnauthorized,
|
||||
},
|
||||
{
|
||||
name: "strict mode - client_id mismatch",
|
||||
name: "strict-client_id-mismatch",
|
||||
strictMode: true,
|
||||
method: "POST",
|
||||
grantType: "authorization_code",
|
||||
@ -1722,7 +1728,7 @@ func TestServeTokenWithClientValidation(t *testing.T) {
|
||||
expectCode: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
name: "strict mode - invalid client secret",
|
||||
name: "strict-invalid-client-secret",
|
||||
strictMode: true,
|
||||
method: "POST",
|
||||
grantType: "authorization_code",
|
||||
@ -1737,7 +1743,7 @@ func TestServeTokenWithClientValidation(t *testing.T) {
|
||||
expectCode: http.StatusUnauthorized,
|
||||
},
|
||||
{
|
||||
name: "strict mode - redirect_uri mismatch",
|
||||
name: "strict-redirect_uri-mismatch",
|
||||
strictMode: true,
|
||||
method: "POST",
|
||||
grantType: "authorization_code",
|
||||
@ -1752,7 +1758,7 @@ func TestServeTokenWithClientValidation(t *testing.T) {
|
||||
expectCode: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
name: "non-strict mode - no client validation required",
|
||||
name: "non-strict-no-client-validation",
|
||||
strictMode: false,
|
||||
method: "POST",
|
||||
grantType: "authorization_code",
|
||||
@ -1913,7 +1919,7 @@ func TestServeUserInfoWithClientValidation(t *testing.T) {
|
||||
expectUserInfo bool
|
||||
}{
|
||||
{
|
||||
name: "strict mode - valid token with existing client",
|
||||
name: "strict-valid-token-existing-client",
|
||||
strictMode: true,
|
||||
setupToken: true,
|
||||
setupClient: true,
|
||||
@ -1923,7 +1929,8 @@ func TestServeUserInfoWithClientValidation(t *testing.T) {
|
||||
expectUserInfo: true,
|
||||
},
|
||||
{
|
||||
name: "strict mode - valid token but client no longer exists",
|
||||
// valid token but client no longer exists
|
||||
name: "strict-token-client-deleted",
|
||||
strictMode: true,
|
||||
setupToken: true,
|
||||
setupClient: false,
|
||||
@ -1934,7 +1941,7 @@ func TestServeUserInfoWithClientValidation(t *testing.T) {
|
||||
expectCode: http.StatusUnauthorized,
|
||||
},
|
||||
{
|
||||
name: "strict mode - expired token",
|
||||
name: "strict-expired-token",
|
||||
strictMode: true,
|
||||
setupToken: true,
|
||||
setupClient: true,
|
||||
@ -1945,7 +1952,7 @@ func TestServeUserInfoWithClientValidation(t *testing.T) {
|
||||
expectCode: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
name: "strict mode - invalid token",
|
||||
name: "strict-invalid-token",
|
||||
strictMode: true,
|
||||
setupToken: false,
|
||||
token: "invalid-token",
|
||||
@ -1953,7 +1960,7 @@ func TestServeUserInfoWithClientValidation(t *testing.T) {
|
||||
expectCode: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
name: "strict mode - token without client association",
|
||||
name: "strict-token-no-client-assoc",
|
||||
strictMode: true,
|
||||
setupToken: true,
|
||||
setupClient: false,
|
||||
@ -1964,7 +1971,7 @@ func TestServeUserInfoWithClientValidation(t *testing.T) {
|
||||
expectCode: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
name: "non-strict mode - no client validation required",
|
||||
name: "non-strict-no-client-validation",
|
||||
strictMode: false,
|
||||
setupToken: true,
|
||||
setupClient: false,
|
||||
|
||||
216
cmd/vet/subtestnames/analyzer.go
Normal file
216
cmd/vet/subtestnames/analyzer.go
Normal file
@ -0,0 +1,216 @@
|
||||
// Copyright (c) Tailscale Inc & contributors
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
// Package subtestnames checks that t.Run subtest names don't contain characters
|
||||
// that require quoting or escaping when re-running via "go test -run".
|
||||
//
|
||||
// Go's testing package rewrites subtest names: spaces become underscores,
|
||||
// non-printable characters get escaped, and regex metacharacters require
|
||||
// escaping in -run patterns. This makes it hard to re-run specific subtests
|
||||
// or search for them in code.
|
||||
//
|
||||
// This analyzer flags:
|
||||
// - Direct t.Run calls with string literal names containing bad characters
|
||||
// - t.Run calls using tt.name (or similar) where tt ranges over a slice/map
|
||||
// of test cases with string literal names containing bad characters
|
||||
package subtestnames
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/go/analysis/passes/inspect"
|
||||
"golang.org/x/tools/go/ast/inspector"
|
||||
)
|
||||
|
||||
// Analyzer checks that t.Run subtest names are clean for use with "go test -run".
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "subtestnames",
|
||||
Doc: "check that t.Run subtest names don't require quoting when re-running via go test -run",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
}
|
||||
|
||||
// badChars are characters that are problematic in subtest names.
|
||||
// Spaces are rewritten to underscores by testing.rewrite, and regex
|
||||
// metacharacters require escaping in -run patterns.
|
||||
const badChars = " \t\n\r^$.*+?()[]{}|\\'\"#"
|
||||
|
||||
// hasBadChar reports whether s contains any character that would be
|
||||
// problematic in a subtest name.
|
||||
func hasBadChar(s string) bool {
|
||||
return strings.ContainsAny(s, badChars) || strings.ContainsFunc(s, func(r rune) bool {
|
||||
return !unicode.IsPrint(r)
|
||||
})
|
||||
}
|
||||
|
||||
func run(pass *analysis.Pass) (any, error) {
|
||||
insp := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
|
||||
|
||||
// Build a stack of enclosing nodes so we can find the RangeStmt
|
||||
// enclosing a given t.Run call.
|
||||
nodeFilter := []ast.Node{
|
||||
(*ast.RangeStmt)(nil),
|
||||
(*ast.CallExpr)(nil),
|
||||
}
|
||||
|
||||
var rangeStack []*ast.RangeStmt
|
||||
|
||||
insp.Nodes(nodeFilter, func(n ast.Node, push bool) bool {
|
||||
switch n := n.(type) {
|
||||
case *ast.RangeStmt:
|
||||
if push {
|
||||
rangeStack = append(rangeStack, n)
|
||||
} else {
|
||||
rangeStack = rangeStack[:len(rangeStack)-1]
|
||||
}
|
||||
return true
|
||||
case *ast.CallExpr:
|
||||
if !push {
|
||||
return true
|
||||
}
|
||||
checkCallExpr(pass, n, rangeStack)
|
||||
return true
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func checkCallExpr(pass *analysis.Pass, call *ast.CallExpr, rangeStack []*ast.RangeStmt) {
|
||||
// Check if this is a t.Run(...) or b.Run(...) call.
|
||||
sel, ok := call.Fun.(*ast.SelectorExpr)
|
||||
if !ok || sel.Sel.Name != "Run" || len(call.Args) < 2 {
|
||||
return
|
||||
}
|
||||
|
||||
// Verify the receiver is *testing.T, *testing.B, or *testing.F.
|
||||
if !isTestingTBF(pass, sel) {
|
||||
return
|
||||
}
|
||||
|
||||
nameArg := call.Args[0]
|
||||
|
||||
// Case 1: Direct string literal, e.g. t.Run("foo bar", ...)
|
||||
if lit, ok := nameArg.(*ast.BasicLit); ok && lit.Kind == token.STRING {
|
||||
val, err := strconv.Unquote(lit.Value)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if hasBadChar(val) {
|
||||
pass.Reportf(lit.Pos(), "subtest name %s contains characters that require quoting in go test -run patterns", lit.Value)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Case 2: Selector expression like tt.name, tc.name, etc.
|
||||
// where tt is a range variable over a slice/map of test cases.
|
||||
selExpr, ok := nameArg.(*ast.SelectorExpr)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
ident, ok := selExpr.X.(*ast.Ident)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
// Find the enclosing range statement where ident is the value variable.
|
||||
for i := len(rangeStack) - 1; i >= 0; i-- {
|
||||
rs := rangeStack[i]
|
||||
valIdent, ok := rs.Value.(*ast.Ident)
|
||||
if !ok || valIdent.Obj != ident.Obj {
|
||||
continue
|
||||
}
|
||||
// Found the range statement. Check the source being iterated.
|
||||
checkRangeSource(pass, rs.X, selExpr.Sel)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// isTestingTBF checks whether sel looks like a method call on *testing.T, *testing.B, or *testing.F.
|
||||
func isTestingTBF(pass *analysis.Pass, sel *ast.SelectorExpr) bool {
|
||||
typ := pass.TypesInfo.TypeOf(sel.X)
|
||||
if typ != nil {
|
||||
s := typ.String()
|
||||
return s == "*testing.T" || s == "*testing.B" || s == "*testing.F"
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// checkRangeSource examines the expression being ranged over and checks
|
||||
// composite literal elements for bad subtest name fields.
|
||||
func checkRangeSource(pass *analysis.Pass, rangeExpr ast.Expr, fieldName *ast.Ident) {
|
||||
switch x := rangeExpr.(type) {
|
||||
case *ast.Ident:
|
||||
if x.Obj == nil {
|
||||
return
|
||||
}
|
||||
switch decl := x.Obj.Decl.(type) {
|
||||
case *ast.AssignStmt:
|
||||
// e.g. tests := []struct{...}{...}
|
||||
for _, rhs := range decl.Rhs {
|
||||
checkCompositeLit(pass, rhs, fieldName)
|
||||
}
|
||||
case *ast.ValueSpec:
|
||||
// e.g. var tests = []struct{...}{...}
|
||||
for _, val := range decl.Values {
|
||||
checkCompositeLit(pass, val, fieldName)
|
||||
}
|
||||
}
|
||||
case *ast.CompositeLit:
|
||||
checkCompositeLit(pass, x, fieldName)
|
||||
}
|
||||
}
|
||||
|
||||
// checkCompositeLit checks a composite literal (slice/map) for elements
|
||||
// that have a field with a bad subtest name.
|
||||
func checkCompositeLit(pass *analysis.Pass, expr ast.Expr, fieldName *ast.Ident) {
|
||||
comp, ok := expr.(*ast.CompositeLit)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
for _, elt := range comp.Elts {
|
||||
// For map literals, check the value.
|
||||
if kv, ok := elt.(*ast.KeyValueExpr); ok {
|
||||
elt = kv.Value
|
||||
}
|
||||
checkStructLitField(pass, elt, fieldName)
|
||||
}
|
||||
}
|
||||
|
||||
// checkStructLitField checks a struct literal for a field with the given name
|
||||
// that contains a bad subtest name string.
|
||||
func checkStructLitField(pass *analysis.Pass, expr ast.Expr, fieldName *ast.Ident) {
|
||||
comp, ok := expr.(*ast.CompositeLit)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
for _, elt := range comp.Elts {
|
||||
kv, ok := elt.(*ast.KeyValueExpr)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
key, ok := kv.Key.(*ast.Ident)
|
||||
if !ok || key.Name != fieldName.Name {
|
||||
continue
|
||||
}
|
||||
lit, ok := kv.Value.(*ast.BasicLit)
|
||||
if !ok || lit.Kind != token.STRING {
|
||||
continue
|
||||
}
|
||||
val, err := strconv.Unquote(lit.Value)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if hasBadChar(val) {
|
||||
pass.Reportf(lit.Pos(), "subtest name %s contains characters that require quoting in go test -run patterns", lit.Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
15
cmd/vet/subtestnames/analyzer_test.go
Normal file
15
cmd/vet/subtestnames/analyzer_test.go
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright (c) Tailscale Inc & contributors
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package subtestnames
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"golang.org/x/tools/go/analysis/analysistest"
|
||||
)
|
||||
|
||||
func TestAnalyzer(t *testing.T) {
|
||||
testdata := analysistest.TestData()
|
||||
analysistest.Run(t, testdata, Analyzer, "example")
|
||||
}
|
||||
106
cmd/vet/subtestnames/testdata/src/example/example_test.go
vendored
Normal file
106
cmd/vet/subtestnames/testdata/src/example/example_test.go
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
// Copyright (c) Tailscale Inc & contributors
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package example
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestDirect(t *testing.T) {
|
||||
// Bad: spaces
|
||||
t.Run("that everything's cool", func(t *testing.T) {}) // want `subtest name "that everything's cool" contains characters that require quoting`
|
||||
|
||||
// Bad: apostrophe
|
||||
t.Run("it's working", func(t *testing.T) {}) // want `subtest name "it's working" contains characters that require quoting`
|
||||
|
||||
// Bad: regex metacharacters
|
||||
t.Run("test(foo)", func(t *testing.T) {}) // want `subtest name "test\(foo\)" contains characters that require quoting`
|
||||
t.Run("test[0]", func(t *testing.T) {}) // want `subtest name "test\[0\]" contains characters that require quoting`
|
||||
t.Run("a|b", func(t *testing.T) {}) // want `subtest name "a\|b" contains characters that require quoting`
|
||||
t.Run("a*b", func(t *testing.T) {}) // want `subtest name "a\*b" contains characters that require quoting`
|
||||
t.Run("a+b", func(t *testing.T) {}) // want `subtest name "a\+b" contains characters that require quoting`
|
||||
t.Run("a.b", func(t *testing.T) {}) // want `subtest name "a\.b" contains characters that require quoting`
|
||||
t.Run("^start", func(t *testing.T) {}) // want `subtest name "\^start" contains characters that require quoting`
|
||||
t.Run("end$", func(t *testing.T) {}) // want `subtest name "end\$" contains characters that require quoting`
|
||||
t.Run("a{2}", func(t *testing.T) {}) // want `subtest name "a\{2\}" contains characters that require quoting`
|
||||
t.Run("a?b", func(t *testing.T) {}) // want `subtest name "a\?b" contains characters that require quoting`
|
||||
t.Run("a\\b", func(t *testing.T) {}) // want `subtest name "a\\\\b" contains characters that require quoting`
|
||||
|
||||
// Bad: double quotes
|
||||
t.Run("say \"hello\"", func(t *testing.T) {}) // want `subtest name "say \\"hello\\"" contains characters that require quoting`
|
||||
|
||||
// Bad: hash
|
||||
t.Run("comment#1", func(t *testing.T) {}) // want `subtest name "comment#1" contains characters that require quoting`
|
||||
|
||||
// Good: clean names
|
||||
t.Run("zero-passes", func(t *testing.T) {})
|
||||
t.Run("simple_test", func(t *testing.T) {})
|
||||
t.Run("CamelCase", func(t *testing.T) {})
|
||||
t.Run("with-dashes", func(t *testing.T) {})
|
||||
t.Run("123", func(t *testing.T) {})
|
||||
t.Run("comma,separated", func(t *testing.T) {})
|
||||
t.Run("colon:value", func(t *testing.T) {})
|
||||
t.Run("slash/path", func(t *testing.T) {})
|
||||
t.Run("equals=sign", func(t *testing.T) {})
|
||||
}
|
||||
|
||||
func TestTableDriven(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
val int
|
||||
}{
|
||||
{name: "bad space name", val: 1}, // want `subtest name "bad space name" contains characters that require quoting`
|
||||
{name: "good-name", val: 2},
|
||||
{name: "also(bad)", val: 3}, // want `subtest name "also\(bad\)" contains characters that require quoting`
|
||||
{name: "it's-bad", val: 4}, // want `subtest name "it's-bad" contains characters that require quoting`
|
||||
{name: "clean-name", val: 5},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableDrivenVar(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name string
|
||||
val int
|
||||
}{
|
||||
{name: "has spaces", val: 1}, // want `subtest name "has spaces" contains characters that require quoting`
|
||||
{name: "ok-name", val: 2},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableDrivenMap(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
name string
|
||||
val int
|
||||
}{
|
||||
"key1": {name: "bad name here", val: 1}, // want `subtest name "bad name here" contains characters that require quoting`
|
||||
"key2": {name: "ok-name", val: 2},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotTesting(t *testing.T) {
|
||||
// Not a t.Run call, should not trigger.
|
||||
s := struct{ Run func(string, func()) }{}
|
||||
s.Run("bad name here", func() {})
|
||||
}
|
||||
|
||||
func TestDynamicName(t *testing.T) {
|
||||
// Dynamic name, not a string literal — should not trigger.
|
||||
name := getName()
|
||||
t.Run(name, func(t *testing.T) {})
|
||||
}
|
||||
|
||||
func getName() string { return "foo" }
|
||||
|
||||
func BenchmarkDirect(b *testing.B) {
|
||||
// Also check b.Run.
|
||||
b.Run("bad name here", func(b *testing.B) {}) // want `subtest name "bad name here" contains characters that require quoting`
|
||||
b.Run("good-name", func(b *testing.B) {})
|
||||
}
|
||||
@ -9,6 +9,7 @@ import (
|
||||
|
||||
"golang.org/x/tools/go/analysis/unitchecker"
|
||||
"tailscale.com/cmd/vet/jsontags"
|
||||
"tailscale.com/cmd/vet/subtestnames"
|
||||
)
|
||||
|
||||
//go:embed jsontags_allowlist
|
||||
@ -20,5 +21,5 @@ func init() {
|
||||
}
|
||||
|
||||
func main() {
|
||||
unitchecker.Main(jsontags.Analyzer)
|
||||
unitchecker.Main(jsontags.Analyzer, subtestnames.Analyzer)
|
||||
}
|
||||
|
||||
@ -801,7 +801,7 @@ func TestUpdateDiscoForNodeCallbackWithFullNetmap(t *testing.T) {
|
||||
expectNewDisco bool
|
||||
}{
|
||||
{
|
||||
name: "disco key wired through when newer lastSeen",
|
||||
name: "disco-key-newer-lastSeen",
|
||||
initialOnline: false,
|
||||
initialLastSeen: oldTime,
|
||||
updateOnline: false,
|
||||
@ -809,7 +809,7 @@ func TestUpdateDiscoForNodeCallbackWithFullNetmap(t *testing.T) {
|
||||
expectNewDisco: true,
|
||||
},
|
||||
{
|
||||
name: "disco key NOT wired through when older lastSeen",
|
||||
name: "disco-key-older-lastSeen",
|
||||
initialOnline: false,
|
||||
initialLastSeen: now,
|
||||
updateOnline: false,
|
||||
@ -817,7 +817,7 @@ func TestUpdateDiscoForNodeCallbackWithFullNetmap(t *testing.T) {
|
||||
expectNewDisco: false,
|
||||
},
|
||||
{
|
||||
name: "disco key wired through when newer lastSeen, going offline",
|
||||
name: "disco-key-newer-lastSeen-going-offline",
|
||||
initialOnline: true,
|
||||
initialLastSeen: oldTime,
|
||||
updateOnline: false,
|
||||
@ -825,7 +825,7 @@ func TestUpdateDiscoForNodeCallbackWithFullNetmap(t *testing.T) {
|
||||
expectNewDisco: true,
|
||||
},
|
||||
{
|
||||
name: "online flip with newer lastSeen",
|
||||
name: "online-flip-newer-lastSeen",
|
||||
initialOnline: false,
|
||||
initialLastSeen: oldTime,
|
||||
updateOnline: true,
|
||||
|
||||
@ -616,13 +616,13 @@ func TestSendFreeze(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("initial send", func(t *testing.T) {
|
||||
t.Run("initial-send", func(t *testing.T) {
|
||||
drain(t, "bob")
|
||||
drain(t, "cathy")
|
||||
isEmpty(t, "alice")
|
||||
})
|
||||
|
||||
t.Run("block cathy", func(t *testing.T) {
|
||||
t.Run("block-cathy", func(t *testing.T) {
|
||||
// Block cathy. Now the cathyConn buffer will fill up quickly,
|
||||
// and the derp server will back up.
|
||||
cathyConn.SetReadBlock(true)
|
||||
|
||||
@ -447,7 +447,7 @@ func TestXDP(t *testing.T) {
|
||||
wantMetrics map[bpfCountersKey]uint64
|
||||
}{
|
||||
{
|
||||
name: "ipv4 STUN Binding Request Drop STUN",
|
||||
name: "ipv4-STUN-Binding-Request-Drop-STUN",
|
||||
dropSTUN: true,
|
||||
packetIn: ipv4STUNBindingReqTX,
|
||||
wantCode: xdpActionDrop,
|
||||
@ -466,7 +466,7 @@ func TestXDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ipv6 STUN Binding Request Drop STUN",
|
||||
name: "ipv6-STUN-Binding-Request-Drop-STUN",
|
||||
dropSTUN: true,
|
||||
packetIn: ipv6STUNBindingReqTX,
|
||||
wantCode: xdpActionDrop,
|
||||
@ -485,7 +485,7 @@ func TestXDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ipv4 STUN Binding Request TX",
|
||||
name: "ipv4-STUN-Binding-Request-TX",
|
||||
packetIn: ipv4STUNBindingReqTX,
|
||||
wantCode: xdpActionTX,
|
||||
wantPacketOut: getIPv4STUNBindingResp(),
|
||||
@ -503,7 +503,7 @@ func TestXDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ipv6 STUN Binding Request TX",
|
||||
name: "ipv6-STUN-Binding-Request-TX",
|
||||
packetIn: ipv6STUNBindingReqTX,
|
||||
wantCode: xdpActionTX,
|
||||
wantPacketOut: getIPv6STUNBindingResp(),
|
||||
@ -521,7 +521,7 @@ func TestXDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ipv4 STUN Binding Request invalid ip csum PASS",
|
||||
name: "ipv4-STUN-Binding-Request-invalid-ip-csum-PASS",
|
||||
packetIn: ipv4STUNBindingReqIPCsumPass,
|
||||
wantCode: xdpActionPass,
|
||||
wantPacketOut: ipv4STUNBindingReqIPCsumPass,
|
||||
@ -539,7 +539,7 @@ func TestXDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ipv4 STUN Binding Request ihl PASS",
|
||||
name: "ipv4-STUN-Binding-Request-ihl-PASS",
|
||||
packetIn: ipv4STUNBindingReqIHLPass,
|
||||
wantCode: xdpActionPass,
|
||||
wantPacketOut: ipv4STUNBindingReqIHLPass,
|
||||
@ -557,7 +557,7 @@ func TestXDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ipv4 STUN Binding Request ip version PASS",
|
||||
name: "ipv4-STUN-Binding-Request-ip-version-PASS",
|
||||
packetIn: ipv4STUNBindingReqIPVerPass,
|
||||
wantCode: xdpActionPass,
|
||||
wantPacketOut: ipv4STUNBindingReqIPVerPass,
|
||||
@ -575,7 +575,7 @@ func TestXDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ipv4 STUN Binding Request ip proto PASS",
|
||||
name: "ipv4-STUN-Binding-Request-ip-proto-PASS",
|
||||
packetIn: ipv4STUNBindingReqIPProtoPass,
|
||||
wantCode: xdpActionPass,
|
||||
wantPacketOut: ipv4STUNBindingReqIPProtoPass,
|
||||
@ -593,7 +593,7 @@ func TestXDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ipv4 STUN Binding Request frag offset PASS",
|
||||
name: "ipv4-STUN-Binding-Request-frag-offset-PASS",
|
||||
packetIn: ipv4STUNBindingReqFragOffsetPass,
|
||||
wantCode: xdpActionPass,
|
||||
wantPacketOut: ipv4STUNBindingReqFragOffsetPass,
|
||||
@ -611,7 +611,7 @@ func TestXDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ipv4 STUN Binding Request flags mf PASS",
|
||||
name: "ipv4-STUN-Binding-Request-flags-mf-PASS",
|
||||
packetIn: ipv4STUNBindingReqFlagsMFPass,
|
||||
wantCode: xdpActionPass,
|
||||
wantPacketOut: ipv4STUNBindingReqFlagsMFPass,
|
||||
@ -629,7 +629,7 @@ func TestXDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ipv4 STUN Binding Request tot len PASS",
|
||||
name: "ipv4-STUN-Binding-Request-tot-len-PASS",
|
||||
packetIn: ipv4STUNBindingReqTotLenPass,
|
||||
wantCode: xdpActionPass,
|
||||
wantPacketOut: ipv4STUNBindingReqTotLenPass,
|
||||
@ -647,7 +647,7 @@ func TestXDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ipv6 STUN Binding Request ip version PASS",
|
||||
name: "ipv6-STUN-Binding-Request-ip-version-PASS",
|
||||
packetIn: ipv6STUNBindingReqIPVerPass,
|
||||
wantCode: xdpActionPass,
|
||||
wantPacketOut: ipv6STUNBindingReqIPVerPass,
|
||||
@ -665,7 +665,7 @@ func TestXDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ipv6 STUN Binding Request next hdr PASS",
|
||||
name: "ipv6-STUN-Binding-Request-next-hdr-PASS",
|
||||
packetIn: ipv6STUNBindingReqNextHdrPass,
|
||||
wantCode: xdpActionPass,
|
||||
wantPacketOut: ipv6STUNBindingReqNextHdrPass,
|
||||
@ -683,7 +683,7 @@ func TestXDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ipv6 STUN Binding Request payload len PASS",
|
||||
name: "ipv6-STUN-Binding-Request-payload-len-PASS",
|
||||
packetIn: ipv6STUNBindingReqPayloadLenPass,
|
||||
wantCode: xdpActionPass,
|
||||
wantPacketOut: ipv6STUNBindingReqPayloadLenPass,
|
||||
@ -701,7 +701,7 @@ func TestXDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ipv4 STUN Binding Request UDP csum PASS",
|
||||
name: "ipv4-STUN-Binding-Request-UDP-csum-PASS",
|
||||
packetIn: ipv4STUNBindingReqUDPCsumPass,
|
||||
wantCode: xdpActionPass,
|
||||
wantPacketOut: ipv4STUNBindingReqUDPCsumPass,
|
||||
@ -719,7 +719,7 @@ func TestXDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ipv6 STUN Binding Request UDP csum PASS",
|
||||
name: "ipv6-STUN-Binding-Request-UDP-csum-PASS",
|
||||
packetIn: ipv6STUNBindingReqUDPCsumPass,
|
||||
wantCode: xdpActionPass,
|
||||
wantPacketOut: ipv6STUNBindingReqUDPCsumPass,
|
||||
@ -737,7 +737,7 @@ func TestXDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ipv4 STUN Binding Request STUN type PASS",
|
||||
name: "ipv4-STUN-Binding-Request-STUN-type-PASS",
|
||||
packetIn: ipv4STUNBindingReqSTUNTypePass,
|
||||
wantCode: xdpActionPass,
|
||||
wantPacketOut: ipv4STUNBindingReqSTUNTypePass,
|
||||
@ -755,7 +755,7 @@ func TestXDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ipv6 STUN Binding Request STUN type PASS",
|
||||
name: "ipv6-STUN-Binding-Request-STUN-type-PASS",
|
||||
packetIn: ipv6STUNBindingReqSTUNTypePass,
|
||||
wantCode: xdpActionPass,
|
||||
wantPacketOut: ipv6STUNBindingReqSTUNTypePass,
|
||||
@ -773,7 +773,7 @@ func TestXDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ipv4 STUN Binding Request STUN magic PASS",
|
||||
name: "ipv4-STUN-Binding-Request-STUN-magic-PASS",
|
||||
packetIn: ipv4STUNBindingReqSTUNMagicPass,
|
||||
wantCode: xdpActionPass,
|
||||
wantPacketOut: ipv4STUNBindingReqSTUNMagicPass,
|
||||
@ -791,7 +791,7 @@ func TestXDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ipv6 STUN Binding Request STUN magic PASS",
|
||||
name: "ipv6-STUN-Binding-Request-STUN-magic-PASS",
|
||||
packetIn: ipv6STUNBindingReqSTUNMagicPass,
|
||||
wantCode: xdpActionPass,
|
||||
wantPacketOut: ipv6STUNBindingReqSTUNMagicPass,
|
||||
@ -809,7 +809,7 @@ func TestXDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ipv4 STUN Binding Request STUN attrs len PASS",
|
||||
name: "ipv4-STUN-Binding-Request-STUN-attrs-len-PASS",
|
||||
packetIn: ipv4STUNBindingReqSTUNAttrsLenPass,
|
||||
wantCode: xdpActionPass,
|
||||
wantPacketOut: ipv4STUNBindingReqSTUNAttrsLenPass,
|
||||
@ -827,7 +827,7 @@ func TestXDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ipv6 STUN Binding Request STUN attrs len PASS",
|
||||
name: "ipv6-STUN-Binding-Request-STUN-attrs-len-PASS",
|
||||
packetIn: ipv6STUNBindingReqSTUNAttrsLenPass,
|
||||
wantCode: xdpActionPass,
|
||||
wantPacketOut: ipv6STUNBindingReqSTUNAttrsLenPass,
|
||||
@ -845,7 +845,7 @@ func TestXDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ipv4 STUN Binding Request STUN SW val PASS",
|
||||
name: "ipv4-STUN-Binding-Request-STUN-SW-val-PASS",
|
||||
packetIn: ipv4STUNBindingReqSTUNSWValPass,
|
||||
wantCode: xdpActionPass,
|
||||
wantPacketOut: ipv4STUNBindingReqSTUNSWValPass,
|
||||
@ -863,7 +863,7 @@ func TestXDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ipv6 STUN Binding Request STUN SW val PASS",
|
||||
name: "ipv6-STUN-Binding-Request-STUN-SW-val-PASS",
|
||||
packetIn: ipv6STUNBindingReqSTUNSWValPass,
|
||||
wantCode: xdpActionPass,
|
||||
wantPacketOut: ipv6STUNBindingReqSTUNSWValPass,
|
||||
@ -881,7 +881,7 @@ func TestXDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ipv4 STUN Binding Request STUN first attr PASS",
|
||||
name: "ipv4-STUN-Binding-Request-STUN-first-attr-PASS",
|
||||
packetIn: ipv4STUNBindingReqSTUNFirstAttrPass,
|
||||
wantCode: xdpActionPass,
|
||||
wantPacketOut: ipv4STUNBindingReqSTUNFirstAttrPass,
|
||||
@ -899,7 +899,7 @@ func TestXDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ipv6 STUN Binding Request STUN first attr PASS",
|
||||
name: "ipv6-STUN-Binding-Request-STUN-first-attr-PASS",
|
||||
packetIn: ipv6STUNBindingReqSTUNFirstAttrPass,
|
||||
wantCode: xdpActionPass,
|
||||
wantPacketOut: ipv6STUNBindingReqSTUNFirstAttrPass,
|
||||
@ -917,7 +917,7 @@ func TestXDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ipv4 UDP zero csum TX",
|
||||
name: "ipv4-UDP-zero-csum-TX",
|
||||
packetIn: ipv4STUNBindingReqUDPZeroCsumTx,
|
||||
wantCode: xdpActionTX,
|
||||
wantPacketOut: getIPv4STUNBindingResp(),
|
||||
@ -935,7 +935,7 @@ func TestXDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ipv6 UDP zero csum PASS",
|
||||
name: "ipv6-UDP-zero-csum-PASS",
|
||||
packetIn: ipv6STUNBindingReqUDPZeroCsumPass,
|
||||
wantCode: xdpActionPass,
|
||||
wantPacketOut: ipv6STUNBindingReqUDPZeroCsumPass,
|
||||
|
||||
@ -29,7 +29,7 @@ func TestStat(t *testing.T) {
|
||||
err error
|
||||
}{
|
||||
{
|
||||
label: "root folder",
|
||||
label: "root-folder",
|
||||
name: "",
|
||||
expected: &shared.StaticFileInfo{
|
||||
Named: "",
|
||||
@ -40,7 +40,7 @@ func TestStat(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "static root folder",
|
||||
label: "static-root-folder",
|
||||
name: "/domain",
|
||||
expected: &shared.StaticFileInfo{
|
||||
Named: "domain",
|
||||
@ -73,7 +73,7 @@ func TestStat(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "non-existent remote",
|
||||
label: "non-existent-remote",
|
||||
name: "remote3",
|
||||
err: os.ErrNotExist,
|
||||
},
|
||||
@ -108,7 +108,7 @@ func TestListDir(t *testing.T) {
|
||||
err error
|
||||
}{
|
||||
{
|
||||
label: "root folder",
|
||||
label: "root-folder",
|
||||
name: "",
|
||||
expected: []fs.FileInfo{
|
||||
&shared.StaticFileInfo{
|
||||
@ -121,7 +121,7 @@ func TestListDir(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "static root folder",
|
||||
label: "static-root-folder",
|
||||
name: "/domain",
|
||||
expected: []fs.FileInfo{
|
||||
&shared.StaticFileInfo{
|
||||
@ -189,19 +189,19 @@ func TestMkdir(t *testing.T) {
|
||||
err error
|
||||
}{
|
||||
{
|
||||
label: "attempt to create root folder",
|
||||
label: "create-root-folder",
|
||||
name: "/",
|
||||
},
|
||||
{
|
||||
label: "attempt to create static root folder",
|
||||
label: "create-static-root-folder",
|
||||
name: "/domain",
|
||||
},
|
||||
{
|
||||
label: "attempt to create remote",
|
||||
label: "create-remote",
|
||||
name: "/domain/remote1",
|
||||
},
|
||||
{
|
||||
label: "attempt to create non-existent remote",
|
||||
label: "create-non-existent-remote",
|
||||
name: "/domain/remote3",
|
||||
err: os.ErrPermission,
|
||||
},
|
||||
@ -231,7 +231,7 @@ func TestRemoveAll(t *testing.T) {
|
||||
err error
|
||||
}{
|
||||
{
|
||||
label: "attempt to remove root folder",
|
||||
label: "remove-root-folder",
|
||||
name: "/",
|
||||
err: os.ErrPermission,
|
||||
},
|
||||
@ -258,7 +258,7 @@ func TestRename(t *testing.T) {
|
||||
err error
|
||||
}{
|
||||
{
|
||||
label: "attempt to move root folder",
|
||||
label: "move-root-folder",
|
||||
oldName: "/",
|
||||
newName: "/domain/remote2/copy.txt",
|
||||
err: os.ErrPermission,
|
||||
|
||||
@ -156,27 +156,27 @@ func TestMissingPaths(t *testing.T) {
|
||||
wantStatus int
|
||||
}{
|
||||
{
|
||||
name: "empty path",
|
||||
name: "empty-path",
|
||||
path: "",
|
||||
wantStatus: http.StatusForbidden,
|
||||
},
|
||||
{
|
||||
name: "single slash",
|
||||
name: "single-slash",
|
||||
path: "/",
|
||||
wantStatus: http.StatusForbidden,
|
||||
},
|
||||
{
|
||||
name: "only token",
|
||||
name: "only-token",
|
||||
path: "/" + secretToken,
|
||||
wantStatus: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
name: "token with trailing slash",
|
||||
name: "token-trailing-slash",
|
||||
path: "/" + secretToken + "/",
|
||||
wantStatus: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
name: "token and invalid share",
|
||||
name: "token-invalid-share",
|
||||
path: "/" + secretToken + "/nonexistentshare",
|
||||
wantStatus: http.StatusNotFound,
|
||||
},
|
||||
|
||||
@ -31,7 +31,7 @@ func TestResolveAuthKey(t *testing.T) {
|
||||
wantErr: "",
|
||||
},
|
||||
{
|
||||
name: "missing client id short-circuits without error",
|
||||
name: "missing-client-id-noop",
|
||||
clientID: "",
|
||||
idToken: "token",
|
||||
audience: "api://tailscale-wif",
|
||||
@ -40,7 +40,7 @@ func TestResolveAuthKey(t *testing.T) {
|
||||
wantErr: "",
|
||||
},
|
||||
{
|
||||
name: "missing id token and audience",
|
||||
name: "missing-id-token-and-audience",
|
||||
clientID: "client-123",
|
||||
idToken: "",
|
||||
audience: "",
|
||||
@ -48,7 +48,7 @@ func TestResolveAuthKey(t *testing.T) {
|
||||
wantErr: "federated identity requires either an ID token or an audience",
|
||||
},
|
||||
{
|
||||
name: "missing tags",
|
||||
name: "missing-tags",
|
||||
clientID: "client-123",
|
||||
idToken: "token",
|
||||
audience: "api://tailscale-wif",
|
||||
@ -56,7 +56,7 @@ func TestResolveAuthKey(t *testing.T) {
|
||||
wantErr: "federated identity authkeys require --advertise-tags",
|
||||
},
|
||||
{
|
||||
name: "invalid client id attributes",
|
||||
name: "invalid-client-id-attrs",
|
||||
clientID: "client-123?invalid=value",
|
||||
idToken: "token",
|
||||
audience: "api://tailscale-wif",
|
||||
@ -99,7 +99,7 @@ func TestParseOptionalAttributes(t *testing.T) {
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "default values",
|
||||
name: "default-values",
|
||||
clientID: "client-123",
|
||||
wantClientID: "client-123",
|
||||
wantEphemeral: true,
|
||||
@ -107,7 +107,7 @@ func TestParseOptionalAttributes(t *testing.T) {
|
||||
wantErr: "",
|
||||
},
|
||||
{
|
||||
name: "custom values",
|
||||
name: "custom-values",
|
||||
clientID: "client-123?ephemeral=false&preauthorized=true",
|
||||
wantClientID: "client-123",
|
||||
wantEphemeral: false,
|
||||
@ -115,7 +115,7 @@ func TestParseOptionalAttributes(t *testing.T) {
|
||||
wantErr: "",
|
||||
},
|
||||
{
|
||||
name: "unknown attribute",
|
||||
name: "unknown-attribute",
|
||||
clientID: "client-123?unknown=value",
|
||||
wantClientID: "",
|
||||
wantEphemeral: false,
|
||||
@ -123,7 +123,7 @@ func TestParseOptionalAttributes(t *testing.T) {
|
||||
wantErr: `unknown optional config attribute "unknown"`,
|
||||
},
|
||||
{
|
||||
name: "invalid value",
|
||||
name: "invalid-value",
|
||||
clientID: "client-123?ephemeral=invalid",
|
||||
wantClientID: "",
|
||||
wantEphemeral: false,
|
||||
|
||||
@ -20,42 +20,42 @@ func TestResolveAuthKey(t *testing.T) {
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "keys without client secret prefix pass through unchanged",
|
||||
name: "non-client-secret-passthrough",
|
||||
clientID: "tskey-auth-regular",
|
||||
tags: []string{"tag:test"},
|
||||
wantAuthKey: "tskey-auth-regular",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "client secret without advertised tags",
|
||||
name: "client-secret-no-tags",
|
||||
clientID: "tskey-client-abc",
|
||||
tags: nil,
|
||||
wantAuthKey: "",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "client secret with default attributes",
|
||||
name: "client-secret-default-attrs",
|
||||
clientID: "tskey-client-abc",
|
||||
tags: []string{"tag:test"},
|
||||
wantAuthKey: "tskey-auth-xyz",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "client secret with custom attributes",
|
||||
name: "client-secret-custom-attrs",
|
||||
clientID: "tskey-client-abc?ephemeral=false&preauthorized=true",
|
||||
tags: []string{"tag:test"},
|
||||
wantAuthKey: "tskey-auth-xyz",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "client secret with unknown attribute",
|
||||
name: "client-secret-unknown-attr",
|
||||
clientID: "tskey-client-abc?unknown=value",
|
||||
tags: []string{"tag:test"},
|
||||
wantAuthKey: "",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "oauth client secret with invalid attribute value",
|
||||
name: "client-secret-invalid-attr-value",
|
||||
clientID: "tskey-client-abc?ephemeral=invalid",
|
||||
tags: []string{"tag:test"},
|
||||
wantAuthKey: "",
|
||||
@ -111,7 +111,7 @@ func TestResolveAuthKeyAttributes(t *testing.T) {
|
||||
wantBaseURL string
|
||||
}{
|
||||
{
|
||||
name: "default values",
|
||||
name: "default-values",
|
||||
clientSecret: "tskey-client-abc",
|
||||
wantEphemeral: true,
|
||||
wantPreauth: false,
|
||||
@ -132,14 +132,14 @@ func TestResolveAuthKeyAttributes(t *testing.T) {
|
||||
wantBaseURL: "https://api.tailscale.com",
|
||||
},
|
||||
{
|
||||
name: "baseURL=https://api.example.com",
|
||||
name: "baseURL-custom",
|
||||
clientSecret: "tskey-client-abc?baseURL=https://api.example.com",
|
||||
wantEphemeral: true,
|
||||
wantPreauth: false,
|
||||
wantBaseURL: "https://api.example.com",
|
||||
},
|
||||
{
|
||||
name: "all custom values",
|
||||
name: "all-custom-values",
|
||||
clientSecret: "tskey-client-abc?ephemeral=false&preauthorized=true&baseURL=https://api.example.com",
|
||||
wantEphemeral: false,
|
||||
wantPreauth: true,
|
||||
|
||||
@ -48,7 +48,7 @@ func Test_extension_profileStateChanged(t *testing.T) {
|
||||
wantEndpoints []netip.AddrPort
|
||||
}{
|
||||
{
|
||||
name: "no changes non-nil port previously running",
|
||||
name: "no-changes-non-nil-port-running",
|
||||
fields: fields{
|
||||
port: new(uint16(1)),
|
||||
rs: mockRelayServerNotZeroVal(),
|
||||
@ -62,7 +62,7 @@ func Test_extension_profileStateChanged(t *testing.T) {
|
||||
wantRelayServerFieldMutated: false,
|
||||
},
|
||||
{
|
||||
name: "set addr ports unchanged port previously running",
|
||||
name: "set-addr-ports-unchanged-running",
|
||||
fields: fields{
|
||||
port: new(uint16(1)),
|
||||
rs: mockRelayServerNotZeroVal(),
|
||||
@ -77,7 +77,7 @@ func Test_extension_profileStateChanged(t *testing.T) {
|
||||
wantEndpoints: prefsWithPortOneRelayEndpoints.RelayServerStaticEndpoints,
|
||||
},
|
||||
{
|
||||
name: "set addr ports not previously running",
|
||||
name: "set-addr-ports-not-running",
|
||||
fields: fields{
|
||||
port: nil,
|
||||
rs: nil,
|
||||
@ -92,7 +92,7 @@ func Test_extension_profileStateChanged(t *testing.T) {
|
||||
wantEndpoints: prefsWithPortOneRelayEndpoints.RelayServerStaticEndpoints,
|
||||
},
|
||||
{
|
||||
name: "clear addr ports unchanged port previously running",
|
||||
name: "clear-addr-ports-unchanged-running",
|
||||
fields: fields{
|
||||
port: new(uint16(1)),
|
||||
staticEndpoints: views.SliceOf(prefsWithPortOneRelayEndpoints.RelayServerStaticEndpoints),
|
||||
@ -108,7 +108,7 @@ func Test_extension_profileStateChanged(t *testing.T) {
|
||||
wantEndpoints: nil,
|
||||
},
|
||||
{
|
||||
name: "prefs port nil",
|
||||
name: "prefs-port-nil",
|
||||
fields: fields{
|
||||
port: new(uint16(1)),
|
||||
},
|
||||
@ -121,7 +121,7 @@ func Test_extension_profileStateChanged(t *testing.T) {
|
||||
wantRelayServerFieldMutated: false,
|
||||
},
|
||||
{
|
||||
name: "prefs port nil previously running",
|
||||
name: "prefs-port-nil-running",
|
||||
fields: fields{
|
||||
port: new(uint16(1)),
|
||||
rs: mockRelayServerNotZeroVal(),
|
||||
@ -135,7 +135,7 @@ func Test_extension_profileStateChanged(t *testing.T) {
|
||||
wantRelayServerFieldMutated: true,
|
||||
},
|
||||
{
|
||||
name: "prefs port changed",
|
||||
name: "prefs-port-changed",
|
||||
fields: fields{
|
||||
port: new(uint16(2)),
|
||||
},
|
||||
@ -148,7 +148,7 @@ func Test_extension_profileStateChanged(t *testing.T) {
|
||||
wantRelayServerFieldMutated: true,
|
||||
},
|
||||
{
|
||||
name: "prefs port changed previously running",
|
||||
name: "prefs-port-changed-running",
|
||||
fields: fields{
|
||||
port: new(uint16(2)),
|
||||
rs: mockRelayServerNotZeroVal(),
|
||||
@ -162,7 +162,7 @@ func Test_extension_profileStateChanged(t *testing.T) {
|
||||
wantRelayServerFieldMutated: true,
|
||||
},
|
||||
{
|
||||
name: "sameNode false",
|
||||
name: "sameNode-false",
|
||||
fields: fields{
|
||||
port: new(uint16(1)),
|
||||
},
|
||||
@ -175,7 +175,7 @@ func Test_extension_profileStateChanged(t *testing.T) {
|
||||
wantRelayServerFieldMutated: true,
|
||||
},
|
||||
{
|
||||
name: "sameNode false previously running",
|
||||
name: "sameNode-false-running",
|
||||
fields: fields{
|
||||
port: new(uint16(1)),
|
||||
rs: mockRelayServerNotZeroVal(),
|
||||
@ -189,7 +189,7 @@ func Test_extension_profileStateChanged(t *testing.T) {
|
||||
wantRelayServerFieldMutated: true,
|
||||
},
|
||||
{
|
||||
name: "prefs port non-nil extension port nil",
|
||||
name: "prefs-port-non-nil-ext-nil",
|
||||
fields: fields{
|
||||
port: nil,
|
||||
},
|
||||
@ -277,7 +277,7 @@ func Test_extension_handleRelayServerLifetimeLocked(t *testing.T) {
|
||||
wantRelayServerFieldMutated bool
|
||||
}{
|
||||
{
|
||||
name: "want running",
|
||||
name: "want-running",
|
||||
shutdown: false,
|
||||
port: new(uint16(1)),
|
||||
hasNodeAttrDisableRelayServer: false,
|
||||
@ -285,7 +285,7 @@ func Test_extension_handleRelayServerLifetimeLocked(t *testing.T) {
|
||||
wantRelayServerFieldMutated: true,
|
||||
},
|
||||
{
|
||||
name: "want running previously running",
|
||||
name: "want-running-previously-running",
|
||||
shutdown: false,
|
||||
port: new(uint16(1)),
|
||||
rs: mockRelayServerNotZeroVal(),
|
||||
@ -294,7 +294,7 @@ func Test_extension_handleRelayServerLifetimeLocked(t *testing.T) {
|
||||
wantRelayServerFieldMutated: false,
|
||||
},
|
||||
{
|
||||
name: "shutdown true",
|
||||
name: "shutdown-true",
|
||||
shutdown: true,
|
||||
port: new(uint16(1)),
|
||||
hasNodeAttrDisableRelayServer: false,
|
||||
@ -302,7 +302,7 @@ func Test_extension_handleRelayServerLifetimeLocked(t *testing.T) {
|
||||
wantRelayServerFieldMutated: false,
|
||||
},
|
||||
{
|
||||
name: "shutdown true previously running",
|
||||
name: "shutdown-true-previously-running",
|
||||
shutdown: true,
|
||||
port: new(uint16(1)),
|
||||
rs: mockRelayServerNotZeroVal(),
|
||||
@ -311,7 +311,7 @@ func Test_extension_handleRelayServerLifetimeLocked(t *testing.T) {
|
||||
wantRelayServerFieldMutated: true,
|
||||
},
|
||||
{
|
||||
name: "port nil",
|
||||
name: "port-nil",
|
||||
shutdown: false,
|
||||
port: nil,
|
||||
hasNodeAttrDisableRelayServer: false,
|
||||
@ -319,7 +319,7 @@ func Test_extension_handleRelayServerLifetimeLocked(t *testing.T) {
|
||||
wantRelayServerFieldMutated: false,
|
||||
},
|
||||
{
|
||||
name: "port nil previously running",
|
||||
name: "port-nil-previously-running",
|
||||
shutdown: false,
|
||||
port: nil,
|
||||
rs: mockRelayServerNotZeroVal(),
|
||||
@ -328,7 +328,7 @@ func Test_extension_handleRelayServerLifetimeLocked(t *testing.T) {
|
||||
wantRelayServerFieldMutated: true,
|
||||
},
|
||||
{
|
||||
name: "hasNodeAttrDisableRelayServer true",
|
||||
name: "hasNodeAttrDisableRelayServer-true",
|
||||
shutdown: false,
|
||||
port: nil,
|
||||
hasNodeAttrDisableRelayServer: true,
|
||||
@ -336,7 +336,7 @@ func Test_extension_handleRelayServerLifetimeLocked(t *testing.T) {
|
||||
wantRelayServerFieldMutated: false,
|
||||
},
|
||||
{
|
||||
name: "hasNodeAttrDisableRelayServer true previously running",
|
||||
name: "hasNodeAttrDisableRelayServer-true-running",
|
||||
shutdown: false,
|
||||
port: nil,
|
||||
rs: mockRelayServerNotZeroVal(),
|
||||
|
||||
@ -163,4 +163,4 @@
|
||||
});
|
||||
};
|
||||
}
|
||||
# nix-direnv cache busting line: sha256-39axT5Q0+fNTcMgZCMLMNfJEJN46wMaaKDgfI+Uj+Ps=
|
||||
# nix-direnv cache busting line: sha256-VsVMvTEblVx/HNbuCVxC9UgKpriRwixswUSKVGLMf3Q=
|
||||
|
||||
@ -1 +1 @@
|
||||
sha256-39axT5Q0+fNTcMgZCMLMNfJEJN46wMaaKDgfI+Uj+Ps=
|
||||
sha256-VsVMvTEblVx/HNbuCVxC9UgKpriRwixswUSKVGLMf3Q=
|
||||
|
||||
@ -388,7 +388,7 @@ func TestShowUpdateWarnable(t *testing.T) {
|
||||
wantShow bool
|
||||
}{
|
||||
{
|
||||
desc: "nil ClientVersion",
|
||||
desc: "nil-ClientVersion",
|
||||
check: true,
|
||||
cv: nil,
|
||||
wantWarnable: nil,
|
||||
@ -402,35 +402,35 @@ func TestShowUpdateWarnable(t *testing.T) {
|
||||
wantShow: false,
|
||||
},
|
||||
{
|
||||
desc: "no LatestVersion",
|
||||
desc: "no-LatestVersion",
|
||||
check: true,
|
||||
cv: &tailcfg.ClientVersion{RunningLatest: false, LatestVersion: ""},
|
||||
wantWarnable: nil,
|
||||
wantShow: false,
|
||||
},
|
||||
{
|
||||
desc: "show regular update",
|
||||
desc: "show-regular-update",
|
||||
check: true,
|
||||
cv: &tailcfg.ClientVersion{RunningLatest: false, LatestVersion: "1.2.3"},
|
||||
wantWarnable: updateAvailableWarnable,
|
||||
wantShow: true,
|
||||
},
|
||||
{
|
||||
desc: "show security update",
|
||||
desc: "show-security-update",
|
||||
check: true,
|
||||
cv: &tailcfg.ClientVersion{RunningLatest: false, LatestVersion: "1.2.3", UrgentSecurityUpdate: true},
|
||||
wantWarnable: securityUpdateAvailableWarnable,
|
||||
wantShow: true,
|
||||
},
|
||||
{
|
||||
desc: "update check disabled",
|
||||
desc: "update-check-disabled",
|
||||
check: false,
|
||||
cv: &tailcfg.ClientVersion{RunningLatest: false, LatestVersion: "1.2.3"},
|
||||
wantWarnable: nil,
|
||||
wantShow: false,
|
||||
},
|
||||
{
|
||||
desc: "hide update with auto-updates",
|
||||
desc: "hide-update-with-auto-updates",
|
||||
check: true,
|
||||
apply: opt.NewBool(true),
|
||||
cv: &tailcfg.ClientVersion{RunningLatest: false, LatestVersion: "1.2.3"},
|
||||
@ -438,7 +438,7 @@ func TestShowUpdateWarnable(t *testing.T) {
|
||||
wantShow: false,
|
||||
},
|
||||
{
|
||||
desc: "show security update with auto-updates",
|
||||
desc: "show-security-update-with-auto-updates",
|
||||
check: true,
|
||||
apply: opt.NewBool(true),
|
||||
cv: &tailcfg.ClientVersion{RunningLatest: false, LatestVersion: "1.2.3", UrgentSecurityUpdate: true},
|
||||
@ -622,7 +622,7 @@ func TestControlHealth(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Strings()", func(t *testing.T) {
|
||||
t.Run("Strings", func(t *testing.T) {
|
||||
wantStrs := []string{
|
||||
"Control health message: Extra help.",
|
||||
"Control health message: Extra help. Learn more: http://www.example.com",
|
||||
|
||||
@ -63,7 +63,7 @@ func TestHandleC2NTLSCertStatus(t *testing.T) {
|
||||
want *tailcfg.C2NTLSCertInfo
|
||||
}{
|
||||
{
|
||||
name: "no domain",
|
||||
name: "no-domain",
|
||||
wantStatus: 400,
|
||||
wantError: "no 'domain'\n",
|
||||
},
|
||||
|
||||
@ -39,25 +39,29 @@ func TestCertRequest(t *testing.T) {
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
domain string
|
||||
wantSANs []string
|
||||
}{
|
||||
{
|
||||
name: "example-com",
|
||||
domain: "example.com",
|
||||
wantSANs: []string{"example.com"},
|
||||
},
|
||||
{
|
||||
name: "wildcard-example-com",
|
||||
domain: "*.example.com",
|
||||
wantSANs: []string{"*.example.com", "example.com"},
|
||||
},
|
||||
{
|
||||
name: "wildcard-foo-bar-com",
|
||||
domain: "*.foo.bar.com",
|
||||
wantSANs: []string{"*.foo.bar.com", "foo.bar.com"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.domain, func(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
csrDER, err := certRequest(key, tt.domain, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("certRequest: %v", err)
|
||||
@ -365,19 +369,19 @@ func TestShouldStartDomainRenewal(t *testing.T) {
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "should renew",
|
||||
name: "should-renew",
|
||||
notBefore: now.AddDate(0, 0, -89),
|
||||
lifetime: 90 * 24 * time.Hour,
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "short-lived renewal",
|
||||
name: "short-lived-renewal",
|
||||
notBefore: now.AddDate(0, 0, -7),
|
||||
lifetime: 10 * 24 * time.Hour,
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "no renew",
|
||||
name: "no-renew",
|
||||
notBefore: now.AddDate(0, 0, -59), // 59 days ago == not 2/3rds of the way through 90 days yet
|
||||
lifetime: 90 * 24 * time.Hour,
|
||||
want: false,
|
||||
|
||||
@ -3035,20 +3035,20 @@ func TestSetExitNodeIDPolicy(t *testing.T) {
|
||||
lastSuggestedExitNode tailcfg.StableNodeID
|
||||
}{
|
||||
{
|
||||
name: "ExitNodeID key is set",
|
||||
name: "exitNodeID-set",
|
||||
exitNodeIDKey: true,
|
||||
exitNodeID: "123",
|
||||
exitNodeIDWant: "123",
|
||||
prefsChanged: true,
|
||||
},
|
||||
{
|
||||
name: "ExitNodeID key not set",
|
||||
name: "exitNodeID-not-set",
|
||||
exitNodeIDKey: true,
|
||||
exitNodeIDWant: "",
|
||||
prefsChanged: false,
|
||||
},
|
||||
{
|
||||
name: "ExitNodeID key set, ExitNodeIP preference set",
|
||||
name: "exitNodeID-set-exitNodeIP-pref-set",
|
||||
exitNodeIDKey: true,
|
||||
exitNodeID: "123",
|
||||
prefs: &ipn.Prefs{ExitNodeIP: netip.MustParseAddr("127.0.0.1")},
|
||||
@ -3056,7 +3056,7 @@ func TestSetExitNodeIDPolicy(t *testing.T) {
|
||||
prefsChanged: true,
|
||||
},
|
||||
{
|
||||
name: "ExitNodeID key not set, ExitNodeIP key set",
|
||||
name: "exitNodeID-not-set-exitNodeIP-set",
|
||||
exitNodeIPKey: true,
|
||||
exitNodeIP: "127.0.0.1",
|
||||
prefs: &ipn.Prefs{ExitNodeIP: netip.MustParseAddr("127.0.0.1")},
|
||||
@ -3064,7 +3064,7 @@ func TestSetExitNodeIDPolicy(t *testing.T) {
|
||||
prefsChanged: false,
|
||||
},
|
||||
{
|
||||
name: "ExitNodeIP key set, existing ExitNodeIP pref",
|
||||
name: "exitNodeIP-set-existing-pref",
|
||||
exitNodeIPKey: true,
|
||||
exitNodeIP: "127.0.0.1",
|
||||
prefs: &ipn.Prefs{ExitNodeIP: netip.MustParseAddr("127.0.0.1")},
|
||||
@ -3072,7 +3072,7 @@ func TestSetExitNodeIDPolicy(t *testing.T) {
|
||||
prefsChanged: false,
|
||||
},
|
||||
{
|
||||
name: "existing preferences match policy",
|
||||
name: "existing-prefs-match-policy",
|
||||
exitNodeIDKey: true,
|
||||
exitNodeID: "123",
|
||||
prefs: &ipn.Prefs{ExitNodeID: tailcfg.StableNodeID("123")},
|
||||
@ -3080,7 +3080,8 @@ func TestSetExitNodeIDPolicy(t *testing.T) {
|
||||
prefsChanged: false,
|
||||
},
|
||||
{
|
||||
name: "ExitNodeIP set if net map does not have corresponding node",
|
||||
// ExitNodeIP is set when net map does not have a corresponding node.
|
||||
name: "exitNodeIP-set-no-matching-node",
|
||||
exitNodeIPKey: true,
|
||||
prefs: &ipn.Prefs{ExitNodeIP: netip.MustParseAddr("127.0.0.1")},
|
||||
exitNodeIP: "127.0.0.1",
|
||||
@ -3116,7 +3117,8 @@ func TestSetExitNodeIDPolicy(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ExitNodeIP cleared if net map has corresponding node - policy matches prefs",
|
||||
// ExitNodeIP cleared when net map has corresponding node and policy matches prefs.
|
||||
name: "exitNodeIP-cleared-matching-node-policy-matches",
|
||||
prefs: &ipn.Prefs{ExitNodeIP: netip.MustParseAddr("127.0.0.1")},
|
||||
exitNodeIPKey: true,
|
||||
exitNodeIP: "127.0.0.1",
|
||||
@ -3156,7 +3158,8 @@ func TestSetExitNodeIDPolicy(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ExitNodeIP cleared if net map has corresponding node - no policy set",
|
||||
// ExitNodeIP cleared when net map has corresponding node and no policy is set.
|
||||
name: "exitNodeIP-cleared-matching-node-no-policy",
|
||||
prefs: &ipn.Prefs{ExitNodeIP: netip.MustParseAddr("127.0.0.1")},
|
||||
exitNodeIPWant: "",
|
||||
exitNodeIDWant: "123",
|
||||
@ -3194,7 +3197,8 @@ func TestSetExitNodeIDPolicy(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ExitNodeIP cleared if net map has corresponding node - different exit node IP in policy",
|
||||
// ExitNodeIP cleared when net map has corresponding node but policy has different exit node IP.
|
||||
name: "exitNodeIP-cleared-matching-node-different-policy-IP",
|
||||
exitNodeIPKey: true,
|
||||
prefs: &ipn.Prefs{ExitNodeIP: netip.MustParseAddr("127.0.0.1")},
|
||||
exitNodeIP: "100.64.5.6",
|
||||
@ -3234,7 +3238,7 @@ func TestSetExitNodeIDPolicy(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ExitNodeID key is set to auto:any and last suggested exit node is populated",
|
||||
name: "exitNodeID-auto-any-last-suggested-populated",
|
||||
exitNodeIDKey: true,
|
||||
exitNodeID: "auto:any",
|
||||
lastSuggestedExitNode: "123",
|
||||
@ -3243,7 +3247,7 @@ func TestSetExitNodeIDPolicy(t *testing.T) {
|
||||
prefsChanged: true,
|
||||
},
|
||||
{
|
||||
name: "ExitNodeID key is set to auto:any and last suggested exit node is not populated",
|
||||
name: "exitNodeID-auto-any-last-suggested-not-populated",
|
||||
exitNodeIDKey: true,
|
||||
exitNodeID: "auto:any",
|
||||
exitNodeIDWant: "auto:any",
|
||||
@ -3251,7 +3255,7 @@ func TestSetExitNodeIDPolicy(t *testing.T) {
|
||||
prefsChanged: true,
|
||||
},
|
||||
{
|
||||
name: "ExitNodeID key is set to auto:foo and last suggested exit node is populated",
|
||||
name: "exitNodeID-auto-foo-last-suggested-populated",
|
||||
exitNodeIDKey: true,
|
||||
exitNodeID: "auto:foo",
|
||||
lastSuggestedExitNode: "123",
|
||||
@ -3260,7 +3264,7 @@ func TestSetExitNodeIDPolicy(t *testing.T) {
|
||||
prefsChanged: true,
|
||||
},
|
||||
{
|
||||
name: "ExitNodeID key is set to auto:foo and last suggested exit node is not populated",
|
||||
name: "exitNodeID-auto-foo-last-suggested-not-populated",
|
||||
exitNodeIDKey: true,
|
||||
exitNodeID: "auto:foo",
|
||||
exitNodeIDWant: "auto:any", // should be "auto:any" for compatibility with existing clients
|
||||
@ -3645,10 +3649,10 @@ func TestApplySysPolicy(t *testing.T) {
|
||||
stringPolicies map[pkey.Key]string
|
||||
}{
|
||||
{
|
||||
name: "empty prefs without policies",
|
||||
name: "empty-prefs-no-policies",
|
||||
},
|
||||
{
|
||||
name: "prefs set without policies",
|
||||
name: "prefs-set-no-policies",
|
||||
prefs: ipn.Prefs{
|
||||
ControlURL: "1",
|
||||
ShieldsUp: true,
|
||||
@ -3667,7 +3671,7 @@ func TestApplySysPolicy(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty prefs with policies",
|
||||
name: "empty-prefs-with-policies",
|
||||
wantPrefs: ipn.Prefs{
|
||||
ControlURL: "1",
|
||||
ShieldsUp: true,
|
||||
@ -3687,7 +3691,7 @@ func TestApplySysPolicy(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "prefs set with matching policies",
|
||||
name: "prefs-set-matching-policies",
|
||||
prefs: ipn.Prefs{
|
||||
ControlURL: "1",
|
||||
ShieldsUp: true,
|
||||
@ -3708,7 +3712,7 @@ func TestApplySysPolicy(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "prefs set with conflicting policies",
|
||||
name: "prefs-set-conflicting-policies",
|
||||
prefs: ipn.Prefs{
|
||||
ControlURL: "1",
|
||||
ShieldsUp: true,
|
||||
@ -3736,7 +3740,7 @@ func TestApplySysPolicy(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "prefs set with neutral policies",
|
||||
name: "prefs-set-neutral-policies",
|
||||
prefs: ipn.Prefs{
|
||||
ControlURL: "1",
|
||||
ShieldsUp: true,
|
||||
@ -3772,7 +3776,7 @@ func TestApplySysPolicy(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "enable AutoUpdate apply does not unset check",
|
||||
name: "enable-apply-keeps-check",
|
||||
prefs: ipn.Prefs{
|
||||
AutoUpdate: ipn.AutoUpdatePrefs{
|
||||
Check: true,
|
||||
@ -3791,7 +3795,7 @@ func TestApplySysPolicy(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "disable AutoUpdate apply does not unset check",
|
||||
name: "disable-apply-keeps-check",
|
||||
prefs: ipn.Prefs{
|
||||
AutoUpdate: ipn.AutoUpdatePrefs{
|
||||
Check: true,
|
||||
@ -3810,7 +3814,7 @@ func TestApplySysPolicy(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "enable AutoUpdate check does not unset apply",
|
||||
name: "enable-check-keeps-apply",
|
||||
prefs: ipn.Prefs{
|
||||
AutoUpdate: ipn.AutoUpdatePrefs{
|
||||
Check: false,
|
||||
@ -3829,7 +3833,7 @@ func TestApplySysPolicy(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "disable AutoUpdate check does not unset apply",
|
||||
name: "disable-check-keeps-apply",
|
||||
prefs: ipn.Prefs{
|
||||
AutoUpdate: ipn.AutoUpdatePrefs{
|
||||
Check: true,
|
||||
@ -3879,7 +3883,7 @@ func TestApplySysPolicy(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("status update", func(t *testing.T) {
|
||||
t.Run("status-update", func(t *testing.T) {
|
||||
// Profile manager fills in blank ControlURL but it's not set
|
||||
// in most test cases to avoid cluttering them, so adjust for
|
||||
// that.
|
||||
@ -3919,75 +3923,75 @@ func TestPreferencePolicyInfo(t *testing.T) {
|
||||
policyError error
|
||||
}{
|
||||
{
|
||||
name: "force enable modify",
|
||||
name: "force-enable-modify",
|
||||
initialValue: false,
|
||||
wantValue: true,
|
||||
wantChange: true,
|
||||
policyValue: "always",
|
||||
},
|
||||
{
|
||||
name: "force enable unchanged",
|
||||
name: "force-enable-unchanged",
|
||||
initialValue: true,
|
||||
wantValue: true,
|
||||
policyValue: "always",
|
||||
},
|
||||
{
|
||||
name: "force disable modify",
|
||||
name: "force-disable-modify",
|
||||
initialValue: true,
|
||||
wantValue: false,
|
||||
wantChange: true,
|
||||
policyValue: "never",
|
||||
},
|
||||
{
|
||||
name: "force disable unchanged",
|
||||
name: "force-disable-unchanged",
|
||||
initialValue: false,
|
||||
wantValue: false,
|
||||
policyValue: "never",
|
||||
},
|
||||
{
|
||||
name: "unforced enabled",
|
||||
name: "unforced-enabled",
|
||||
initialValue: true,
|
||||
wantValue: true,
|
||||
policyValue: "user-decides",
|
||||
},
|
||||
{
|
||||
name: "unforced disabled",
|
||||
name: "unforced-disabled",
|
||||
initialValue: false,
|
||||
wantValue: false,
|
||||
policyValue: "user-decides",
|
||||
},
|
||||
{
|
||||
name: "blank enabled",
|
||||
name: "blank-enabled",
|
||||
initialValue: true,
|
||||
wantValue: true,
|
||||
policyValue: "",
|
||||
},
|
||||
{
|
||||
name: "blank disabled",
|
||||
name: "blank-disabled",
|
||||
initialValue: false,
|
||||
wantValue: false,
|
||||
policyValue: "",
|
||||
},
|
||||
{
|
||||
name: "unset enabled",
|
||||
name: "unset-enabled",
|
||||
initialValue: true,
|
||||
wantValue: true,
|
||||
policyError: syspolicy.ErrNoSuchKey,
|
||||
},
|
||||
{
|
||||
name: "unset disabled",
|
||||
name: "unset-disabled",
|
||||
initialValue: false,
|
||||
wantValue: false,
|
||||
policyError: syspolicy.ErrNoSuchKey,
|
||||
},
|
||||
{
|
||||
name: "error enabled",
|
||||
name: "error-enabled",
|
||||
initialValue: true,
|
||||
wantValue: true,
|
||||
policyError: errors.New("test error"),
|
||||
},
|
||||
{
|
||||
name: "error disabled",
|
||||
name: "error-disabled",
|
||||
initialValue: false,
|
||||
wantValue: false,
|
||||
policyError: errors.New("test error"),
|
||||
@ -4113,53 +4117,62 @@ func TestOnTailnetDefaultAutoUpdate(t *testing.T) {
|
||||
func TestTCPHandlerForDst(t *testing.T) {
|
||||
b := newTestBackend(t)
|
||||
tests := []struct {
|
||||
name string
|
||||
desc string
|
||||
dst string
|
||||
intercept bool
|
||||
}{
|
||||
{
|
||||
name: "100_100_100_100-port80",
|
||||
desc: "intercept port 80 (Web UI) on quad100 IPv4",
|
||||
dst: "100.100.100.100:80",
|
||||
intercept: true,
|
||||
},
|
||||
{
|
||||
name: "fd7a-115c-a1e0--53-port80",
|
||||
desc: "intercept port 80 (Web UI) on quad100 IPv6",
|
||||
dst: "[fd7a:115c:a1e0::53]:80",
|
||||
intercept: true,
|
||||
},
|
||||
{
|
||||
name: "100_100_103_100-port80",
|
||||
desc: "don't intercept port 80 on local ip",
|
||||
dst: "100.100.103.100:80",
|
||||
intercept: false,
|
||||
},
|
||||
{
|
||||
name: "fd7a-115c-a1e0--53-port8080",
|
||||
desc: "intercept port 8080 (Taildrive) on quad100 IPv4",
|
||||
dst: "[fd7a:115c:a1e0::53]:8080",
|
||||
intercept: true,
|
||||
},
|
||||
{
|
||||
name: "100_100_103_100-port8080",
|
||||
desc: "don't intercept port 8080 on local ip",
|
||||
dst: "100.100.103.100:8080",
|
||||
intercept: false,
|
||||
},
|
||||
{
|
||||
name: "100_100_100_100-port9080",
|
||||
desc: "don't intercept port 9080 on quad100 IPv4",
|
||||
dst: "100.100.100.100:9080",
|
||||
intercept: false,
|
||||
},
|
||||
{
|
||||
name: "fd7a-115c-a1e0--53-port9080",
|
||||
desc: "don't intercept port 9080 on quad100 IPv6",
|
||||
dst: "[fd7a:115c:a1e0::53]:9080",
|
||||
intercept: false,
|
||||
},
|
||||
{
|
||||
name: "100_100_103_100-port9080",
|
||||
desc: "don't intercept port 9080 on local ip",
|
||||
dst: "100.100.103.100:9080",
|
||||
intercept: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.dst, func(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Log(tt.desc)
|
||||
src := netip.MustParseAddrPort("100.100.102.100:51234")
|
||||
h, _ := b.TCPHandlerForDst(src, netip.MustParseAddrPort(tt.dst))
|
||||
@ -4258,122 +4271,146 @@ func TestTCPHandlerForDstWithVIPService(t *testing.T) {
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
desc string
|
||||
dst string
|
||||
intercept bool
|
||||
}{
|
||||
{
|
||||
name: "100_100_100_100-port80",
|
||||
desc: "intercept port 80 (Web UI) on quad100 IPv4",
|
||||
dst: "100.100.100.100:80",
|
||||
intercept: true,
|
||||
},
|
||||
{
|
||||
name: "fd7a-115c-a1e0--53-port80",
|
||||
desc: "intercept port 80 (Web UI) on quad100 IPv6",
|
||||
dst: "[fd7a:115c:a1e0::53]:80",
|
||||
intercept: true,
|
||||
},
|
||||
{
|
||||
name: "100_100_103_100-port80",
|
||||
desc: "don't intercept port 80 on local ip",
|
||||
dst: "100.100.103.100:80",
|
||||
intercept: false,
|
||||
},
|
||||
{
|
||||
name: "100_100_100_100-port8080",
|
||||
desc: "intercept port 8080 (Taildrive) on quad100 IPv4",
|
||||
dst: "100.100.100.100:8080",
|
||||
intercept: true,
|
||||
},
|
||||
{
|
||||
name: "fd7a-115c-a1e0--53-port8080",
|
||||
desc: "intercept port 8080 (Taildrive) on quad100 IPv6",
|
||||
dst: "[fd7a:115c:a1e0::53]:8080",
|
||||
intercept: true,
|
||||
},
|
||||
{
|
||||
name: "100_100_103_100-port8080",
|
||||
desc: "don't intercept port 8080 on local ip",
|
||||
dst: "100.100.103.100:8080",
|
||||
intercept: false,
|
||||
},
|
||||
{
|
||||
name: "100_100_100_100-port9080",
|
||||
desc: "don't intercept port 9080 on quad100 IPv4",
|
||||
dst: "100.100.100.100:9080",
|
||||
intercept: false,
|
||||
},
|
||||
{
|
||||
name: "fd7a-115c-a1e0--53-port9080",
|
||||
desc: "don't intercept port 9080 on quad100 IPv6",
|
||||
dst: "[fd7a:115c:a1e0::53]:9080",
|
||||
intercept: false,
|
||||
},
|
||||
{
|
||||
name: "100_100_103_100-port9080",
|
||||
desc: "don't intercept port 9080 on local ip",
|
||||
dst: "100.100.103.100:9080",
|
||||
intercept: false,
|
||||
},
|
||||
// VIP service destinations
|
||||
{
|
||||
name: "100_101_101_101-port882",
|
||||
desc: "intercept port 882 (HTTP) on service foo IPv4",
|
||||
dst: "100.101.101.101:882",
|
||||
intercept: true,
|
||||
},
|
||||
{
|
||||
name: "fd7a-115c-a1e0-ab12-4843-cd96-6565-6565-port882",
|
||||
desc: "intercept port 882 (HTTP) on service foo IPv6",
|
||||
dst: "[fd7a:115c:a1e0:ab12:4843:cd96:6565:6565]:882",
|
||||
intercept: true,
|
||||
},
|
||||
{
|
||||
name: "100_101_101_101-port883",
|
||||
desc: "intercept port 883 (HTTPS) on service foo IPv4",
|
||||
dst: "100.101.101.101:883",
|
||||
intercept: true,
|
||||
},
|
||||
{
|
||||
name: "fd7a-115c-a1e0-ab12-4843-cd96-6565-6565-port883",
|
||||
desc: "intercept port 883 (HTTPS) on service foo IPv6",
|
||||
dst: "[fd7a:115c:a1e0:ab12:4843:cd96:6565:6565]:883",
|
||||
intercept: true,
|
||||
},
|
||||
{
|
||||
name: "100_99_99_99-port990",
|
||||
desc: "intercept port 990 (TCPForward) on service bar IPv4",
|
||||
dst: "100.99.99.99:990",
|
||||
intercept: true,
|
||||
},
|
||||
{
|
||||
name: "fd7a-115c-a1e0-ab12-4843-cd96-626b-628b-port990",
|
||||
desc: "intercept port 990 (TCPForward) on service bar IPv6",
|
||||
dst: "[fd7a:115c:a1e0:ab12:4843:cd96:626b:628b]:990",
|
||||
intercept: true,
|
||||
},
|
||||
{
|
||||
name: "100_99_99_99-port990-terminateTLS",
|
||||
desc: "intercept port 991 (TCPForward with TerminateTLS) on service bar IPv4",
|
||||
dst: "100.99.99.99:990",
|
||||
intercept: true,
|
||||
},
|
||||
{
|
||||
name: "fd7a-115c-a1e0-ab12-4843-cd96-626b-628b-port990-terminateTLS",
|
||||
desc: "intercept port 991 (TCPForward with TerminateTLS) on service bar IPv6",
|
||||
dst: "[fd7a:115c:a1e0:ab12:4843:cd96:626b:628b]:990",
|
||||
intercept: true,
|
||||
},
|
||||
{
|
||||
name: "100_101_101_101-port4444",
|
||||
desc: "don't intercept port 4444 on service foo IPv4",
|
||||
dst: "100.101.101.101:4444",
|
||||
intercept: false,
|
||||
},
|
||||
{
|
||||
name: "fd7a-115c-a1e0-ab12-4843-cd96-6565-6565-port4444",
|
||||
desc: "don't intercept port 4444 on service foo IPv6",
|
||||
dst: "[fd7a:115c:a1e0:ab12:4843:cd96:6565:6565]:4444",
|
||||
intercept: false,
|
||||
},
|
||||
{
|
||||
name: "100_22_22_22-port883",
|
||||
desc: "don't intercept port 600 on unknown service IPv4",
|
||||
dst: "100.22.22.22:883",
|
||||
intercept: false,
|
||||
},
|
||||
{
|
||||
name: "fd7a-115c-a1e0-ab12-4843-cd96-626b-628b-port883",
|
||||
desc: "don't intercept port 600 on unknown service IPv6",
|
||||
dst: "[fd7a:115c:a1e0:ab12:4843:cd96:626b:628b]:883",
|
||||
intercept: false,
|
||||
},
|
||||
{
|
||||
name: "100_133_133_133-port600",
|
||||
desc: "don't intercept port 600 (HTTPS) on service baz IPv4",
|
||||
dst: "100.133.133.133:600",
|
||||
intercept: false,
|
||||
},
|
||||
{
|
||||
name: "fd7a-115c-a1e0-ab12-4843-cd96-8585-8585-port600",
|
||||
desc: "don't intercept port 600 (HTTPS) on service baz IPv6",
|
||||
dst: "[fd7a:115c:a1e0:ab12:4843:cd96:8585:8585]:600",
|
||||
intercept: false,
|
||||
@ -4381,7 +4418,7 @@ func TestTCPHandlerForDstWithVIPService(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.dst, func(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Log(tt.desc)
|
||||
src := netip.MustParseAddrPort("100.100.102.100:51234")
|
||||
h, _ := b.TCPHandlerForDst(src, netip.MustParseAddrPort(tt.dst))
|
||||
@ -4664,14 +4701,14 @@ func TestRoundTraffic(t *testing.T) {
|
||||
bytes int64
|
||||
want float64
|
||||
}{
|
||||
{name: "under 5 bytes", bytes: 4, want: 4},
|
||||
{name: "under 1000 bytes", bytes: 987, want: 990},
|
||||
{name: "under 10_000 bytes", bytes: 8875, want: 8900},
|
||||
{name: "under 100_000 bytes", bytes: 77777, want: 78000},
|
||||
{name: "under 1_000_000 bytes", bytes: 666523, want: 670000},
|
||||
{name: "under 10_000_000 bytes", bytes: 22556677, want: 23000000},
|
||||
{name: "under 1_000_000_000 bytes", bytes: 1234234234, want: 1200000000},
|
||||
{name: "under 1_000_000_000 bytes", bytes: 123423423499, want: 123400000000},
|
||||
{name: "under-5B", bytes: 4, want: 4},
|
||||
{name: "under-1000B", bytes: 987, want: 990},
|
||||
{name: "under-10000B", bytes: 8875, want: 8900},
|
||||
{name: "under-100000B", bytes: 77777, want: 78000},
|
||||
{name: "under-1000000B", bytes: 666523, want: 670000},
|
||||
{name: "under-10000000B", bytes: 22556677, want: 23000000},
|
||||
{name: "under-1000000000B", bytes: 1234234234, want: 1200000000},
|
||||
{name: "over-1000000000B", bytes: 123423423499, want: 123400000000},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
@ -5033,7 +5070,7 @@ func TestSuggestExitNode(t *testing.T) {
|
||||
wantError error
|
||||
}{
|
||||
{
|
||||
name: "2 exit nodes in same region",
|
||||
name: "2-exits-same-region",
|
||||
lastReport: preferred1Report,
|
||||
netMap: &netmap.NetworkMap{
|
||||
SelfNode: selfNode.View(),
|
||||
@ -5051,7 +5088,7 @@ func TestSuggestExitNode(t *testing.T) {
|
||||
wantID: "stable1",
|
||||
},
|
||||
{
|
||||
name: "2 exit nodes different regions unknown latency",
|
||||
name: "2-exits-different-regions-unknown-latency",
|
||||
lastReport: noLatency1Report,
|
||||
netMap: defaultNetmap,
|
||||
wantRegions: []int{1, 3}, // the only regions with peers
|
||||
@ -5060,7 +5097,7 @@ func TestSuggestExitNode(t *testing.T) {
|
||||
wantID: "stable2",
|
||||
},
|
||||
{
|
||||
name: "2 derp based exit nodes, different regions, equal latency",
|
||||
name: "2-derp-exits-different-regions-equal-latency",
|
||||
lastReport: &netcheck.Report{
|
||||
RegionLatency: map[int]time.Duration{
|
||||
1: 10,
|
||||
@ -5083,7 +5120,7 @@ func TestSuggestExitNode(t *testing.T) {
|
||||
wantID: "stable1",
|
||||
},
|
||||
{
|
||||
name: "mullvad nodes, no derp based exit nodes",
|
||||
name: "mullvad-no-derp-exits",
|
||||
lastReport: noLatency1Report,
|
||||
netMap: locationNetmap,
|
||||
wantID: "stable5",
|
||||
@ -5091,7 +5128,7 @@ func TestSuggestExitNode(t *testing.T) {
|
||||
wantName: "Dallas",
|
||||
},
|
||||
{
|
||||
name: "nearby mullvad nodes with different priorities",
|
||||
name: "nearby-mullvad-different-priorities",
|
||||
lastReport: noLatency1Report,
|
||||
netMap: &netmap.NetworkMap{
|
||||
SelfNode: selfNode.View(),
|
||||
@ -5107,7 +5144,7 @@ func TestSuggestExitNode(t *testing.T) {
|
||||
wantName: "Fort Worth",
|
||||
},
|
||||
{
|
||||
name: "nearby mullvad nodes with same priorities",
|
||||
name: "nearby-mullvad-same-priorities",
|
||||
lastReport: noLatency1Report,
|
||||
netMap: &netmap.NetworkMap{
|
||||
SelfNode: selfNode.View(),
|
||||
@ -5124,7 +5161,7 @@ func TestSuggestExitNode(t *testing.T) {
|
||||
wantName: "Dallas",
|
||||
},
|
||||
{
|
||||
name: "mullvad nodes, remaining node is not in preferred derp",
|
||||
name: "mullvad-remaining-not-in-preferred-derp",
|
||||
lastReport: noLatency1Report,
|
||||
netMap: &netmap.NetworkMap{
|
||||
SelfNode: selfNode.View(),
|
||||
@ -5140,7 +5177,7 @@ func TestSuggestExitNode(t *testing.T) {
|
||||
wantName: "peer4",
|
||||
},
|
||||
{
|
||||
name: "no peers",
|
||||
name: "no-peers",
|
||||
lastReport: noLatency1Report,
|
||||
netMap: &netmap.NetworkMap{
|
||||
SelfNode: selfNode.View(),
|
||||
@ -5148,13 +5185,13 @@ func TestSuggestExitNode(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "nil report",
|
||||
name: "nil-report",
|
||||
lastReport: nil,
|
||||
netMap: largeNetmap,
|
||||
wantError: ErrNoPreferredDERP,
|
||||
},
|
||||
{
|
||||
name: "no preferred derp region",
|
||||
name: "no-preferred-derp-region",
|
||||
lastReport: preferredNoneReport,
|
||||
netMap: &netmap.NetworkMap{
|
||||
SelfNode: selfNode.View(),
|
||||
@ -5163,13 +5200,13 @@ func TestSuggestExitNode(t *testing.T) {
|
||||
wantError: ErrNoPreferredDERP,
|
||||
},
|
||||
{
|
||||
name: "nil netmap",
|
||||
name: "nil-netmap",
|
||||
lastReport: noLatency1Report,
|
||||
netMap: nil,
|
||||
wantError: ErrNoPreferredDERP,
|
||||
},
|
||||
{
|
||||
name: "nil derpmap",
|
||||
name: "nil-derpmap",
|
||||
lastReport: noLatency1Report,
|
||||
netMap: &netmap.NetworkMap{
|
||||
SelfNode: selfNode.View(),
|
||||
@ -5181,7 +5218,7 @@ func TestSuggestExitNode(t *testing.T) {
|
||||
wantError: ErrNoPreferredDERP,
|
||||
},
|
||||
{
|
||||
name: "missing suggestion capability",
|
||||
name: "missing-suggestion-capability",
|
||||
lastReport: noLatency1Report,
|
||||
netMap: &netmap.NetworkMap{
|
||||
SelfNode: selfNode.View(),
|
||||
@ -5193,7 +5230,7 @@ func TestSuggestExitNode(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "prefer last node",
|
||||
name: "prefer-last-node",
|
||||
lastReport: preferred1Report,
|
||||
netMap: &netmap.NetworkMap{
|
||||
SelfNode: selfNode.View(),
|
||||
@ -5212,7 +5249,7 @@ func TestSuggestExitNode(t *testing.T) {
|
||||
wantID: "stable2",
|
||||
},
|
||||
{
|
||||
name: "found better derp node",
|
||||
name: "found-better-derp-node",
|
||||
lastSuggestion: "stable3",
|
||||
lastReport: preferred1Report,
|
||||
netMap: defaultNetmap,
|
||||
@ -5220,7 +5257,7 @@ func TestSuggestExitNode(t *testing.T) {
|
||||
wantName: "peer2",
|
||||
},
|
||||
{
|
||||
name: "prefer last mullvad node",
|
||||
name: "prefer-last-mullvad-node",
|
||||
lastSuggestion: "stable2",
|
||||
lastReport: preferred1Report,
|
||||
netMap: &netmap.NetworkMap{
|
||||
@ -5238,7 +5275,7 @@ func TestSuggestExitNode(t *testing.T) {
|
||||
wantLocation: dallas.View(),
|
||||
},
|
||||
{
|
||||
name: "prefer better mullvad node",
|
||||
name: "prefer-better-mullvad-node",
|
||||
lastSuggestion: "stable2",
|
||||
lastReport: preferred1Report,
|
||||
netMap: &netmap.NetworkMap{
|
||||
@ -5256,7 +5293,7 @@ func TestSuggestExitNode(t *testing.T) {
|
||||
wantLocation: fortWorth.View(),
|
||||
},
|
||||
{
|
||||
name: "large netmap",
|
||||
name: "large-netmap",
|
||||
lastReport: preferred1Report,
|
||||
netMap: largeNetmap,
|
||||
wantNodes: []tailcfg.StableNodeID{"stable1", "stable2"},
|
||||
@ -5264,13 +5301,13 @@ func TestSuggestExitNode(t *testing.T) {
|
||||
wantName: "peer2",
|
||||
},
|
||||
{
|
||||
name: "no allowed suggestions",
|
||||
name: "no-allowed-suggestions",
|
||||
lastReport: preferred1Report,
|
||||
netMap: largeNetmap,
|
||||
allowPolicy: []tailcfg.StableNodeID{},
|
||||
},
|
||||
{
|
||||
name: "only derp suggestions",
|
||||
name: "only-derp-suggestions",
|
||||
lastReport: preferred1Report,
|
||||
netMap: largeNetmap,
|
||||
allowPolicy: []tailcfg.StableNodeID{"stable1", "stable2", "stable3"},
|
||||
@ -5279,7 +5316,7 @@ func TestSuggestExitNode(t *testing.T) {
|
||||
wantName: "peer2",
|
||||
},
|
||||
{
|
||||
name: "only mullvad suggestions",
|
||||
name: "only-mullvad-suggestions",
|
||||
lastReport: preferred1Report,
|
||||
netMap: largeNetmap,
|
||||
allowPolicy: []tailcfg.StableNodeID{"stable5", "stable6", "stable7"},
|
||||
@ -5288,7 +5325,7 @@ func TestSuggestExitNode(t *testing.T) {
|
||||
wantLocation: fortWorth.View(),
|
||||
},
|
||||
{
|
||||
name: "only worst derp",
|
||||
name: "only-worst-derp",
|
||||
lastReport: preferred1Report,
|
||||
netMap: largeNetmap,
|
||||
allowPolicy: []tailcfg.StableNodeID{"stable3"},
|
||||
@ -5296,7 +5333,7 @@ func TestSuggestExitNode(t *testing.T) {
|
||||
wantName: "peer3",
|
||||
},
|
||||
{
|
||||
name: "only worst mullvad",
|
||||
name: "only-worst-mullvad",
|
||||
lastReport: preferred1Report,
|
||||
netMap: largeNetmap,
|
||||
allowPolicy: []tailcfg.StableNodeID{"stable6"},
|
||||
@ -5306,7 +5343,7 @@ func TestSuggestExitNode(t *testing.T) {
|
||||
},
|
||||
{
|
||||
// Regression test for https://github.com/tailscale/tailscale/issues/17661
|
||||
name: "exit nodes with no home DERP, randomly selected",
|
||||
name: "exits-no-home-DERP-random-selection",
|
||||
lastReport: &netcheck.Report{
|
||||
RegionLatency: map[int]time.Duration{
|
||||
1: 10,
|
||||
@ -5388,7 +5425,7 @@ func TestSuggestExitNodePickWeighted(t *testing.T) {
|
||||
wantIDs []tailcfg.StableNodeID
|
||||
}{
|
||||
{
|
||||
name: "different priorities",
|
||||
name: "different-priorities",
|
||||
candidates: []tailcfg.NodeView{
|
||||
makePeer(2, withExitRoutes(), withLocation(location20.View())),
|
||||
makePeer(3, withExitRoutes(), withLocation(location10.View())),
|
||||
@ -5396,7 +5433,7 @@ func TestSuggestExitNodePickWeighted(t *testing.T) {
|
||||
wantIDs: []tailcfg.StableNodeID{"stable2"},
|
||||
},
|
||||
{
|
||||
name: "same priorities",
|
||||
name: "same-priorities",
|
||||
candidates: []tailcfg.NodeView{
|
||||
makePeer(2, withExitRoutes(), withLocation(location10.View())),
|
||||
makePeer(3, withExitRoutes(), withLocation(location10.View())),
|
||||
@ -5404,11 +5441,11 @@ func TestSuggestExitNodePickWeighted(t *testing.T) {
|
||||
wantIDs: []tailcfg.StableNodeID{"stable2", "stable3"},
|
||||
},
|
||||
{
|
||||
name: "<1 candidates",
|
||||
name: "lt1-candidates",
|
||||
candidates: []tailcfg.NodeView{},
|
||||
},
|
||||
{
|
||||
name: "1 candidate",
|
||||
name: "1-candidate",
|
||||
candidates: []tailcfg.NodeView{
|
||||
makePeer(2, withExitRoutes(), withLocation(location20.View())),
|
||||
},
|
||||
@ -5444,7 +5481,7 @@ func TestSuggestExitNodeLongLatDistance(t *testing.T) {
|
||||
want float64
|
||||
}{
|
||||
{
|
||||
name: "zero values",
|
||||
name: "zero-values",
|
||||
fromLat: 0,
|
||||
fromLong: 0,
|
||||
toLat: 0,
|
||||
@ -5452,7 +5489,7 @@ func TestSuggestExitNodeLongLatDistance(t *testing.T) {
|
||||
want: 0,
|
||||
},
|
||||
{
|
||||
name: "valid values",
|
||||
name: "valid-values",
|
||||
fromLat: 40.73061,
|
||||
fromLong: -73.935242,
|
||||
toLat: 37.3382082,
|
||||
@ -5460,7 +5497,8 @@ func TestSuggestExitNodeLongLatDistance(t *testing.T) {
|
||||
want: 4117266.873301274,
|
||||
},
|
||||
{
|
||||
name: "valid values, locations in north and south of equator",
|
||||
// Locations in north and south of equator.
|
||||
name: "valid-values-cross-equator",
|
||||
fromLat: 40.73061,
|
||||
fromLong: -73.935242,
|
||||
toLat: -33.861481,
|
||||
@ -5865,13 +5903,13 @@ func TestMinLatencyDERPregion(t *testing.T) {
|
||||
wantRegion int
|
||||
}{
|
||||
{
|
||||
name: "regions, no latency values",
|
||||
name: "regions-no-latency",
|
||||
regions: []int{1, 2, 3},
|
||||
wantRegion: 0,
|
||||
report: &netcheck.Report{},
|
||||
},
|
||||
{
|
||||
name: "regions, different latency values",
|
||||
name: "regions-different-latency",
|
||||
regions: []int{1, 2, 3},
|
||||
wantRegion: 2,
|
||||
report: &netcheck.Report{
|
||||
@ -5883,7 +5921,7 @@ func TestMinLatencyDERPregion(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "regions, same values",
|
||||
name: "regions-same-latency",
|
||||
regions: []int{1, 2, 3},
|
||||
wantRegion: 1,
|
||||
report: &netcheck.Report{
|
||||
@ -6030,7 +6068,7 @@ func TestFillAllowedSuggestions(t *testing.T) {
|
||||
want: []tailcfg.StableNodeID{"one", "three", "four", "two"}, // order should not matter
|
||||
},
|
||||
{
|
||||
name: "preserve case",
|
||||
name: "preserve-case",
|
||||
allowPolicy: []string{"ABC", "def", "gHiJ"},
|
||||
want: []tailcfg.StableNodeID{"ABC", "def", "gHiJ"},
|
||||
},
|
||||
@ -6184,61 +6222,61 @@ func TestNotificationTargetMatch(t *testing.T) {
|
||||
wantMatch: false,
|
||||
},
|
||||
{
|
||||
name: "FilterByUID+CID/Nil",
|
||||
name: "FilterByUID-CID/Nil",
|
||||
target: notificationTarget{userID: "S-1-5-21-1-2-3-4"},
|
||||
actor: nil,
|
||||
wantMatch: false,
|
||||
},
|
||||
{
|
||||
name: "FilterByUID+CID/NoUID/NoCID",
|
||||
name: "FilterByUID-CID/NoUID/NoCID",
|
||||
target: notificationTarget{userID: "S-1-5-21-1-2-3-4", clientID: ipnauth.ClientIDFrom("A")},
|
||||
actor: &ipnauth.TestActor{},
|
||||
wantMatch: false,
|
||||
},
|
||||
{
|
||||
name: "FilterByUID+CID/NoUID/SameCID",
|
||||
name: "FilterByUID-CID/NoUID/SameCID",
|
||||
target: notificationTarget{userID: "S-1-5-21-1-2-3-4", clientID: ipnauth.ClientIDFrom("A")},
|
||||
actor: &ipnauth.TestActor{CID: ipnauth.ClientIDFrom("A")},
|
||||
wantMatch: false,
|
||||
},
|
||||
{
|
||||
name: "FilterByUID+CID/NoUID/DifferentCID",
|
||||
name: "FilterByUID-CID/NoUID/DifferentCID",
|
||||
target: notificationTarget{userID: "S-1-5-21-1-2-3-4", clientID: ipnauth.ClientIDFrom("A")},
|
||||
actor: &ipnauth.TestActor{CID: ipnauth.ClientIDFrom("B")},
|
||||
wantMatch: false,
|
||||
},
|
||||
{
|
||||
name: "FilterByUID+CID/SameUID/NoCID",
|
||||
name: "FilterByUID-CID/SameUID/NoCID",
|
||||
target: notificationTarget{userID: "S-1-5-21-1-2-3-4", clientID: ipnauth.ClientIDFrom("A")},
|
||||
actor: &ipnauth.TestActor{UID: "S-1-5-21-1-2-3-4"},
|
||||
wantMatch: false,
|
||||
},
|
||||
{
|
||||
name: "FilterByUID+CID/SameUID/SameCID",
|
||||
name: "FilterByUID-CID/SameUID/SameCID",
|
||||
target: notificationTarget{userID: "S-1-5-21-1-2-3-4", clientID: ipnauth.ClientIDFrom("A")},
|
||||
actor: &ipnauth.TestActor{UID: "S-1-5-21-1-2-3-4", CID: ipnauth.ClientIDFrom("A")},
|
||||
wantMatch: true,
|
||||
},
|
||||
{
|
||||
name: "FilterByUID+CID/SameUID/DifferentCID",
|
||||
name: "FilterByUID-CID/SameUID/DifferentCID",
|
||||
target: notificationTarget{userID: "S-1-5-21-1-2-3-4", clientID: ipnauth.ClientIDFrom("A")},
|
||||
actor: &ipnauth.TestActor{UID: "S-1-5-21-1-2-3-4", CID: ipnauth.ClientIDFrom("B")},
|
||||
wantMatch: false,
|
||||
},
|
||||
{
|
||||
name: "FilterByUID+CID/DifferentUID/NoCID",
|
||||
name: "FilterByUID-CID/DifferentUID/NoCID",
|
||||
target: notificationTarget{userID: "S-1-5-21-1-2-3-4", clientID: ipnauth.ClientIDFrom("A")},
|
||||
actor: &ipnauth.TestActor{UID: "S-1-5-21-5-6-7-8"},
|
||||
wantMatch: false,
|
||||
},
|
||||
{
|
||||
name: "FilterByUID+CID/DifferentUID/SameCID",
|
||||
name: "FilterByUID-CID/DifferentUID/SameCID",
|
||||
target: notificationTarget{userID: "S-1-5-21-1-2-3-4", clientID: ipnauth.ClientIDFrom("A")},
|
||||
actor: &ipnauth.TestActor{UID: "S-1-5-21-5-6-7-8", CID: ipnauth.ClientIDFrom("A")},
|
||||
wantMatch: false,
|
||||
},
|
||||
{
|
||||
name: "FilterByUID+CID/DifferentUID/DifferentCID",
|
||||
name: "FilterByUID-CID/DifferentUID/DifferentCID",
|
||||
target: notificationTarget{userID: "S-1-5-21-1-2-3-4", clientID: ipnauth.ClientIDFrom("A")},
|
||||
actor: &ipnauth.TestActor{UID: "S-1-5-21-5-6-7-8", CID: ipnauth.ClientIDFrom("B")},
|
||||
wantMatch: false,
|
||||
|
||||
@ -300,9 +300,9 @@ func TestTKASync(t *testing.T) {
|
||||
}
|
||||
|
||||
tcs := []tkaSyncScenario{
|
||||
{name: "up to date"},
|
||||
{name: "up-to-date"},
|
||||
{
|
||||
name: "control has an update",
|
||||
name: "control-has-an-update",
|
||||
controlAUMs: func(t *testing.T, a *tka.Authority, storage tka.Chonk, signer tka.Signer) []tka.AUM {
|
||||
b := a.NewUpdater(signer)
|
||||
if err := b.RemoveKey(someKey.MustID()); err != nil {
|
||||
@ -317,7 +317,7 @@ func TestTKASync(t *testing.T) {
|
||||
},
|
||||
{
|
||||
// AKA 'control data loss' scenario
|
||||
name: "node has an update",
|
||||
name: "node-has-an-update",
|
||||
nodeAUMs: func(t *testing.T, a *tka.Authority, storage tka.Chonk, signer tka.Signer) []tka.AUM {
|
||||
b := a.NewUpdater(signer)
|
||||
if err := b.RemoveKey(someKey.MustID()); err != nil {
|
||||
@ -332,7 +332,7 @@ func TestTKASync(t *testing.T) {
|
||||
},
|
||||
{
|
||||
// AKA 'control data loss + update in the meantime' scenario
|
||||
name: "node and control diverge",
|
||||
name: "node-and-control-diverge",
|
||||
controlAUMs: func(t *testing.T, a *tka.Authority, storage tka.Chonk, signer tka.Signer) []tka.AUM {
|
||||
b := a.NewUpdater(signer)
|
||||
if err := b.SetKeyMeta(someKey.MustID(), map[string]string{"ye": "swiggity"}); err != nil {
|
||||
@ -1020,7 +1020,7 @@ func TestTKAAffectedSigs(t *testing.T) {
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
"no error",
|
||||
"no-error",
|
||||
func() *tka.NodeKeySignature {
|
||||
sig, _ := signNodeKey(tailcfg.TKASignInfo{NodePublic: nodePriv.Public()}, nlPriv)
|
||||
return sig
|
||||
@ -1028,7 +1028,7 @@ func TestTKAAffectedSigs(t *testing.T) {
|
||||
"",
|
||||
},
|
||||
{
|
||||
"signature for different keyID",
|
||||
"signature-for-different-keyID",
|
||||
func() *tka.NodeKeySignature {
|
||||
sig, _ := signNodeKey(tailcfg.TKASignInfo{NodePublic: nodePriv.Public()}, untrustedKey)
|
||||
return sig
|
||||
@ -1036,7 +1036,7 @@ func TestTKAAffectedSigs(t *testing.T) {
|
||||
fmt.Sprintf("got signature with keyID %X from request for %X", untrustedKey.KeyID(), nlPriv.KeyID()),
|
||||
},
|
||||
{
|
||||
"invalid signature",
|
||||
"invalid-signature",
|
||||
func() *tka.NodeKeySignature {
|
||||
sig, _ := signNodeKey(tailcfg.TKASignInfo{NodePublic: nodePriv.Public()}, nlPriv)
|
||||
copy(sig.Signature, []byte{1, 2, 3, 4, 5, 6}) // overwrite with trash to invalid signature
|
||||
|
||||
@ -619,49 +619,49 @@ func TestServeHTTPProxyPath(t *testing.T) {
|
||||
wantRequestPath string
|
||||
}{
|
||||
{
|
||||
name: "/foo -> /foo, with mount point and path /foo",
|
||||
name: "foo-to-foo-mount-foo",
|
||||
mountPoint: "/foo",
|
||||
proxyPath: "/foo",
|
||||
requestPath: "/foo",
|
||||
wantRequestPath: "/foo",
|
||||
},
|
||||
{
|
||||
name: "/foo/ -> /foo/, with mount point and path /foo",
|
||||
name: "foo-slash-to-foo-slash-mount-foo",
|
||||
mountPoint: "/foo",
|
||||
proxyPath: "/foo",
|
||||
requestPath: "/foo/",
|
||||
wantRequestPath: "/foo/",
|
||||
},
|
||||
{
|
||||
name: "/foo -> /foo/, with mount point and path /foo/",
|
||||
name: "foo-to-foo-slash-mount-foo-slash",
|
||||
mountPoint: "/foo/",
|
||||
proxyPath: "/foo/",
|
||||
requestPath: "/foo",
|
||||
wantRequestPath: "/foo/",
|
||||
},
|
||||
{
|
||||
name: "/-> /, with mount point and path /",
|
||||
name: "root-to-root-mount-root",
|
||||
mountPoint: "/",
|
||||
proxyPath: "/",
|
||||
requestPath: "/",
|
||||
wantRequestPath: "/",
|
||||
},
|
||||
{
|
||||
name: "/foo -> /foo, with mount point and path /",
|
||||
name: "foo-to-foo-mount-root",
|
||||
mountPoint: "/",
|
||||
proxyPath: "/",
|
||||
requestPath: "/foo",
|
||||
wantRequestPath: "/foo",
|
||||
},
|
||||
{
|
||||
name: "/foo/bar -> /foo/bar, with mount point and path /foo",
|
||||
name: "foo-bar-to-foo-bar-mount-foo",
|
||||
mountPoint: "/foo",
|
||||
proxyPath: "/foo",
|
||||
requestPath: "/foo/bar",
|
||||
wantRequestPath: "/foo/bar",
|
||||
},
|
||||
{
|
||||
name: "/foo/bar/baz -> /foo/bar/baz, with mount point and path /foo",
|
||||
name: "foo-bar-baz-to-foo-bar-baz-mount-foo",
|
||||
mountPoint: "/foo",
|
||||
proxyPath: "/foo",
|
||||
requestPath: "/foo/bar/baz",
|
||||
@ -1457,7 +1457,7 @@ func TestValidateServeConfigUpdate(t *testing.T) {
|
||||
wantError bool
|
||||
}{
|
||||
{
|
||||
name: "empty existing config",
|
||||
name: "empty-existing-config",
|
||||
description: "should be able to update with empty existing config",
|
||||
existing: &ipn.ServeConfig{},
|
||||
incoming: &ipn.ServeConfig{
|
||||
@ -1468,7 +1468,7 @@ func TestValidateServeConfigUpdate(t *testing.T) {
|
||||
wantError: false,
|
||||
},
|
||||
{
|
||||
name: "no existing config",
|
||||
name: "no-existing-config",
|
||||
description: "should be able to update with no existing config",
|
||||
existing: nil,
|
||||
incoming: &ipn.ServeConfig{
|
||||
@ -1479,7 +1479,7 @@ func TestValidateServeConfigUpdate(t *testing.T) {
|
||||
wantError: false,
|
||||
},
|
||||
{
|
||||
name: "empty incoming config",
|
||||
name: "empty-incoming-config",
|
||||
description: "wiping config should work",
|
||||
existing: &ipn.ServeConfig{
|
||||
TCP: map[uint16]*ipn.TCPPortHandler{
|
||||
@ -1490,7 +1490,7 @@ func TestValidateServeConfigUpdate(t *testing.T) {
|
||||
wantError: false,
|
||||
},
|
||||
{
|
||||
name: "no incoming config",
|
||||
name: "no-incoming-config",
|
||||
description: "missing incoming config should not result in an error",
|
||||
existing: &ipn.ServeConfig{
|
||||
TCP: map[uint16]*ipn.TCPPortHandler{
|
||||
@ -1501,7 +1501,7 @@ func TestValidateServeConfigUpdate(t *testing.T) {
|
||||
wantError: false,
|
||||
},
|
||||
{
|
||||
name: "non-overlapping update",
|
||||
name: "non-overlapping-update",
|
||||
description: "non-overlapping update should work",
|
||||
existing: &ipn.ServeConfig{
|
||||
TCP: map[uint16]*ipn.TCPPortHandler{
|
||||
@ -1516,7 +1516,7 @@ func TestValidateServeConfigUpdate(t *testing.T) {
|
||||
wantError: false,
|
||||
},
|
||||
{
|
||||
name: "overwriting background port",
|
||||
name: "overwriting-background-port",
|
||||
description: "should be able to overwrite a background port",
|
||||
existing: &ipn.ServeConfig{
|
||||
TCP: map[uint16]*ipn.TCPPortHandler{
|
||||
@ -1535,7 +1535,7 @@ func TestValidateServeConfigUpdate(t *testing.T) {
|
||||
wantError: false,
|
||||
},
|
||||
{
|
||||
name: "broken existing config",
|
||||
name: "broken-existing-config",
|
||||
description: "broken existing config should not prevent new config updates",
|
||||
existing: &ipn.ServeConfig{
|
||||
TCP: map[uint16]*ipn.TCPPortHandler{
|
||||
@ -1573,7 +1573,7 @@ func TestValidateServeConfigUpdate(t *testing.T) {
|
||||
wantError: false,
|
||||
},
|
||||
{
|
||||
name: "services same port as background",
|
||||
name: "services-same-port-as-background",
|
||||
description: "services should be able to use the same port as background listeners",
|
||||
existing: &ipn.ServeConfig{
|
||||
TCP: map[uint16]*ipn.TCPPortHandler{
|
||||
@ -1592,7 +1592,7 @@ func TestValidateServeConfigUpdate(t *testing.T) {
|
||||
wantError: false,
|
||||
},
|
||||
{
|
||||
name: "services tun mode",
|
||||
name: "services-tun-mode",
|
||||
description: "TUN mode should be mutually exclusive with TCP or web handlers for new Services",
|
||||
existing: &ipn.ServeConfig{},
|
||||
incoming: &ipn.ServeConfig{
|
||||
@ -1608,7 +1608,7 @@ func TestValidateServeConfigUpdate(t *testing.T) {
|
||||
wantError: true,
|
||||
},
|
||||
{
|
||||
name: "new foreground listener",
|
||||
name: "new-foreground-listener",
|
||||
description: "new foreground listeners must be on open ports",
|
||||
existing: &ipn.ServeConfig{
|
||||
TCP: map[uint16]*ipn.TCPPortHandler{
|
||||
@ -1627,7 +1627,7 @@ func TestValidateServeConfigUpdate(t *testing.T) {
|
||||
wantError: true,
|
||||
},
|
||||
{
|
||||
name: "new background listener",
|
||||
name: "new-background-listener",
|
||||
description: "new background listers cannot overwrite foreground listeners",
|
||||
existing: &ipn.ServeConfig{
|
||||
Foreground: map[string]*ipn.ServeConfig{
|
||||
@ -1646,7 +1646,7 @@ func TestValidateServeConfigUpdate(t *testing.T) {
|
||||
wantError: true,
|
||||
},
|
||||
{
|
||||
name: "serve type overwrite",
|
||||
name: "serve-type-overwrite",
|
||||
description: "incoming configuration cannot change the serve type in use by a port",
|
||||
existing: &ipn.ServeConfig{
|
||||
TCP: map[uint16]*ipn.TCPPortHandler{
|
||||
@ -1665,7 +1665,7 @@ func TestValidateServeConfigUpdate(t *testing.T) {
|
||||
wantError: true,
|
||||
},
|
||||
{
|
||||
name: "serve type overwrite services",
|
||||
name: "serve-type-overwrite-services",
|
||||
description: "incoming Services configuration cannot change the serve type in use by a port",
|
||||
existing: &ipn.ServeConfig{
|
||||
Services: map[tailcfg.ServiceName]*ipn.ServiceConfig{
|
||||
@ -1692,7 +1692,7 @@ func TestValidateServeConfigUpdate(t *testing.T) {
|
||||
wantError: true,
|
||||
},
|
||||
{
|
||||
name: "tun mode with handlers",
|
||||
name: "tun-mode-with-handlers",
|
||||
description: "Services cannot enable TUN mode if L4 or L7 handlers already exist",
|
||||
existing: &ipn.ServeConfig{
|
||||
Services: map[tailcfg.ServiceName]*ipn.ServiceConfig{
|
||||
@ -1720,7 +1720,7 @@ func TestValidateServeConfigUpdate(t *testing.T) {
|
||||
wantError: true,
|
||||
},
|
||||
{
|
||||
name: "handlers with tun mode",
|
||||
name: "handlers-with-tun-mode",
|
||||
description: "Services cannot add L4 or L7 handlers if TUN mode is already enabled",
|
||||
existing: &ipn.ServeConfig{
|
||||
Services: map[tailcfg.ServiceName]*ipn.ServiceConfig{
|
||||
|
||||
@ -23,26 +23,30 @@ import (
|
||||
|
||||
func TestExpandProxyArgUnix(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
wantURL string
|
||||
wantInsecure bool
|
||||
}{
|
||||
{
|
||||
name: "unix-tmp-sock",
|
||||
input: "unix:/tmp/test.sock",
|
||||
wantURL: "unix:/tmp/test.sock",
|
||||
},
|
||||
{
|
||||
name: "unix-var-run-docker-sock",
|
||||
input: "unix:/var/run/docker.sock",
|
||||
wantURL: "unix:/var/run/docker.sock",
|
||||
},
|
||||
{
|
||||
name: "unix-relative-sock",
|
||||
input: "unix:./relative.sock",
|
||||
wantURL: "unix:./relative.sock",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.input, func(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
gotURL, gotInsecure := expandProxyArg(tt.input)
|
||||
if gotURL != tt.wantURL {
|
||||
t.Errorf("expandProxyArg(%q) url = %q, want %q", tt.input, gotURL, tt.wantURL)
|
||||
|
||||
@ -458,7 +458,7 @@ func TestPrefsFromBytesPreservesOldValues(t *testing.T) {
|
||||
want: Prefs{ControlURL: "https://foo", RouteAll: true},
|
||||
},
|
||||
{
|
||||
name: "opt.Bool", // test that we don't normalize it early
|
||||
name: "opt-Bool", // test that we don't normalize it early
|
||||
old: Prefs{Sync: "unset"},
|
||||
json: []byte(`{}`),
|
||||
want: Prefs{Sync: "unset"},
|
||||
@ -1236,13 +1236,13 @@ func TestParseAutoExitNodeString(t *testing.T) {
|
||||
wantExpr ExitNodeExpression
|
||||
}{
|
||||
{
|
||||
name: "empty expr",
|
||||
name: "empty-expr",
|
||||
exitNodeID: "",
|
||||
wantOk: false,
|
||||
wantExpr: "",
|
||||
},
|
||||
{
|
||||
name: "no auto prefix",
|
||||
name: "no-auto-prefix",
|
||||
exitNodeID: "foo",
|
||||
wantOk: false,
|
||||
wantExpr: "",
|
||||
@ -1260,13 +1260,13 @@ func TestParseAutoExitNodeString(t *testing.T) {
|
||||
wantExpr: "foo",
|
||||
},
|
||||
{
|
||||
name: "auto prefix but empty suffix",
|
||||
name: "auto-prefix-empty-suffix",
|
||||
exitNodeID: "auto:",
|
||||
wantOk: false,
|
||||
wantExpr: "",
|
||||
},
|
||||
{
|
||||
name: "auto prefix no colon",
|
||||
name: "auto-prefix-no-colon",
|
||||
exitNodeID: "auto",
|
||||
wantOk: false,
|
||||
wantExpr: "",
|
||||
|
||||
@ -283,11 +283,11 @@ func TestExpandProxyTargetDev(t *testing.T) {
|
||||
wantErr bool
|
||||
}{
|
||||
{name: "port-only", input: "8080", expected: "http://127.0.0.1:8080"},
|
||||
{name: "hostname+port", input: "localhost:8080", expected: "http://localhost:8080"},
|
||||
{name: "hostname-and-port", input: "localhost:8080", expected: "http://localhost:8080"},
|
||||
{name: "no-change", input: "http://127.0.0.1:8080", expected: "http://127.0.0.1:8080"},
|
||||
{name: "include-path", input: "http://127.0.0.1:8080/foo", expected: "http://127.0.0.1:8080/foo"},
|
||||
{name: "https-scheme", input: "https://localhost:8080", expected: "https://localhost:8080"},
|
||||
{name: "https+insecure-scheme", input: "https+insecure://localhost:8080", expected: "https+insecure://localhost:8080"},
|
||||
{name: "https-insecure-scheme", input: "https+insecure://localhost:8080", expected: "https+insecure://localhost:8080"},
|
||||
{name: "change-default-scheme", input: "localhost:8080", defaultScheme: "https", expected: "https://localhost:8080"},
|
||||
{name: "change-supported-schemes", input: "localhost:8080", defaultScheme: "tcp", supportedSchemes: []string{"tcp"}, expected: "tcp://localhost:8080"},
|
||||
{name: "remote-target", input: "https://example.com:8080", expected: "https://example.com:8080"},
|
||||
|
||||
@ -30,7 +30,7 @@ func TestReconciler_Reconcile(t *testing.T) {
|
||||
ExpectsError bool
|
||||
}{
|
||||
{
|
||||
Name: "single policy, denies all",
|
||||
Name: "single-policy-denies-all",
|
||||
ExpectedPolicyCount: 2,
|
||||
Request: reconcile.Request{
|
||||
NamespacedName: types.NamespacedName{
|
||||
@ -53,7 +53,7 @@ func TestReconciler_Reconcile(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "multiple policies merged",
|
||||
Name: "multiple-policies-merged",
|
||||
ExpectedPolicyCount: 2,
|
||||
Request: reconcile.Request{
|
||||
NamespacedName: types.NamespacedName{
|
||||
@ -89,7 +89,7 @@ func TestReconciler_Reconcile(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "no policies, no child resources",
|
||||
Name: "no-policies-no-child-resources",
|
||||
ExpectedPolicyCount: 0,
|
||||
Request: reconcile.Request{
|
||||
NamespacedName: types.NamespacedName{
|
||||
|
||||
@ -39,7 +39,7 @@ func TestReconciler_Reconcile(t *testing.T) {
|
||||
ClientFunc func(*tsapi.Tailnet, *corev1.Secret) tailnet.TailscaleClient
|
||||
}{
|
||||
{
|
||||
Name: "ignores unknown tailnet requests",
|
||||
Name: "ignores-unknown-tailnet-requests",
|
||||
Request: reconcile.Request{
|
||||
NamespacedName: types.NamespacedName{
|
||||
Name: "test",
|
||||
@ -47,7 +47,7 @@ func TestReconciler_Reconcile(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "invalid status for missing secret",
|
||||
Name: "invalid-status-missing-secret",
|
||||
Request: reconcile.Request{
|
||||
NamespacedName: types.NamespacedName{
|
||||
Name: "test",
|
||||
@ -73,7 +73,7 @@ func TestReconciler_Reconcile(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "invalid status for empty secret",
|
||||
Name: "invalid-status-empty-secret",
|
||||
Request: reconcile.Request{
|
||||
NamespacedName: types.NamespacedName{
|
||||
Name: "test",
|
||||
@ -105,7 +105,7 @@ func TestReconciler_Reconcile(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "invalid status for missing client id",
|
||||
Name: "invalid-status-missing-client-id",
|
||||
Request: reconcile.Request{
|
||||
NamespacedName: types.NamespacedName{
|
||||
Name: "test",
|
||||
@ -140,7 +140,7 @@ func TestReconciler_Reconcile(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "invalid status for missing client secret",
|
||||
Name: "invalid-status-missing-client-secret",
|
||||
Request: reconcile.Request{
|
||||
NamespacedName: types.NamespacedName{
|
||||
Name: "test",
|
||||
@ -175,7 +175,7 @@ func TestReconciler_Reconcile(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "invalid status for bad devices scope",
|
||||
Name: "invalid-status-bad-devices-scope",
|
||||
Request: reconcile.Request{
|
||||
NamespacedName: types.NamespacedName{
|
||||
Name: "test",
|
||||
@ -214,7 +214,7 @@ func TestReconciler_Reconcile(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "invalid status for bad services scope",
|
||||
Name: "invalid-status-bad-services-scope",
|
||||
Request: reconcile.Request{
|
||||
NamespacedName: types.NamespacedName{
|
||||
Name: "test",
|
||||
@ -253,7 +253,7 @@ func TestReconciler_Reconcile(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "invalid status for bad keys scope",
|
||||
Name: "invalid-status-bad-keys-scope",
|
||||
Request: reconcile.Request{
|
||||
NamespacedName: types.NamespacedName{
|
||||
Name: "test",
|
||||
@ -292,7 +292,7 @@ func TestReconciler_Reconcile(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "ready when valid and scopes are correct",
|
||||
Name: "ready-valid-scopes-correct",
|
||||
Request: reconcile.Request{
|
||||
NamespacedName: types.NamespacedName{
|
||||
Name: "default",
|
||||
|
||||
@ -39,19 +39,19 @@ func TestDelta(t *testing.T) {
|
||||
wantStats map[sockstats.Label]deltaStat
|
||||
}{
|
||||
{
|
||||
name: "nil a stat",
|
||||
name: "nil-a-stat",
|
||||
a: nil,
|
||||
b: &sockstats.SockStats{},
|
||||
wantStats: nil,
|
||||
},
|
||||
{
|
||||
name: "nil b stat",
|
||||
name: "nil-b-stat",
|
||||
a: &sockstats.SockStats{},
|
||||
b: nil,
|
||||
wantStats: nil,
|
||||
},
|
||||
{
|
||||
name: "no change",
|
||||
name: "no-change",
|
||||
a: &sockstats.SockStats{
|
||||
Stats: map[sockstats.Label]sockstats.SockStat{
|
||||
sockstats.LabelDERPHTTPClient: {
|
||||
@ -69,7 +69,7 @@ func TestDelta(t *testing.T) {
|
||||
wantStats: nil,
|
||||
},
|
||||
{
|
||||
name: "tx after empty stat",
|
||||
name: "tx-after-empty-stat",
|
||||
a: &sockstats.SockStats{},
|
||||
b: &sockstats.SockStats{
|
||||
Stats: map[sockstats.Label]sockstats.SockStat{
|
||||
@ -83,7 +83,7 @@ func TestDelta(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "rx after non-empty stat",
|
||||
name: "rx-after-non-empty-stat",
|
||||
a: &sockstats.SockStats{
|
||||
Stats: map[sockstats.Label]sockstats.SockStat{
|
||||
sockstats.LabelDERPHTTPClient: {
|
||||
|
||||
@ -42,7 +42,7 @@ func Test_linuxBatchingConn_splitCoalescedMessages(t *testing.T) {
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "second last split last empty",
|
||||
name: "second-last-split-last-empty",
|
||||
msgs: []ipv6.Message{
|
||||
newMsg(0, 0),
|
||||
newMsg(0, 0),
|
||||
@ -55,7 +55,7 @@ func Test_linuxBatchingConn_splitCoalescedMessages(t *testing.T) {
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "second last no split last empty",
|
||||
name: "second-last-no-split-last-empty",
|
||||
msgs: []ipv6.Message{
|
||||
newMsg(0, 0),
|
||||
newMsg(0, 0),
|
||||
@ -68,7 +68,7 @@ func Test_linuxBatchingConn_splitCoalescedMessages(t *testing.T) {
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "second last no split last no split",
|
||||
name: "second-last-no-split-last-no-split",
|
||||
msgs: []ipv6.Message{
|
||||
newMsg(0, 0),
|
||||
newMsg(0, 0),
|
||||
@ -81,7 +81,7 @@ func Test_linuxBatchingConn_splitCoalescedMessages(t *testing.T) {
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "second last no split last split",
|
||||
name: "second-last-no-split-last-split",
|
||||
msgs: []ipv6.Message{
|
||||
newMsg(0, 0),
|
||||
newMsg(0, 0),
|
||||
@ -94,7 +94,7 @@ func Test_linuxBatchingConn_splitCoalescedMessages(t *testing.T) {
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "second last split last split",
|
||||
name: "second-last-split-last-split",
|
||||
msgs: []ipv6.Message{
|
||||
newMsg(0, 0),
|
||||
newMsg(0, 0),
|
||||
@ -107,7 +107,7 @@ func Test_linuxBatchingConn_splitCoalescedMessages(t *testing.T) {
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "second last no split last split overflow",
|
||||
name: "second-last-no-split-last-split-overflow",
|
||||
msgs: []ipv6.Message{
|
||||
newMsg(0, 0),
|
||||
newMsg(0, 0),
|
||||
@ -161,7 +161,7 @@ func Test_linuxBatchingConn_coalesceMessages(t *testing.T) {
|
||||
wantGSO []int
|
||||
}{
|
||||
{
|
||||
name: "one message no coalesce",
|
||||
name: "one-message-no-coalesce",
|
||||
buffs: [][]byte{
|
||||
withGeneveSpace(1, 1),
|
||||
},
|
||||
@ -169,7 +169,7 @@ func Test_linuxBatchingConn_coalesceMessages(t *testing.T) {
|
||||
wantGSO: []int{0},
|
||||
},
|
||||
{
|
||||
name: "one message no coalesce vni.isSet",
|
||||
name: "one-message-no-coalesce-vni-isSet",
|
||||
buffs: [][]byte{
|
||||
withGeneveSpace(1, 1),
|
||||
},
|
||||
@ -178,7 +178,7 @@ func Test_linuxBatchingConn_coalesceMessages(t *testing.T) {
|
||||
wantGSO: []int{0},
|
||||
},
|
||||
{
|
||||
name: "two messages equal len coalesce",
|
||||
name: "two-messages-equal-len-coalesce",
|
||||
buffs: [][]byte{
|
||||
withGeneveSpace(1, 2),
|
||||
withGeneveSpace(1, 1),
|
||||
@ -187,7 +187,7 @@ func Test_linuxBatchingConn_coalesceMessages(t *testing.T) {
|
||||
wantGSO: []int{1},
|
||||
},
|
||||
{
|
||||
name: "two messages equal len coalesce vni.isSet",
|
||||
name: "two-messages-equal-len-coalesce-vni-isSet",
|
||||
buffs: [][]byte{
|
||||
withGeneveSpace(1, 2+packet.GeneveFixedHeaderLength),
|
||||
withGeneveSpace(1, 1),
|
||||
@ -197,7 +197,7 @@ func Test_linuxBatchingConn_coalesceMessages(t *testing.T) {
|
||||
wantGSO: []int{1 + packet.GeneveFixedHeaderLength},
|
||||
},
|
||||
{
|
||||
name: "two messages unequal len coalesce",
|
||||
name: "two-messages-unequal-len-coalesce",
|
||||
buffs: [][]byte{
|
||||
withGeneveSpace(2, 3),
|
||||
withGeneveSpace(1, 1),
|
||||
@ -206,7 +206,7 @@ func Test_linuxBatchingConn_coalesceMessages(t *testing.T) {
|
||||
wantGSO: []int{2},
|
||||
},
|
||||
{
|
||||
name: "two messages unequal len coalesce vni.isSet",
|
||||
name: "two-messages-unequal-len-coalesce-vni-isSet",
|
||||
buffs: [][]byte{
|
||||
withGeneveSpace(2, 3+packet.GeneveFixedHeaderLength),
|
||||
withGeneveSpace(1, 1),
|
||||
@ -216,7 +216,7 @@ func Test_linuxBatchingConn_coalesceMessages(t *testing.T) {
|
||||
wantGSO: []int{2 + packet.GeneveFixedHeaderLength},
|
||||
},
|
||||
{
|
||||
name: "three messages second unequal len coalesce",
|
||||
name: "three-messages-second-unequal-len-coalesce",
|
||||
buffs: [][]byte{
|
||||
withGeneveSpace(2, 3),
|
||||
withGeneveSpace(1, 1),
|
||||
@ -226,7 +226,7 @@ func Test_linuxBatchingConn_coalesceMessages(t *testing.T) {
|
||||
wantGSO: []int{2, 0},
|
||||
},
|
||||
{
|
||||
name: "three messages second unequal len coalesce vni.isSet",
|
||||
name: "three-messages-second-unequal-len-coalesce-vni-isSet",
|
||||
buffs: [][]byte{
|
||||
withGeneveSpace(2, 3+(2*packet.GeneveFixedHeaderLength)),
|
||||
withGeneveSpace(1, 1),
|
||||
@ -237,7 +237,7 @@ func Test_linuxBatchingConn_coalesceMessages(t *testing.T) {
|
||||
wantGSO: []int{2 + packet.GeneveFixedHeaderLength, 0},
|
||||
},
|
||||
{
|
||||
name: "three messages limited cap coalesce",
|
||||
name: "three-messages-limited-cap-coalesce",
|
||||
buffs: [][]byte{
|
||||
withGeneveSpace(2, 4),
|
||||
withGeneveSpace(2, 2),
|
||||
@ -247,7 +247,7 @@ func Test_linuxBatchingConn_coalesceMessages(t *testing.T) {
|
||||
wantGSO: []int{2},
|
||||
},
|
||||
{
|
||||
name: "three messages limited cap coalesce vni.isSet",
|
||||
name: "three-messages-limited-cap-coalesce-vni-isSet",
|
||||
buffs: [][]byte{
|
||||
withGeneveSpace(2, 4+packet.GeneveFixedHeaderLength),
|
||||
withGeneveSpace(2, 2),
|
||||
@ -376,19 +376,19 @@ func Test_getRXQOverflowsFromControl(t *testing.T) {
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "rxq overflows",
|
||||
name: "rxq-overflows",
|
||||
control: rxqOverflowsControl(1),
|
||||
want: 1,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "multiple cmsg rxq overflows at head",
|
||||
name: "multiple-cmsg-rxq-overflows-at-head",
|
||||
control: append(rxqOverflowsControl(1), gsoControl(1)...),
|
||||
want: 1,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "multiple cmsg rxq overflows at tail",
|
||||
name: "multiple-cmsg-rxq-overflows-at-tail",
|
||||
control: append(gsoControl(1), rxqOverflowsControl(1)...),
|
||||
want: 1,
|
||||
wantErr: false,
|
||||
@ -432,19 +432,19 @@ func Test_getGSOSizeFromControl(t *testing.T) {
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "rxq overflows",
|
||||
name: "rxq-overflows",
|
||||
control: rxqOverflowsControl(1),
|
||||
want: 0,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "multiple cmsg gso at tail",
|
||||
name: "multiple-cmsg-gso-at-tail",
|
||||
control: append(rxqOverflowsControl(1), gsoControl(1)...),
|
||||
want: 1,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "multiple cmsg gso at head",
|
||||
name: "multiple-cmsg-gso-at-head",
|
||||
control: append(gsoControl(1), rxqOverflowsControl(1)...),
|
||||
want: 1,
|
||||
wantErr: false,
|
||||
|
||||
@ -22,7 +22,7 @@ func TestLinuxDNSMode(t *testing.T) {
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "no_obvious_resolv.conf_owner",
|
||||
name: "no_obvious_resolvconf_owner",
|
||||
env: env(resolvDotConf("nameserver 10.0.0.1")),
|
||||
wantLog: "dns: [rc=unknown ret=direct]",
|
||||
want: "direct",
|
||||
@ -153,7 +153,7 @@ func TestLinuxDNSMode(t *testing.T) {
|
||||
// alleged that it was managed by systemd-resolved, but it
|
||||
// was actually a completely static config file pointing
|
||||
// elsewhere.
|
||||
name: "allegedly_resolved_but_not_in_resolv.conf",
|
||||
name: "allegedly_resolved_but_not_in_resolvconf",
|
||||
env: env(resolvDotConf("# Managed by systemd-resolved", "nameserver 10.0.0.1")),
|
||||
wantLog: "dns: resolvedIsActuallyResolver error: resolv.conf doesn't point to systemd-resolved; points to [10.0.0.1]\n" +
|
||||
"dns: [rc=resolved resolved=not-in-use ret=direct]",
|
||||
@ -163,7 +163,7 @@ func TestLinuxDNSMode(t *testing.T) {
|
||||
// We used to incorrectly decide that resolved wasn't in
|
||||
// charge when handed this (admittedly weird and bugged)
|
||||
// resolv.conf.
|
||||
name: "resolved_with_duplicates_in_resolv.conf",
|
||||
name: "resolved_with_duplicates_in_resolvconf",
|
||||
env: env(
|
||||
resolvDotConf(
|
||||
"# Managed by systemd-resolved",
|
||||
|
||||
@ -1127,7 +1127,7 @@ func TestForwarderWithManyResolvers(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ServFail+Success",
|
||||
name: "ServFail-and-Success",
|
||||
responses: [][]byte{ // All upstream servers fail except for one.
|
||||
makeTestResponse(t, domain, dns.RCodeServerFailure),
|
||||
makeTestResponse(t, domain, dns.RCodeServerFailure),
|
||||
@ -1150,7 +1150,7 @@ func TestForwarderWithManyResolvers(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "NXDomain+Success",
|
||||
name: "NXDomain-and-Success",
|
||||
responses: [][]byte{ // All upstream servers returned NXDOMAIN except for one.
|
||||
makeTestResponse(t, domain, dns.RCodeNameError),
|
||||
makeTestResponse(t, domain, dns.RCodeNameError),
|
||||
@ -1173,7 +1173,7 @@ func TestForwarderWithManyResolvers(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Refused+Success",
|
||||
name: "Refused-and-Success",
|
||||
responses: [][]byte{ // Some upstream servers refuse, but one succeeds.
|
||||
makeTestResponse(t, domain, dns.RCodeRefused),
|
||||
makeTestResponse(t, domain, dns.RCodeRefused),
|
||||
@ -1187,7 +1187,7 @@ func TestForwarderWithManyResolvers(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Refused+ServFail",
|
||||
name: "Refused-and-ServFail",
|
||||
responses: [][]byte{ // Some servers refuse, at least one fails.
|
||||
makeTestResponse(t, domain, dns.RCodeRefused),
|
||||
makeTestResponse(t, domain, dns.RCodeServerFailure),
|
||||
|
||||
@ -998,7 +998,7 @@ func TestNodeAddrResolve(t *testing.T) {
|
||||
}
|
||||
t.Logf("got IPv6 addr: %v", ap)
|
||||
})
|
||||
t.Run("IPv6 Failure", func(t *testing.T) {
|
||||
t.Run("IPv6-Failure", func(t *testing.T) {
|
||||
ap, ok := c.nodeAddrPort(ctx, dnV4Only, dn.STUNPort, probeIPv6)
|
||||
if ok {
|
||||
t.Fatalf("expected no addr but got: %v", ap)
|
||||
|
||||
@ -49,7 +49,7 @@ func TestIgnoreDuplicateNEWADDR(t *testing.T) {
|
||||
return msg
|
||||
}
|
||||
|
||||
t.Run("suppress duplicate NEWADDRs", func(t *testing.T) {
|
||||
t.Run("suppress-duplicate-NEWADDRs", func(t *testing.T) {
|
||||
c := nlConn{
|
||||
buffered: []netlink.Message{
|
||||
newAddrMsg(1, "192.168.0.5", unix.RTM_NEWADDR),
|
||||
@ -69,7 +69,7 @@ func TestIgnoreDuplicateNEWADDR(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("do not suppress after DELADDR", func(t *testing.T) {
|
||||
t.Run("no-suppress-after-DELADDR", func(t *testing.T) {
|
||||
c := nlConn{
|
||||
buffered: []netlink.Message{
|
||||
newAddrMsg(1, "192.168.0.5", unix.RTM_NEWADDR),
|
||||
|
||||
@ -47,7 +47,7 @@ func TestDownload(t *testing.T) {
|
||||
// ensure that the test returns an appropriate number of Result structs
|
||||
expectedLen := int(DefaultDuration.Seconds()) + 1
|
||||
|
||||
t.Run("download test", func(t *testing.T) {
|
||||
t.Run("download-test", func(t *testing.T) {
|
||||
// conduct a download test
|
||||
results, err := RunClient(Download, DefaultDuration, serverIP)
|
||||
|
||||
@ -65,7 +65,7 @@ func TestDownload(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("upload test", func(t *testing.T) {
|
||||
t.Run("upload-test", func(t *testing.T) {
|
||||
// conduct an upload test
|
||||
results, err := RunClient(Upload, DefaultDuration, serverIP)
|
||||
|
||||
|
||||
@ -60,7 +60,7 @@ var responseTests = []struct {
|
||||
wantPort: 59029,
|
||||
},
|
||||
{
|
||||
name: "stun.sipgate.net:10000",
|
||||
name: "stun-sipgate-net-10000",
|
||||
data: []byte{
|
||||
0x01, 0x01, 0x00, 0x44, 0x21, 0x12, 0xa4, 0x42,
|
||||
0x48, 0x2e, 0xb6, 0x47, 0x15, 0xe8, 0xb2, 0x8e,
|
||||
@ -82,7 +82,7 @@ var responseTests = []struct {
|
||||
wantPort: 58539,
|
||||
},
|
||||
{
|
||||
name: "stun.powervoip.com:3478",
|
||||
name: "stun-powervoip-com-3478",
|
||||
data: []byte{
|
||||
0x01, 0x01, 0x00, 0x24, 0x21, 0x12, 0xa4, 0x42,
|
||||
0x7e, 0x57, 0x96, 0x68, 0x29, 0xf4, 0x44, 0x60,
|
||||
@ -100,7 +100,7 @@ var responseTests = []struct {
|
||||
wantPort: 59859,
|
||||
},
|
||||
{
|
||||
name: "in-process pion server",
|
||||
name: "in-process-pion-server",
|
||||
data: []byte{
|
||||
0x01, 0x01, 0x00, 0x24, 0x21, 0x12, 0xa4, 0x42,
|
||||
0xeb, 0xc2, 0xd3, 0x6e, 0xf4, 0x71, 0x21, 0x7c,
|
||||
@ -119,7 +119,7 @@ var responseTests = []struct {
|
||||
wantPort: 61300,
|
||||
},
|
||||
{
|
||||
name: "stuntman-server ipv6",
|
||||
name: "stuntman-server-ipv6",
|
||||
data: []byte{
|
||||
0x01, 0x01, 0x00, 0x48, 0x21, 0x12, 0xa4, 0x42,
|
||||
0x06, 0xf5, 0x66, 0x85, 0xd2, 0x8a, 0xf3, 0xe6,
|
||||
|
||||
@ -28,7 +28,7 @@ func TestSynologyProxyFromConfigCached(t *testing.T) {
|
||||
|
||||
tstest.Replace(t, &synologyProxyConfigPath, filepath.Join(t.TempDir(), "proxy.conf"))
|
||||
|
||||
t.Run("no config file", func(t *testing.T) {
|
||||
t.Run("no-config-file", func(t *testing.T) {
|
||||
if _, err := os.Stat(synologyProxyConfigPath); err == nil {
|
||||
t.Fatalf("%s must not exist for this test", synologyProxyConfigPath)
|
||||
}
|
||||
@ -52,7 +52,7 @@ func TestSynologyProxyFromConfigCached(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("config file updated", func(t *testing.T) {
|
||||
t.Run("config-file-updated", func(t *testing.T) {
|
||||
cache.updated = time.Now()
|
||||
cache.httpProxy = nil
|
||||
cache.httpsProxy = nil
|
||||
@ -84,7 +84,7 @@ https_port=443
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("config file removed", func(t *testing.T) {
|
||||
t.Run("config-file-removed", func(t *testing.T) {
|
||||
cache.updated = time.Now()
|
||||
cache.httpProxy = urlMustParse("http://127.0.0.1/")
|
||||
cache.httpsProxy = urlMustParse("http://127.0.0.1/")
|
||||
@ -108,7 +108,7 @@ https_port=443
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("picks proxy from request scheme", func(t *testing.T) {
|
||||
t.Run("picks-proxy-from-request-scheme", func(t *testing.T) {
|
||||
cache.updated = time.Now()
|
||||
cache.httpProxy = nil
|
||||
cache.httpsProxy = nil
|
||||
@ -164,7 +164,7 @@ func TestSynologyProxiesFromConfig(t *testing.T) {
|
||||
return openReader, openErr
|
||||
})
|
||||
|
||||
t.Run("with config", func(t *testing.T) {
|
||||
t.Run("with-config", func(t *testing.T) {
|
||||
mc := &mustCloser{Reader: strings.NewReader(`
|
||||
proxy_user=foo
|
||||
proxy_pwd=bar
|
||||
@ -200,7 +200,7 @@ http_port=80
|
||||
|
||||
})
|
||||
|
||||
t.Run("nonexistent config", func(t *testing.T) {
|
||||
t.Run("nonexistent-config", func(t *testing.T) {
|
||||
openReader = nil
|
||||
openErr = os.ErrNotExist
|
||||
|
||||
@ -216,7 +216,7 @@ http_port=80
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("error opening config", func(t *testing.T) {
|
||||
t.Run("error-opening-config", func(t *testing.T) {
|
||||
openReader = nil
|
||||
openErr = errors.New("example error")
|
||||
|
||||
|
||||
@ -97,7 +97,7 @@ func TestSetSelfProxy(t *testing.T) {
|
||||
wantHTTPS string
|
||||
}{
|
||||
{
|
||||
name: "no self proxy",
|
||||
name: "no-self-proxy",
|
||||
env: map[string]string{
|
||||
"HTTP_PROXY": "127.0.0.1:1234",
|
||||
"HTTPS_PROXY": "127.0.0.1:1234",
|
||||
@ -107,7 +107,7 @@ func TestSetSelfProxy(t *testing.T) {
|
||||
wantHTTPS: "127.0.0.1:1234",
|
||||
},
|
||||
{
|
||||
name: "skip proxies",
|
||||
name: "skip-proxies",
|
||||
env: map[string]string{
|
||||
"HTTP_PROXY": "127.0.0.1:1234",
|
||||
"HTTPS_PROXY": "127.0.0.1:5678",
|
||||
@ -117,7 +117,7 @@ func TestSetSelfProxy(t *testing.T) {
|
||||
wantHTTPS: "", // skipped
|
||||
},
|
||||
{
|
||||
name: "localhost normalization of env var",
|
||||
name: "localhost-normalization-of-env-var",
|
||||
env: map[string]string{
|
||||
"HTTP_PROXY": "localhost:1234",
|
||||
"HTTPS_PROXY": "[::1]:5678",
|
||||
@ -127,7 +127,7 @@ func TestSetSelfProxy(t *testing.T) {
|
||||
wantHTTPS: "", // skipped
|
||||
},
|
||||
{
|
||||
name: "localhost normalization of addr",
|
||||
name: "localhost-normalization-of-addr",
|
||||
env: map[string]string{
|
||||
"HTTP_PROXY": "127.0.0.1:1234",
|
||||
"HTTPS_PROXY": "127.0.0.1:1234",
|
||||
@ -137,7 +137,7 @@ func TestSetSelfProxy(t *testing.T) {
|
||||
wantHTTPS: "", // skipped
|
||||
},
|
||||
{
|
||||
name: "no ports",
|
||||
name: "no-ports",
|
||||
env: map[string]string{
|
||||
"HTTP_PROXY": "myproxy",
|
||||
"HTTPS_PROXY": "myproxy",
|
||||
|
||||
@ -28,32 +28,32 @@ func TestServerEndpointJSONUnmarshal(t *testing.T) {
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "invalid ServerDisco",
|
||||
name: "invalid-ServerDisco",
|
||||
json: []byte(`{"ServerDisco":"1","LamportID":18446744073709551615,"AddrPorts":["127.0.0.1:1","127.0.0.2:2"],"VNI":16777215,"BindLifetime":"30s","SteadyStateLifetime":"5m0s"}`),
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid LamportID",
|
||||
name: "invalid-LamportID",
|
||||
json: []byte(`{"ServerDisco":"discokey:003cd7453e04a653eb0e7a18f206fc353180efadb2facfd05ebd6982a1392c7f","LamportID":1.1,"AddrPorts":["127.0.0.1:1","127.0.0.2:2"],"VNI":16777215,"BindLifetime":"30s","SteadyStateLifetime":"5m0s"}`),
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid AddrPorts",
|
||||
name: "invalid-AddrPorts",
|
||||
json: []byte(`{"ServerDisco":"discokey:003cd7453e04a653eb0e7a18f206fc353180efadb2facfd05ebd6982a1392c7f","LamportID":18446744073709551615,"AddrPorts":["127.0.0.1.1:1","127.0.0.2:2"],"VNI":16777215,"BindLifetime":"30s","SteadyStateLifetime":"5m0s"}`),
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid VNI",
|
||||
name: "invalid-VNI",
|
||||
json: []byte(`{"ServerDisco":"discokey:003cd7453e04a653eb0e7a18f206fc353180efadb2facfd05ebd6982a1392c7f","LamportID":18446744073709551615,"AddrPorts":["127.0.0.1:1","127.0.0.2:2"],"VNI":18446744073709551615,"BindLifetime":"30s","SteadyStateLifetime":"5m0s"}`),
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid BindLifetime",
|
||||
name: "invalid-BindLifetime",
|
||||
json: []byte(`{"ServerDisco":"discokey:003cd7453e04a653eb0e7a18f206fc353180efadb2facfd05ebd6982a1392c7f","LamportID":18446744073709551615,"AddrPorts":["127.0.0.1:1","127.0.0.2:2"],"VNI":16777215,"BindLifetime":"5","SteadyStateLifetime":"5m0s"}`),
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid SteadyStateLifetime",
|
||||
name: "invalid-SteadyStateLifetime",
|
||||
json: []byte(`{"ServerDisco":"discokey:003cd7453e04a653eb0e7a18f206fc353180efadb2facfd05ebd6982a1392c7f","LamportID":18446744073709551615,"AddrPorts":["127.0.0.1:1","127.0.0.2:2"],"VNI":16777215,"BindLifetime":"30s","SteadyStateLifetime":"5"}`),
|
||||
wantErr: true,
|
||||
},
|
||||
@ -79,7 +79,7 @@ func TestServerEndpointJSONMarshal(t *testing.T) {
|
||||
serverEndpoint ServerEndpoint
|
||||
}{
|
||||
{
|
||||
name: "valid roundtrip",
|
||||
name: "valid-roundtrip",
|
||||
serverEndpoint: ServerEndpoint{
|
||||
ServerDisco: key.NewDisco().Public(),
|
||||
LamportID: uint64(math.MaxUint64),
|
||||
|
||||
@ -196,15 +196,15 @@ func TestServer(t *testing.T) {
|
||||
forceClientsMixedAF bool
|
||||
}{
|
||||
{
|
||||
name: "over ipv4",
|
||||
name: "over-ipv4",
|
||||
staticAddrs: []netip.Addr{netip.MustParseAddr("127.0.0.1")},
|
||||
},
|
||||
{
|
||||
name: "over ipv6",
|
||||
name: "over-ipv6",
|
||||
staticAddrs: []netip.Addr{netip.MustParseAddr("::1")},
|
||||
},
|
||||
{
|
||||
name: "mixed address families",
|
||||
name: "mixed-address-families",
|
||||
staticAddrs: []netip.Addr{netip.MustParseAddr("127.0.0.1"), netip.MustParseAddr("::1")},
|
||||
forceClientsMixedAF: true,
|
||||
},
|
||||
|
||||
@ -41,25 +41,25 @@ func TestPostRequestContentTypeValidation(t *testing.T) {
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "API routes should accept `application/json` content-type",
|
||||
name: "API-accept-application-json",
|
||||
browserRoute: false,
|
||||
contentType: "application/json",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "API routes should reject `application/x-www-form-urlencoded` content-type",
|
||||
name: "API-reject-form-urlencoded",
|
||||
browserRoute: false,
|
||||
contentType: "application/x-www-form-urlencoded",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Browser routes should accept `application/x-www-form-urlencoded` content-type",
|
||||
name: "browser-accept-form-urlencoded",
|
||||
browserRoute: true,
|
||||
contentType: "application/x-www-form-urlencoded",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "non Browser routes should accept `application/json` content-type",
|
||||
name: "browser-accept-application-json",
|
||||
browserRoute: true,
|
||||
contentType: "application/json",
|
||||
wantErr: false,
|
||||
@ -106,21 +106,21 @@ func TestAPIMuxCrossOriginResourceSharingHeaders(t *testing.T) {
|
||||
corsMethods []string
|
||||
}{
|
||||
{
|
||||
name: "do not set CORS headers for non-OPTIONS requests",
|
||||
name: "no-CORS-headers-for-non-OPTIONS",
|
||||
corsOrigins: []string{"https://foobar.com"},
|
||||
corsMethods: []string{"GET", "POST", "HEAD"},
|
||||
httpMethod: "GET",
|
||||
wantCORSHeaders: false,
|
||||
},
|
||||
{
|
||||
name: "set CORS headers for non-OPTIONS requests",
|
||||
name: "CORS-headers-for-OPTIONS",
|
||||
corsOrigins: []string{"https://foobar.com"},
|
||||
corsMethods: []string{"GET", "POST", "HEAD"},
|
||||
httpMethod: "OPTIONS",
|
||||
wantCORSHeaders: true,
|
||||
},
|
||||
{
|
||||
name: "do not serve CORS headers for OPTIONS requests with no configured origins",
|
||||
name: "no-CORS-headers-for-OPTIONS-without-origins",
|
||||
httpMethod: "OPTIONS",
|
||||
wantCORSHeaders: false,
|
||||
},
|
||||
@ -162,19 +162,19 @@ func TestCSRFProtection(t *testing.T) {
|
||||
wantStatus int
|
||||
}{
|
||||
{
|
||||
name: "POST requests to non-API routes require CSRF token and fail if not provided",
|
||||
name: "non-API-POST-without-CSRF-fails",
|
||||
apiRoute: false,
|
||||
passCSRFToken: false,
|
||||
wantStatus: http.StatusForbidden,
|
||||
},
|
||||
{
|
||||
name: "POST requests to non-API routes require CSRF token and pass if provided",
|
||||
name: "non-API-POST-with-CSRF-passes",
|
||||
apiRoute: false,
|
||||
passCSRFToken: true,
|
||||
wantStatus: http.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "POST requests to /api/ routes do not require CSRF token",
|
||||
name: "API-POST-without-CSRF-passes",
|
||||
apiRoute: true,
|
||||
passCSRFToken: false,
|
||||
wantStatus: http.StatusOK,
|
||||
@ -246,11 +246,11 @@ func TestContentSecurityPolicyHeader(t *testing.T) {
|
||||
wantCSP string
|
||||
}{
|
||||
{
|
||||
name: "default CSP",
|
||||
name: "default-CSP",
|
||||
wantCSP: `base-uri 'self'; block-all-mixed-content; default-src 'self'; form-action 'self'; frame-ancestors 'none';`,
|
||||
},
|
||||
{
|
||||
name: "custom CSP",
|
||||
name: "custom-CSP",
|
||||
csp: CSP{
|
||||
"default-src": {"'self'", "https://tailscale.com"},
|
||||
"upgrade-insecure-requests": nil,
|
||||
@ -258,7 +258,7 @@ func TestContentSecurityPolicyHeader(t *testing.T) {
|
||||
wantCSP: `default-src 'self' https://tailscale.com; upgrade-insecure-requests;`,
|
||||
},
|
||||
{
|
||||
name: "`/api/*` routes do not get CSP headers",
|
||||
name: "api-routes-no-CSP-headers",
|
||||
apiRoute: true,
|
||||
wantCSP: "",
|
||||
},
|
||||
@ -301,12 +301,12 @@ func TestCSRFCookieSecureMode(t *testing.T) {
|
||||
wantSecure bool
|
||||
}{
|
||||
{
|
||||
name: "CSRF cookie should be secure when server is in secure context",
|
||||
name: "secure-context-cookie-secure",
|
||||
secureMode: true,
|
||||
wantSecure: true,
|
||||
},
|
||||
{
|
||||
name: "CSRF cookie should not be secure when server is not in secure context",
|
||||
name: "non-secure-context-cookie-not-secure",
|
||||
secureMode: false,
|
||||
wantSecure: false,
|
||||
},
|
||||
@ -343,12 +343,12 @@ func TestRefererPolicy(t *testing.T) {
|
||||
wantRefererPolicy bool
|
||||
}{
|
||||
{
|
||||
name: "BrowserMux routes get Referer-Policy headers",
|
||||
name: "BrowserMux-gets-Referer-Policy",
|
||||
browserRoute: true,
|
||||
wantRefererPolicy: true,
|
||||
},
|
||||
{
|
||||
name: "APIMux routes do not get Referer-Policy headers",
|
||||
name: "APIMux-no-Referer-Policy",
|
||||
browserRoute: false,
|
||||
wantRefererPolicy: false,
|
||||
},
|
||||
@ -420,54 +420,54 @@ func TestRouting(t *testing.T) {
|
||||
want string
|
||||
}{
|
||||
{
|
||||
desc: "only browser mux",
|
||||
desc: "only-browser-mux",
|
||||
browserPatterns: []string{"/"},
|
||||
requestPath: "/index.html",
|
||||
want: "browser",
|
||||
},
|
||||
{
|
||||
desc: "only API mux",
|
||||
desc: "only-API-mux",
|
||||
apiPatterns: []string{"/api/"},
|
||||
requestPath: "/api/foo",
|
||||
want: "api",
|
||||
},
|
||||
{
|
||||
desc: "browser mux match",
|
||||
desc: "browser-mux-match",
|
||||
browserPatterns: []string{"/content/"},
|
||||
apiPatterns: []string{"/api/"},
|
||||
requestPath: "/content/index.html",
|
||||
want: "browser",
|
||||
},
|
||||
{
|
||||
desc: "API mux match",
|
||||
desc: "API-mux-match",
|
||||
browserPatterns: []string{"/content/"},
|
||||
apiPatterns: []string{"/api/"},
|
||||
requestPath: "/api/foo",
|
||||
want: "api",
|
||||
},
|
||||
{
|
||||
desc: "browser wildcard match",
|
||||
desc: "browser-wildcard-match",
|
||||
browserPatterns: []string{"/"},
|
||||
apiPatterns: []string{"/api/"},
|
||||
requestPath: "/index.html",
|
||||
want: "browser",
|
||||
},
|
||||
{
|
||||
desc: "API wildcard match",
|
||||
desc: "API-wildcard-match",
|
||||
browserPatterns: []string{"/content/"},
|
||||
apiPatterns: []string{"/"},
|
||||
requestPath: "/api/foo",
|
||||
want: "api",
|
||||
},
|
||||
{
|
||||
desc: "path conflict",
|
||||
desc: "path-conflict",
|
||||
browserPatterns: []string{"/foo/"},
|
||||
apiPatterns: []string{"/foo/bar/"},
|
||||
requestPath: "/foo/bar/baz",
|
||||
want: "api",
|
||||
},
|
||||
{
|
||||
desc: "no match",
|
||||
desc: "no-match",
|
||||
browserPatterns: []string{"/foo/"},
|
||||
apiPatterns: []string{"/bar/"},
|
||||
requestPath: "/baz",
|
||||
@ -521,43 +521,43 @@ func TestGetMoreSpecificPattern(t *testing.T) {
|
||||
want: unknownHandler,
|
||||
},
|
||||
{
|
||||
desc: "identical prefix",
|
||||
desc: "identical-prefix",
|
||||
a: "/foo/bar/",
|
||||
b: "/foo/bar/",
|
||||
want: unknownHandler,
|
||||
},
|
||||
{
|
||||
desc: "trailing slash",
|
||||
desc: "trailing-slash",
|
||||
a: "/foo",
|
||||
b: "/foo/", // path.Clean will strip the trailing slash.
|
||||
want: unknownHandler,
|
||||
},
|
||||
{
|
||||
desc: "same prefix",
|
||||
desc: "same-prefix",
|
||||
a: "/foo/bar/quux",
|
||||
b: "/foo/bar/", // path.Clean will strip the trailing slash.
|
||||
want: apiHandler,
|
||||
},
|
||||
{
|
||||
desc: "almost same prefix, but not a path component",
|
||||
desc: "almost-same-prefix-not-path-component",
|
||||
a: "/goat/sheep/cheese",
|
||||
b: "/goat/sheepcheese/", // path.Clean will strip the trailing slash.
|
||||
want: apiHandler,
|
||||
},
|
||||
{
|
||||
desc: "attempt to make less-specific pattern look more specific",
|
||||
desc: "traversal-less-specific-pattern",
|
||||
a: "/goat/cat/buddy",
|
||||
b: "/goat/../../../../../../../cat", // path.Clean catches this foolishness
|
||||
want: apiHandler,
|
||||
},
|
||||
{
|
||||
desc: "2 names for / (1)",
|
||||
desc: "two-names-for-root-1",
|
||||
a: "/",
|
||||
b: "/../../../../../../",
|
||||
want: unknownHandler,
|
||||
},
|
||||
{
|
||||
desc: "2 names for / (2)",
|
||||
desc: "two-names-for-root-2",
|
||||
a: "/",
|
||||
b: "///////",
|
||||
want: unknownHandler,
|
||||
@ -586,15 +586,15 @@ func TestStrictTransportSecurityOptions(t *testing.T) {
|
||||
expect string
|
||||
}{
|
||||
{
|
||||
name: "off by default",
|
||||
name: "off-by-default",
|
||||
},
|
||||
{
|
||||
name: "default HSTS options in the secure context",
|
||||
name: "default-HSTS-in-secure-context",
|
||||
secureContext: true,
|
||||
expect: DefaultStrictTransportSecurityOptions,
|
||||
},
|
||||
{
|
||||
name: "custom options sent in the secure context",
|
||||
name: "custom-options-in-secure-context",
|
||||
options: DefaultStrictTransportSecurityOptions + "; includeSubDomains",
|
||||
secureContext: true,
|
||||
expect: DefaultStrictTransportSecurityOptions + "; includeSubDomains",
|
||||
|
||||
@ -35,7 +35,7 @@ func TestConnectToRecorder(t *testing.T) {
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "v1 recorder",
|
||||
desc: "v1-recorder",
|
||||
setup: func(t *testing.T) (*http.ServeMux, <-chan []byte) {
|
||||
uploadHash := make(chan []byte, 1)
|
||||
mux := http.NewServeMux()
|
||||
@ -50,7 +50,7 @@ func TestConnectToRecorder(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "v2 recorder",
|
||||
desc: "v2-recorder",
|
||||
http2: true,
|
||||
setup: func(t *testing.T) (*http.ServeMux, <-chan []byte) {
|
||||
uploadHash := make(chan []byte, 1)
|
||||
@ -100,7 +100,7 @@ func TestConnectToRecorder(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "v2 recorder no acks",
|
||||
desc: "v2-recorder-no-acks",
|
||||
http2: true,
|
||||
wantErr: true,
|
||||
setup: func(t *testing.T) (*http.ServeMux, <-chan []byte) {
|
||||
|
||||
@ -16,4 +16,4 @@
|
||||
) {
|
||||
src = ./.;
|
||||
}).shellNix
|
||||
# nix-direnv cache busting line: sha256-39axT5Q0+fNTcMgZCMLMNfJEJN46wMaaKDgfI+Uj+Ps=
|
||||
# nix-direnv cache busting line: sha256-VsVMvTEblVx/HNbuCVxC9UgKpriRwixswUSKVGLMf3Q=
|
||||
|
||||
@ -111,25 +111,25 @@ func TestFilterEnv(t *testing.T) {
|
||||
wantErrMessage string
|
||||
}{
|
||||
{
|
||||
name: "simple direct matches",
|
||||
name: "simple-direct-matches",
|
||||
acceptEnv: []string{"FOO", "FOO2", "FOO_3"},
|
||||
environ: []string{"FOO=BAR", "FOO2=BAZ", "FOO_3=123", "FOOOO4-2=AbCdEfG"},
|
||||
expectedFiltered: []string{"FOO=BAR", "FOO2=BAZ", "FOO_3=123"},
|
||||
},
|
||||
{
|
||||
name: "bare wildcard",
|
||||
name: "bare-wildcard",
|
||||
acceptEnv: []string{"*"},
|
||||
environ: []string{"FOO=BAR", "FOO2=BAZ", "FOO_3=123", "FOOOO4-2=AbCdEfG"},
|
||||
expectedFiltered: []string{"FOO=BAR", "FOO2=BAZ", "FOO_3=123", "FOOOO4-2=AbCdEfG"},
|
||||
},
|
||||
{
|
||||
name: "complex matches",
|
||||
name: "complex-matches",
|
||||
acceptEnv: []string{"FO?", "FOOO*", "FO*5?7"},
|
||||
environ: []string{"FOO=BAR", "FOO2=BAZ", "FOO_3=123", "FOOOO4-2=AbCdEfG", "FO1-kmndGamc79567=ABC", "FO57=BAR2"},
|
||||
expectedFiltered: []string{"FOO=BAR", "FOOOO4-2=AbCdEfG", "FO1-kmndGamc79567=ABC"},
|
||||
},
|
||||
{
|
||||
name: "environ format invalid",
|
||||
name: "environ-format-invalid",
|
||||
acceptEnv: []string{"FO?", "FOOO*", "FO*5?7"},
|
||||
environ: []string{"FOOBAR"},
|
||||
expectedFiltered: nil,
|
||||
|
||||
@ -30,7 +30,7 @@ func BenchmarkShardedInt(b *testing.B) {
|
||||
})
|
||||
})
|
||||
|
||||
b.Run("sharded int", func(b *testing.B) {
|
||||
b.Run("sharded-int", func(b *testing.B) {
|
||||
m := NewShardedInt()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
@ -60,7 +60,7 @@ func TestShardedInt(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("high concurrency", func(t *testing.T) {
|
||||
t.Run("high-concurrency", func(t *testing.T) {
|
||||
m := NewShardedInt()
|
||||
wg := sync.WaitGroup{}
|
||||
numWorkers := 1000
|
||||
@ -83,7 +83,7 @@ func TestShardedInt(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("encoding.TextAppender", func(t *testing.T) {
|
||||
t.Run("encoding-TextAppender", func(t *testing.T) {
|
||||
m := NewShardedInt()
|
||||
m.Add(1)
|
||||
b := make([]byte, 0, 10)
|
||||
|
||||
@ -18,31 +18,35 @@ func TestProtoPortRangeParsing(t *testing.T) {
|
||||
return PortRange{First: s, Last: e}
|
||||
}
|
||||
tests := []struct {
|
||||
in string
|
||||
out ProtoPortRange
|
||||
err error
|
||||
name string
|
||||
in string
|
||||
out ProtoPortRange
|
||||
err error
|
||||
}{
|
||||
{in: "tcp:80", out: ProtoPortRange{Proto: int(ipproto.TCP), Ports: pr(80, 80)}},
|
||||
{in: "80", out: ProtoPortRange{Ports: pr(80, 80)}},
|
||||
{in: "*", out: ProtoPortRange{Ports: PortRangeAny}},
|
||||
{in: "*:*", out: ProtoPortRange{Ports: PortRangeAny}},
|
||||
{in: "tcp:*", out: ProtoPortRange{Proto: int(ipproto.TCP), Ports: PortRangeAny}},
|
||||
{name: "tcp-80", in: "tcp:80", out: ProtoPortRange{Proto: int(ipproto.TCP), Ports: pr(80, 80)}},
|
||||
{name: "80", in: "80", out: ProtoPortRange{Ports: pr(80, 80)}},
|
||||
{name: "star", in: "*", out: ProtoPortRange{Ports: PortRangeAny}},
|
||||
{name: "star-star", in: "*:*", out: ProtoPortRange{Ports: PortRangeAny}},
|
||||
{name: "tcp-star", in: "tcp:*", out: ProtoPortRange{Proto: int(ipproto.TCP), Ports: PortRangeAny}},
|
||||
{
|
||||
in: "tcp:",
|
||||
err: vizerror.Errorf("invalid port list: %#v", ""),
|
||||
name: "tcp-empty-port",
|
||||
in: "tcp:",
|
||||
err: vizerror.Errorf("invalid port list: %#v", ""),
|
||||
},
|
||||
{
|
||||
in: ":80",
|
||||
err: errEmptyProtocol,
|
||||
name: "empty-proto-80",
|
||||
in: ":80",
|
||||
err: errEmptyProtocol,
|
||||
},
|
||||
{
|
||||
in: "",
|
||||
err: errEmptyString,
|
||||
name: "empty-string",
|
||||
in: "",
|
||||
err: errEmptyString,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.in, func(t *testing.T) {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
var ppr ProtoPortRange
|
||||
err := ppr.UnmarshalText([]byte(tc.in))
|
||||
if tc.err != err {
|
||||
|
||||
@ -841,12 +841,12 @@ func TestMarshalToRawMessageAndBack(t *testing.T) {
|
||||
capType: PeerCapability("foo"),
|
||||
},
|
||||
{
|
||||
name: "some values",
|
||||
name: "some-values",
|
||||
val: testRule{Ports: []int{80, 443}, Name: "foo"},
|
||||
capType: PeerCapability("foo"),
|
||||
},
|
||||
{
|
||||
name: "all values",
|
||||
name: "all-values",
|
||||
val: testRule{Ports: []int{80, 443}, Name: "foo", ToggleOn: true, Groups: inner{Groups: []string{"foo", "bar"}}, Addrs: []netip.AddrPort{testip}},
|
||||
capType: PeerCapability("foo"),
|
||||
},
|
||||
|
||||
@ -185,7 +185,7 @@ func TestMarkActiveChain(t *testing.T) {
|
||||
expectLastActiveIdx: 0,
|
||||
},
|
||||
{
|
||||
name: "simple truncate",
|
||||
name: "simple-truncate",
|
||||
minChain: 2,
|
||||
chain: []aumTemplate{
|
||||
{AUM: AUM{MessageKind: AUMCheckpoint, State: &State{}}},
|
||||
@ -196,7 +196,7 @@ func TestMarkActiveChain(t *testing.T) {
|
||||
expectLastActiveIdx: 1,
|
||||
},
|
||||
{
|
||||
name: "long truncate",
|
||||
name: "long-truncate",
|
||||
minChain: 5,
|
||||
chain: []aumTemplate{
|
||||
{AUM: AUM{MessageKind: AUMCheckpoint, State: &State{}}},
|
||||
@ -211,7 +211,7 @@ func TestMarkActiveChain(t *testing.T) {
|
||||
expectLastActiveIdx: 2,
|
||||
},
|
||||
{
|
||||
name: "truncate finding checkpoint",
|
||||
name: "truncate-finding-checkpoint",
|
||||
minChain: 2,
|
||||
chain: []aumTemplate{
|
||||
{AUM: AUM{MessageKind: AUMCheckpoint, State: &State{}}},
|
||||
@ -342,7 +342,7 @@ func TestMarkAncestorIntersectionAUMs(t *testing.T) {
|
||||
wantRetained: []string{"A"},
|
||||
},
|
||||
{
|
||||
name: "no adjustment",
|
||||
name: "no-adjustment",
|
||||
chain: newTestchain(t, `
|
||||
DEAD -> A -> B -> C
|
||||
A.template = checkpoint
|
||||
@ -380,7 +380,7 @@ func TestMarkAncestorIntersectionAUMs(t *testing.T) {
|
||||
wantDeleted: []string{"A", "B"},
|
||||
},
|
||||
{
|
||||
name: "fork finding earlier checkpoint",
|
||||
name: "fork-finding-earlier-checkpoint",
|
||||
chain: newTestchain(t, `
|
||||
A -> B -> C -> D -> E -> F
|
||||
| -> FORK
|
||||
@ -403,7 +403,7 @@ func TestMarkAncestorIntersectionAUMs(t *testing.T) {
|
||||
wantDeleted: []string{"A"},
|
||||
},
|
||||
{
|
||||
name: "fork multi",
|
||||
name: "fork-multi",
|
||||
chain: newTestchain(t, `
|
||||
A -> B -> C -> D -> E
|
||||
| -> DEADFORK
|
||||
@ -429,7 +429,7 @@ func TestMarkAncestorIntersectionAUMs(t *testing.T) {
|
||||
wantDeleted: []string{"A", "B", "DEADFORK"},
|
||||
},
|
||||
{
|
||||
name: "fork multi 2",
|
||||
name: "fork-multi-2",
|
||||
chain: newTestchain(t, `
|
||||
A -> B -> C -> D -> E -> F -> G
|
||||
|
||||
|
||||
@ -68,14 +68,17 @@ func authForPeers(self *ipnstate.PeerStatus, peers []*ipnstate.PeerStatus) *auth
|
||||
|
||||
func TestAuthRefreshErrorsNotRunning(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
in *ipnstate.Status
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "no-status",
|
||||
in: nil,
|
||||
expected: "no status",
|
||||
},
|
||||
{
|
||||
name: "ts-server-not-running",
|
||||
in: &ipnstate.Status{
|
||||
BackendState: "NeedsMachineAuth",
|
||||
},
|
||||
@ -84,7 +87,7 @@ func TestAuthRefreshErrorsNotRunning(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.expected, func(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctx := t.Context()
|
||||
a := authForStatus(tt.in)
|
||||
err := a.Refresh(ctx)
|
||||
@ -127,22 +130,22 @@ func TestAuthAllowsHost(t *testing.T) {
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "tagged with different tag",
|
||||
name: "tagged-different-tag",
|
||||
peerStatus: peers[0],
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "not tagged",
|
||||
name: "not-tagged",
|
||||
peerStatus: peers[1],
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "tags includes testTag",
|
||||
name: "tags-include-testTag",
|
||||
peerStatus: peers[2],
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "only tag is testTag",
|
||||
name: "only-testTag",
|
||||
peerStatus: peers[3],
|
||||
expected: true,
|
||||
},
|
||||
@ -201,12 +204,12 @@ func TestAuthSelfAllowed(t *testing.T) {
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "self has different tag",
|
||||
name: "self-different-tag",
|
||||
in: []string{"woo"},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "selfs tags include testTag",
|
||||
name: "self-tags-include-testTag",
|
||||
in: []string{"woo", testTag},
|
||||
expected: true,
|
||||
},
|
||||
|
||||
@ -2933,7 +2933,7 @@ func TestResolveAuthKey(t *testing.T) {
|
||||
wantErrContains string
|
||||
}{
|
||||
{
|
||||
name: "successful resolution via OAuth client secret",
|
||||
name: "success-oauth-client-secret",
|
||||
clientSecret: "tskey-client-secret-123",
|
||||
oauthAvailable: true,
|
||||
resolveViaOAuth: func(ctx context.Context, clientSecret string, tags []string) (string, error) {
|
||||
@ -2946,7 +2946,7 @@ func TestResolveAuthKey(t *testing.T) {
|
||||
wantErrContains: "",
|
||||
},
|
||||
{
|
||||
name: "failing resolution via OAuth client secret",
|
||||
name: "fail-oauth-client-secret",
|
||||
clientSecret: "tskey-client-secret-123",
|
||||
oauthAvailable: true,
|
||||
resolveViaOAuth: func(ctx context.Context, clientSecret string, tags []string) (string, error) {
|
||||
@ -2955,7 +2955,7 @@ func TestResolveAuthKey(t *testing.T) {
|
||||
wantErrContains: "resolution failed",
|
||||
},
|
||||
{
|
||||
name: "successful resolution via federated ID token",
|
||||
name: "success-federated-id-token",
|
||||
clientID: "client-id-123",
|
||||
idToken: "id-token-456",
|
||||
wifAvailable: true,
|
||||
@ -2972,7 +2972,7 @@ func TestResolveAuthKey(t *testing.T) {
|
||||
wantErrContains: "",
|
||||
},
|
||||
{
|
||||
name: "successful resolution via federated audience",
|
||||
name: "success-federated-audience",
|
||||
clientID: "client-id-123",
|
||||
audience: "api.tailscale.com",
|
||||
wifAvailable: true,
|
||||
@ -2989,7 +2989,7 @@ func TestResolveAuthKey(t *testing.T) {
|
||||
wantErrContains: "",
|
||||
},
|
||||
{
|
||||
name: "failing resolution via federated ID token",
|
||||
name: "fail-federated-id-token",
|
||||
clientID: "client-id-123",
|
||||
idToken: "id-token-456",
|
||||
wifAvailable: true,
|
||||
@ -2999,7 +2999,7 @@ func TestResolveAuthKey(t *testing.T) {
|
||||
wantErrContains: "resolution failed",
|
||||
},
|
||||
{
|
||||
name: "empty client ID with ID token",
|
||||
name: "empty-client-id-with-token",
|
||||
clientID: "",
|
||||
idToken: "id-token-456",
|
||||
wifAvailable: true,
|
||||
@ -3009,7 +3009,7 @@ func TestResolveAuthKey(t *testing.T) {
|
||||
wantErrContains: "empty",
|
||||
},
|
||||
{
|
||||
name: "empty client ID with audience",
|
||||
name: "empty-client-id-with-audience",
|
||||
clientID: "",
|
||||
audience: "api.tailscale.com",
|
||||
wifAvailable: true,
|
||||
@ -3019,7 +3019,7 @@ func TestResolveAuthKey(t *testing.T) {
|
||||
wantErrContains: "empty",
|
||||
},
|
||||
{
|
||||
name: "empty ID token",
|
||||
name: "empty-id-token",
|
||||
clientID: "client-id-123",
|
||||
idToken: "",
|
||||
wifAvailable: true,
|
||||
@ -3029,7 +3029,7 @@ func TestResolveAuthKey(t *testing.T) {
|
||||
wantErrContains: "empty",
|
||||
},
|
||||
{
|
||||
name: "audience with ID token",
|
||||
name: "audience-with-id-token",
|
||||
clientID: "client-id-123",
|
||||
idToken: "id-token-456",
|
||||
audience: "api.tailscale.com",
|
||||
@ -3040,7 +3040,7 @@ func TestResolveAuthKey(t *testing.T) {
|
||||
wantErrContains: "only one of ID token and audience",
|
||||
},
|
||||
{
|
||||
name: "workload identity resolution skipped if resolution via OAuth token succeeds",
|
||||
name: "wif-skipped-oauth-succeeds",
|
||||
clientSecret: "tskey-client-secret-123",
|
||||
oauthAvailable: true,
|
||||
resolveViaOAuth: func(ctx context.Context, clientSecret string, tags []string) (string, error) {
|
||||
@ -3057,7 +3057,7 @@ func TestResolveAuthKey(t *testing.T) {
|
||||
wantErrContains: "",
|
||||
},
|
||||
{
|
||||
name: "workload identity resolution skipped if resolution via OAuth token fails",
|
||||
name: "wif-skipped-oauth-fails",
|
||||
clientID: "tskey-client-id-123",
|
||||
idToken: "",
|
||||
oauthAvailable: true,
|
||||
@ -3071,7 +3071,7 @@ func TestResolveAuthKey(t *testing.T) {
|
||||
wantErrContains: "failed",
|
||||
},
|
||||
{
|
||||
name: "authkey set and no resolution available",
|
||||
name: "authkey-set-no-resolution",
|
||||
authKey: "tskey-auth-123",
|
||||
oauthAvailable: false,
|
||||
wifAvailable: false,
|
||||
@ -3079,14 +3079,14 @@ func TestResolveAuthKey(t *testing.T) {
|
||||
wantErrContains: "",
|
||||
},
|
||||
{
|
||||
name: "no authkey set and no resolution available",
|
||||
name: "no-authkey-no-resolution",
|
||||
oauthAvailable: false,
|
||||
wifAvailable: false,
|
||||
wantAuthKey: "",
|
||||
wantErrContains: "",
|
||||
},
|
||||
{
|
||||
name: "authkey is client secret and resolution via OAuth client secret succeeds",
|
||||
name: "authkey-client-secret-oauth-succeeds",
|
||||
authKey: "tskey-client-secret-123",
|
||||
oauthAvailable: true,
|
||||
resolveViaOAuth: func(ctx context.Context, clientSecret string, tags []string) (string, error) {
|
||||
@ -3099,7 +3099,7 @@ func TestResolveAuthKey(t *testing.T) {
|
||||
wantErrContains: "",
|
||||
},
|
||||
{
|
||||
name: "authkey is client secret but resolution via OAuth client secret fails",
|
||||
name: "authkey-client-secret-oauth-fails",
|
||||
authKey: "tskey-client-secret-123",
|
||||
oauthAvailable: true,
|
||||
resolveViaOAuth: func(ctx context.Context, clientSecret string, tags []string) (string, error) {
|
||||
@ -3282,12 +3282,12 @@ func TestListenUnspecifiedAddr(t *testing.T) {
|
||||
|
||||
t.Run("Netstack", func(t *testing.T) {
|
||||
lt := setupTwoClientTest(t, false)
|
||||
t.Run("0.0.0.0", func(t *testing.T) { testUnspec(t, lt, "0.0.0.0:8080", "8080") })
|
||||
t.Run("v4-unspec", func(t *testing.T) { testUnspec(t, lt, "0.0.0.0:8080", "8080") })
|
||||
t.Run("::", func(t *testing.T) { testUnspec(t, lt, "[::]:8081", "8081") })
|
||||
})
|
||||
t.Run("TUN", func(t *testing.T) {
|
||||
lt := setupTwoClientTest(t, true)
|
||||
t.Run("0.0.0.0", func(t *testing.T) { testUnspec(t, lt, "0.0.0.0:8080", "8080") })
|
||||
t.Run("v4-unspec", func(t *testing.T) { testUnspec(t, lt, "0.0.0.0:8080", "8080") })
|
||||
t.Run("::", func(t *testing.T) { testUnspec(t, lt, "[::]:8081", "8081") })
|
||||
})
|
||||
}
|
||||
|
||||
@ -22,7 +22,7 @@ func TestClockWithDefinedStartTime(t *testing.T) {
|
||||
wants []time.Time // The return values of sequential calls to Now().
|
||||
}{
|
||||
{
|
||||
name: "increment ms",
|
||||
name: "increment-ms",
|
||||
start: time.Unix(12345, 1000),
|
||||
step: 1000,
|
||||
wants: []time.Time{
|
||||
@ -33,7 +33,7 @@ func TestClockWithDefinedStartTime(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "increment second",
|
||||
name: "increment-second",
|
||||
start: time.Unix(12345, 1000),
|
||||
step: time.Second,
|
||||
wants: []time.Time{
|
||||
@ -44,7 +44,7 @@ func TestClockWithDefinedStartTime(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no increment",
|
||||
name: "no-increment",
|
||||
start: time.Unix(12345, 1000),
|
||||
wants: []time.Time{
|
||||
time.Unix(12345, 1000),
|
||||
@ -91,7 +91,7 @@ func TestClockWithDefaultStartTime(t *testing.T) {
|
||||
wants []time.Duration // The return values of sequential calls to Now() after added to Start()
|
||||
}{
|
||||
{
|
||||
name: "increment ms",
|
||||
name: "increment-ms",
|
||||
step: 1000,
|
||||
wants: []time.Duration{
|
||||
0,
|
||||
@ -101,7 +101,7 @@ func TestClockWithDefaultStartTime(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "increment second",
|
||||
name: "increment-second",
|
||||
step: time.Second,
|
||||
wants: []time.Duration{
|
||||
0 * time.Second,
|
||||
@ -111,7 +111,7 @@ func TestClockWithDefaultStartTime(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no increment",
|
||||
name: "no-increment",
|
||||
wants: []time.Duration{0, 0, 0, 0},
|
||||
},
|
||||
}
|
||||
@ -177,7 +177,7 @@ func TestClockSetStep(t *testing.T) {
|
||||
wants []time.Time // The return values of sequential calls to Now().
|
||||
}{
|
||||
{
|
||||
name: "increment ms then s",
|
||||
name: "increment-ms-then-s",
|
||||
start: time.Unix(12345, 1000),
|
||||
step: 1000,
|
||||
stepChanges: []stepInfo{
|
||||
@ -198,7 +198,7 @@ func TestClockSetStep(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple changes over time",
|
||||
name: "multiple-changes-over-time",
|
||||
start: time.Unix(12345, 1000),
|
||||
step: 1,
|
||||
stepChanges: []stepInfo{
|
||||
@ -227,7 +227,7 @@ func TestClockSetStep(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple changes at once",
|
||||
name: "multiple-changes-at-once",
|
||||
start: time.Unix(12345, 1000),
|
||||
step: 1,
|
||||
stepChanges: []stepInfo{
|
||||
@ -252,7 +252,7 @@ func TestClockSetStep(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "changes at start",
|
||||
name: "changes-at-start",
|
||||
start: time.Unix(12345, 1000),
|
||||
step: 0,
|
||||
stepChanges: []stepInfo{
|
||||
@ -325,7 +325,7 @@ func TestClockAdvance(t *testing.T) {
|
||||
wants []time.Time // The return values of sequential calls to Now().
|
||||
}{
|
||||
{
|
||||
name: "increment ms then advance 1s",
|
||||
name: "increment-ms-then-advance-1s",
|
||||
start: time.Unix(12345, 1000),
|
||||
step: 1000,
|
||||
advances: []advanceInfo{
|
||||
@ -346,7 +346,7 @@ func TestClockAdvance(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple advances over time",
|
||||
name: "multiple-advances-over-time",
|
||||
start: time.Unix(12345, 1000),
|
||||
step: 1,
|
||||
advances: []advanceInfo{
|
||||
@ -375,7 +375,7 @@ func TestClockAdvance(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple advances at once",
|
||||
name: "multiple-advances-at-once",
|
||||
start: time.Unix(12345, 1000),
|
||||
step: 1,
|
||||
advances: []advanceInfo{
|
||||
@ -400,7 +400,7 @@ func TestClockAdvance(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "changes at start",
|
||||
name: "changes-at-start",
|
||||
start: time.Unix(12345, 1000),
|
||||
step: 5,
|
||||
advances: []advanceInfo{
|
||||
@ -489,7 +489,7 @@ func TestSingleTicker(t *testing.T) {
|
||||
steps []testStep
|
||||
}{
|
||||
{
|
||||
name: "no tick advance",
|
||||
name: "no-tick-advance",
|
||||
start: time.Unix(12345, 0),
|
||||
period: time.Second,
|
||||
steps: []testStep{
|
||||
@ -500,7 +500,7 @@ func TestSingleTicker(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no tick step",
|
||||
name: "no-tick-step",
|
||||
start: time.Unix(12345, 0),
|
||||
step: time.Second - 1,
|
||||
period: time.Second,
|
||||
@ -514,7 +514,7 @@ func TestSingleTicker(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "single tick advance exact",
|
||||
name: "single-tick-advance-exact",
|
||||
start: time.Unix(12345, 0),
|
||||
period: time.Second,
|
||||
steps: []testStep{
|
||||
@ -526,7 +526,7 @@ func TestSingleTicker(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "single tick advance extra",
|
||||
name: "single-tick-advance-extra",
|
||||
start: time.Unix(12345, 0),
|
||||
period: time.Second,
|
||||
steps: []testStep{
|
||||
@ -538,7 +538,7 @@ func TestSingleTicker(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "single tick step exact",
|
||||
name: "single-tick-step-exact",
|
||||
start: time.Unix(12345, 0),
|
||||
step: time.Second,
|
||||
period: time.Second,
|
||||
@ -553,7 +553,7 @@ func TestSingleTicker(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "single tick step extra",
|
||||
name: "single-tick-step-extra",
|
||||
start: time.Unix(12345, 0),
|
||||
step: time.Second + 1,
|
||||
period: time.Second,
|
||||
@ -568,7 +568,7 @@ func TestSingleTicker(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "single tick per advance",
|
||||
name: "single-tick-per-advance",
|
||||
start: time.Unix(12345, 0),
|
||||
period: 3 * time.Second,
|
||||
steps: []testStep{
|
||||
@ -597,7 +597,7 @@ func TestSingleTicker(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "single tick per step",
|
||||
name: "single-tick-per-step",
|
||||
start: time.Unix(12345, 0),
|
||||
step: 2 * time.Second,
|
||||
period: 3 * time.Second,
|
||||
@ -626,7 +626,7 @@ func TestSingleTicker(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple tick per advance",
|
||||
name: "multiple-tick-per-advance",
|
||||
start: time.Unix(12345, 0),
|
||||
period: time.Second,
|
||||
channelSize: 3,
|
||||
@ -655,7 +655,7 @@ func TestSingleTicker(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple tick per step",
|
||||
name: "multiple-tick-per-step",
|
||||
start: time.Unix(12345, 0),
|
||||
step: 3 * time.Second,
|
||||
period: 2 * time.Second,
|
||||
@ -723,7 +723,7 @@ func TestSingleTicker(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "reset while running",
|
||||
name: "reset-while-running",
|
||||
start: time.Unix(12345, 0),
|
||||
period: 2 * time.Second,
|
||||
steps: []testStep{
|
||||
@ -763,7 +763,7 @@ func TestSingleTicker(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "reset while stopped",
|
||||
name: "reset-while-stopped",
|
||||
start: time.Unix(12345, 0),
|
||||
step: time.Second,
|
||||
period: 2 * time.Second,
|
||||
@ -803,7 +803,7 @@ func TestSingleTicker(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "reset absolute",
|
||||
name: "reset-absolute",
|
||||
start: time.Unix(12345, 0),
|
||||
step: time.Second,
|
||||
period: 2 * time.Second,
|
||||
@ -841,7 +841,7 @@ func TestSingleTicker(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "follow real time",
|
||||
name: "follow-real-time",
|
||||
realTimeOpts: new(ClockOpts),
|
||||
start: time.Unix(12345, 0),
|
||||
period: 2 * time.Second,
|
||||
@ -965,7 +965,7 @@ func TestSingleTimer(t *testing.T) {
|
||||
steps []testStep
|
||||
}{
|
||||
{
|
||||
name: "no tick advance",
|
||||
name: "no-tick-advance",
|
||||
start: time.Unix(12345, 0),
|
||||
delay: time.Second,
|
||||
steps: []testStep{
|
||||
@ -976,7 +976,7 @@ func TestSingleTimer(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no tick step",
|
||||
name: "no-tick-step",
|
||||
start: time.Unix(12345, 0),
|
||||
step: time.Second - 1,
|
||||
delay: time.Second,
|
||||
@ -990,7 +990,7 @@ func TestSingleTimer(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "single tick advance exact",
|
||||
name: "single-tick-advance-exact",
|
||||
start: time.Unix(12345, 0),
|
||||
delay: time.Second,
|
||||
steps: []testStep{
|
||||
@ -1006,7 +1006,7 @@ func TestSingleTimer(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "single tick advance extra",
|
||||
name: "single-tick-advance-extra",
|
||||
start: time.Unix(12345, 0),
|
||||
delay: time.Second,
|
||||
steps: []testStep{
|
||||
@ -1022,7 +1022,7 @@ func TestSingleTimer(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "single tick step exact",
|
||||
name: "single-tick-step-exact",
|
||||
start: time.Unix(12345, 0),
|
||||
step: time.Second,
|
||||
delay: time.Second,
|
||||
@ -1040,7 +1040,7 @@ func TestSingleTimer(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "single tick step extra",
|
||||
name: "single-tick-step-extra",
|
||||
start: time.Unix(12345, 0),
|
||||
step: time.Second + 1,
|
||||
delay: time.Second,
|
||||
@ -1058,7 +1058,7 @@ func TestSingleTimer(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "reset for single tick per advance",
|
||||
name: "reset-for-single-tick-per-advance",
|
||||
start: time.Unix(12345, 0),
|
||||
delay: 3 * time.Second,
|
||||
steps: []testStep{
|
||||
@ -1093,7 +1093,7 @@ func TestSingleTimer(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "reset for single tick per step",
|
||||
name: "reset-for-single-tick-per-step",
|
||||
start: time.Unix(12345, 0),
|
||||
step: 2 * time.Second,
|
||||
delay: 3 * time.Second,
|
||||
@ -1124,7 +1124,7 @@ func TestSingleTimer(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "reset while active",
|
||||
name: "reset-while-active",
|
||||
start: time.Unix(12345, 0),
|
||||
step: 2 * time.Second,
|
||||
delay: 3 * time.Second,
|
||||
@ -1155,7 +1155,7 @@ func TestSingleTimer(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "stop after fire",
|
||||
name: "stop-after-fire",
|
||||
start: time.Unix(12345, 0),
|
||||
step: 2 * time.Second,
|
||||
delay: time.Second,
|
||||
@ -1181,7 +1181,7 @@ func TestSingleTimer(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "stop before fire",
|
||||
name: "stop-before-fire",
|
||||
start: time.Unix(12345, 0),
|
||||
step: 2 * time.Second,
|
||||
delay: time.Second,
|
||||
@ -1207,7 +1207,7 @@ func TestSingleTimer(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "stop after reset",
|
||||
name: "stop-after-reset",
|
||||
start: time.Unix(12345, 0),
|
||||
step: 2 * time.Second,
|
||||
delay: time.Second,
|
||||
@ -1235,7 +1235,7 @@ func TestSingleTimer(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "reset while running",
|
||||
name: "reset-while-running",
|
||||
start: time.Unix(12345, 0),
|
||||
delay: 2 * time.Second,
|
||||
steps: []testStep{
|
||||
@ -1275,7 +1275,7 @@ func TestSingleTimer(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "reset while stopped",
|
||||
name: "reset-while-stopped",
|
||||
start: time.Unix(12345, 0),
|
||||
step: time.Second,
|
||||
delay: 2 * time.Second,
|
||||
@ -1310,7 +1310,7 @@ func TestSingleTimer(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "reset absolute",
|
||||
name: "reset-absolute",
|
||||
start: time.Unix(12345, 0),
|
||||
step: time.Second,
|
||||
delay: 2 * time.Second,
|
||||
@ -1344,7 +1344,7 @@ func TestSingleTimer(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "follow real time",
|
||||
name: "follow-real-time",
|
||||
realTimeOpts: new(ClockOpts),
|
||||
start: time.Unix(12345, 0),
|
||||
delay: 2 * time.Second,
|
||||
@ -1705,7 +1705,7 @@ func TestClockFollowRealTime(t *testing.T) {
|
||||
wants []time.Time // The return values of sequential calls to Now().
|
||||
}{
|
||||
{
|
||||
name: "increment ms then advance 1s",
|
||||
name: "increment-ms-then-advance-1s",
|
||||
start: time.Unix(12345, 1000),
|
||||
wantStart: time.Unix(12345, 1000),
|
||||
advances: []advanceInfo{
|
||||
@ -1750,7 +1750,7 @@ func TestClockFollowRealTime(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple advances over time",
|
||||
name: "multiple-advances-over-time",
|
||||
start: time.Unix(12345, 1000),
|
||||
wantStart: time.Unix(12345, 1000),
|
||||
advances: []advanceInfo{
|
||||
@ -1795,7 +1795,7 @@ func TestClockFollowRealTime(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple advances at once",
|
||||
name: "multiple-advances-at-once",
|
||||
start: time.Unix(12345, 1000),
|
||||
wantStart: time.Unix(12345, 1000),
|
||||
advances: []advanceInfo{
|
||||
@ -1828,7 +1828,7 @@ func TestClockFollowRealTime(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "changes at start",
|
||||
name: "changes-at-start",
|
||||
start: time.Unix(12345, 1000),
|
||||
wantStart: time.Unix(12345, 1000),
|
||||
advances: []advanceInfo{
|
||||
@ -1861,7 +1861,7 @@ func TestClockFollowRealTime(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "start from current time",
|
||||
name: "start-from-current-time",
|
||||
realTimeClockOpts: ClockOpts{
|
||||
Start: time.Unix(12345, 0),
|
||||
},
|
||||
@ -1966,7 +1966,7 @@ func TestAfterFunc(t *testing.T) {
|
||||
steps []testStep
|
||||
}{
|
||||
{
|
||||
name: "no tick advance",
|
||||
name: "no-tick-advance",
|
||||
start: time.Unix(12345, 0),
|
||||
delay: time.Second,
|
||||
steps: []testStep{
|
||||
@ -1977,7 +1977,7 @@ func TestAfterFunc(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no tick step",
|
||||
name: "no-tick-step",
|
||||
start: time.Unix(12345, 0),
|
||||
step: time.Second - 1,
|
||||
delay: time.Second,
|
||||
@ -1991,7 +1991,7 @@ func TestAfterFunc(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "single tick advance exact",
|
||||
name: "single-tick-advance-exact",
|
||||
start: time.Unix(12345, 0),
|
||||
delay: time.Second,
|
||||
steps: []testStep{
|
||||
@ -2007,7 +2007,7 @@ func TestAfterFunc(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "single tick advance extra",
|
||||
name: "single-tick-advance-extra",
|
||||
start: time.Unix(12345, 0),
|
||||
delay: time.Second,
|
||||
steps: []testStep{
|
||||
@ -2023,7 +2023,7 @@ func TestAfterFunc(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "single tick step exact",
|
||||
name: "single-tick-step-exact",
|
||||
start: time.Unix(12345, 0),
|
||||
step: time.Second,
|
||||
delay: time.Second,
|
||||
@ -2041,7 +2041,7 @@ func TestAfterFunc(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "single tick step extra",
|
||||
name: "single-tick-step-extra",
|
||||
start: time.Unix(12345, 0),
|
||||
step: time.Second + 1,
|
||||
delay: time.Second,
|
||||
@ -2059,7 +2059,7 @@ func TestAfterFunc(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "reset for single tick per advance",
|
||||
name: "reset-for-single-tick-per-advance",
|
||||
start: time.Unix(12345, 0),
|
||||
delay: 3 * time.Second,
|
||||
steps: []testStep{
|
||||
@ -2094,7 +2094,7 @@ func TestAfterFunc(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "reset for single tick per step",
|
||||
name: "reset-for-single-tick-per-step",
|
||||
start: time.Unix(12345, 0),
|
||||
step: 2 * time.Second,
|
||||
delay: 3 * time.Second,
|
||||
@ -2125,7 +2125,7 @@ func TestAfterFunc(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "reset while active",
|
||||
name: "reset-while-active",
|
||||
start: time.Unix(12345, 0),
|
||||
step: 2 * time.Second,
|
||||
delay: 3 * time.Second,
|
||||
@ -2156,7 +2156,7 @@ func TestAfterFunc(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "stop after fire",
|
||||
name: "stop-after-fire",
|
||||
start: time.Unix(12345, 0),
|
||||
step: 2 * time.Second,
|
||||
delay: time.Second,
|
||||
@ -2182,7 +2182,7 @@ func TestAfterFunc(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "stop before fire",
|
||||
name: "stop-before-fire",
|
||||
start: time.Unix(12345, 0),
|
||||
step: 2 * time.Second,
|
||||
delay: time.Second,
|
||||
@ -2208,7 +2208,7 @@ func TestAfterFunc(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "stop after reset",
|
||||
name: "stop-after-reset",
|
||||
start: time.Unix(12345, 0),
|
||||
step: 2 * time.Second,
|
||||
delay: time.Second,
|
||||
@ -2236,7 +2236,7 @@ func TestAfterFunc(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "reset while running",
|
||||
name: "reset-while-running",
|
||||
start: time.Unix(12345, 0),
|
||||
delay: 2 * time.Second,
|
||||
steps: []testStep{
|
||||
@ -2270,7 +2270,7 @@ func TestAfterFunc(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "reset while stopped",
|
||||
name: "reset-while-stopped",
|
||||
start: time.Unix(12345, 0),
|
||||
step: time.Second,
|
||||
delay: 2 * time.Second,
|
||||
@ -2303,7 +2303,7 @@ func TestAfterFunc(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "reset absolute",
|
||||
name: "reset-absolute",
|
||||
start: time.Unix(12345, 0),
|
||||
step: time.Second,
|
||||
delay: 2 * time.Second,
|
||||
@ -2333,7 +2333,7 @@ func TestAfterFunc(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "follow real time",
|
||||
name: "follow-real-time",
|
||||
realTimeOpts: new(ClockOpts),
|
||||
start: time.Unix(12345, 0),
|
||||
delay: 2 * time.Second,
|
||||
|
||||
@ -355,7 +355,7 @@ func (h *Harness) testDistro(t *testing.T, d Distro, ipm ipMapping) {
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("tailscale status", func(t *testing.T) {
|
||||
t.Run("tailscale-status", func(t *testing.T) {
|
||||
dur := 100 * time.Millisecond
|
||||
var outp []byte
|
||||
var err error
|
||||
@ -383,7 +383,7 @@ func (h *Harness) testDistro(t *testing.T, d Distro, ipm ipMapping) {
|
||||
t.Fatalf("error: %v", err)
|
||||
})
|
||||
|
||||
t.Run("dump routes", func(t *testing.T) {
|
||||
t.Run("dump-routes", func(t *testing.T) {
|
||||
sess, err := cli.NewSession()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@ -22,7 +22,7 @@ func TestPrintGoroutines(t *testing.T) {
|
||||
want: "goroutine profile: total 0",
|
||||
},
|
||||
{
|
||||
name: "single goroutine",
|
||||
name: "single-goroutine",
|
||||
in: `goroutine profile: total 1
|
||||
1 @ 0x47bc0e 0x458e57 0x847587 0x483da1
|
||||
# 0x847586 database/sql.(*DB).connectionOpener+0x86 database/sql/sql.go:1261
|
||||
@ -34,7 +34,7 @@ func TestPrintGoroutines(t *testing.T) {
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "multiple goroutines sorted",
|
||||
name: "multiple-goroutines-sorted",
|
||||
in: `goroutine profile: total 14
|
||||
7 @ 0x47bc0e 0x413705 0x4132b2 0x10fda4d 0x483da1
|
||||
# 0x10fda4c github.com/user/pkg.RoutineA+0x16c pkg/a.go:443
|
||||
@ -70,7 +70,7 @@ func TestDiffPprofGoroutines(t *testing.T) {
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "no difference",
|
||||
name: "no-difference",
|
||||
x: `goroutine profile: total 1
|
||||
1 @ 0x47bc0e 0x458e57 0x847587 0x483da1
|
||||
# 0x847586 database/sql.(*DB).connectionOpener+0x86 database/sql/sql.go:1261`,
|
||||
@ -81,7 +81,7 @@ func TestDiffPprofGoroutines(t *testing.T) {
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
name: "different counts",
|
||||
name: "different-counts",
|
||||
x: `goroutine profile: total 1
|
||||
1 @ 0x47bc0e 0x458e57 0x847587 0x483da1
|
||||
# 0x847586 database/sql.(*DB).connectionOpener+0x86 database/sql/sql.go:1261
|
||||
@ -99,7 +99,7 @@ func TestDiffPprofGoroutines(t *testing.T) {
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "new goroutine",
|
||||
name: "new-goroutine",
|
||||
x: `goroutine profile: total 1
|
||||
1 @ 0x47bc0e 0x458e57 0x847587 0x483da1
|
||||
# 0x847586 database/sql.(*DB).connectionOpener+0x86 database/sql/sql.go:1261
|
||||
@ -119,7 +119,7 @@ func TestDiffPprofGoroutines(t *testing.T) {
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "removed goroutine",
|
||||
name: "removed-goroutine",
|
||||
x: `goroutine profile: total 2
|
||||
1 @ 0x47bc0e 0x458e57 0x847587 0x483da1
|
||||
# 0x847586 database/sql.(*DB).connectionOpener+0x86 database/sql/sql.go:1261
|
||||
@ -139,7 +139,7 @@ func TestDiffPprofGoroutines(t *testing.T) {
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "removed many goroutine",
|
||||
name: "removed-many-goroutine",
|
||||
x: `goroutine profile: total 2
|
||||
1 @ 0x47bc0e 0x458e57 0x847587 0x483da1
|
||||
# 0x847586 database/sql.(*DB).connectionOpener+0x86 database/sql/sql.go:1261
|
||||
@ -159,13 +159,13 @@ func TestDiffPprofGoroutines(t *testing.T) {
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "invalid input x",
|
||||
name: "invalid-input-x",
|
||||
x: "invalid",
|
||||
y: "goroutine profile: total 0\n",
|
||||
want: "- invalid\n+ goroutine profile: total 0\n",
|
||||
},
|
||||
{
|
||||
name: "invalid input y",
|
||||
name: "invalid-input-y",
|
||||
x: "goroutine profile: total 0\n",
|
||||
y: "invalid",
|
||||
want: "- goroutine profile: total 0\n+ invalid\n",
|
||||
@ -193,13 +193,13 @@ func TestParseGoroutines(t *testing.T) {
|
||||
wantCount int
|
||||
}{
|
||||
{
|
||||
name: "empty profile",
|
||||
name: "empty-profile",
|
||||
in: "goroutine profile: total 0\n",
|
||||
wantHeader: "goroutine profile: total 0",
|
||||
wantCount: 0,
|
||||
},
|
||||
{
|
||||
name: "single goroutine",
|
||||
name: "single-goroutine",
|
||||
in: `goroutine profile: total 1
|
||||
1 @ 0x47bc0e 0x458e57 0x847587 0x483da1
|
||||
# 0x847586 database/sql.(*DB).connectionOpener+0x86 database/sql/sql.go:1261
|
||||
@ -208,7 +208,7 @@ func TestParseGoroutines(t *testing.T) {
|
||||
wantCount: 1,
|
||||
},
|
||||
{
|
||||
name: "multiple goroutines",
|
||||
name: "multiple-goroutines",
|
||||
in: `goroutine profile: total 14
|
||||
7 @ 0x47bc0e 0x413705 0x4132b2 0x10fda4d 0x483da1
|
||||
# 0x10fda4c github.com/user/pkg.RoutineA+0x16c pkg/a.go:443
|
||||
@ -220,7 +220,7 @@ func TestParseGoroutines(t *testing.T) {
|
||||
wantCount: 2,
|
||||
},
|
||||
{
|
||||
name: "invalid format",
|
||||
name: "invalid-format",
|
||||
in: "invalid",
|
||||
wantHeader: "invalid",
|
||||
},
|
||||
|
||||
@ -85,7 +85,7 @@ func TestStdHandler(t *testing.T) {
|
||||
wantBody string
|
||||
}{
|
||||
{
|
||||
name: "handler returns 200",
|
||||
name: "handler-returns-200",
|
||||
rh: handlerCode(200),
|
||||
r: req(bgCtx, "http://example.com/"),
|
||||
wantCode: 200,
|
||||
@ -102,7 +102,7 @@ func TestStdHandler(t *testing.T) {
|
||||
},
|
||||
|
||||
{
|
||||
name: "handler returns 200 with request ID",
|
||||
name: "handler-returns-200-with-request-ID",
|
||||
rh: handlerCode(200),
|
||||
r: req(bgCtx, "http://example.com/"),
|
||||
wantCode: 200,
|
||||
@ -119,7 +119,7 @@ func TestStdHandler(t *testing.T) {
|
||||
},
|
||||
|
||||
{
|
||||
name: "handler returns 404",
|
||||
name: "handler-returns-404",
|
||||
rh: handlerCode(404),
|
||||
r: req(bgCtx, "http://example.com/foo"),
|
||||
wantCode: 404,
|
||||
@ -135,7 +135,7 @@ func TestStdHandler(t *testing.T) {
|
||||
},
|
||||
|
||||
{
|
||||
name: "handler returns 404 with request ID",
|
||||
name: "handler-returns-404-with-request-ID",
|
||||
rh: handlerCode(404),
|
||||
r: req(bgCtx, "http://example.com/foo"),
|
||||
wantCode: 404,
|
||||
@ -151,7 +151,7 @@ func TestStdHandler(t *testing.T) {
|
||||
},
|
||||
|
||||
{
|
||||
name: "handler returns 404 via HTTPError",
|
||||
name: "handler-returns-404-via-HTTPError",
|
||||
rh: handlerErr(0, Error(404, "not found", testErr)),
|
||||
r: req(bgCtx, "http://example.com/foo"),
|
||||
wantCode: 404,
|
||||
@ -169,7 +169,7 @@ func TestStdHandler(t *testing.T) {
|
||||
},
|
||||
|
||||
{
|
||||
name: "handler returns 404 via HTTPError with request ID",
|
||||
name: "handler-returns-404-via-HTTPError-with-request-ID",
|
||||
rh: handlerErr(0, Error(404, "not found", testErr)),
|
||||
r: req(RequestIDKey.WithValue(bgCtx, exampleRequestID), "http://example.com/foo"),
|
||||
wantCode: 404,
|
||||
@ -188,7 +188,7 @@ func TestStdHandler(t *testing.T) {
|
||||
},
|
||||
|
||||
{
|
||||
name: "handler returns 404 with nil child error",
|
||||
name: "handler-returns-404-nil-child-error",
|
||||
rh: handlerErr(0, Error(404, "not found", nil)),
|
||||
r: req(bgCtx, "http://example.com/foo"),
|
||||
wantCode: 404,
|
||||
@ -206,7 +206,7 @@ func TestStdHandler(t *testing.T) {
|
||||
},
|
||||
|
||||
{
|
||||
name: "handler returns 404 with request ID and nil child error",
|
||||
name: "handler-returns-404-request-ID-nil-child-error",
|
||||
rh: handlerErr(0, Error(404, "not found", nil)),
|
||||
r: req(RequestIDKey.WithValue(bgCtx, exampleRequestID), "http://example.com/foo"),
|
||||
wantCode: 404,
|
||||
@ -225,7 +225,7 @@ func TestStdHandler(t *testing.T) {
|
||||
},
|
||||
|
||||
{
|
||||
name: "handler returns user-visible error",
|
||||
name: "handler-returns-user-visible-error",
|
||||
rh: handlerErr(0, vizerror.New("visible error")),
|
||||
r: req(bgCtx, "http://example.com/foo"),
|
||||
wantCode: 500,
|
||||
@ -243,7 +243,7 @@ func TestStdHandler(t *testing.T) {
|
||||
},
|
||||
|
||||
{
|
||||
name: "handler returns user-visible error with request ID",
|
||||
name: "handler-returns-user-visible-error-with-request-ID",
|
||||
rh: handlerErr(0, vizerror.New("visible error")),
|
||||
r: req(RequestIDKey.WithValue(bgCtx, exampleRequestID), "http://example.com/foo"),
|
||||
wantCode: 500,
|
||||
@ -262,7 +262,7 @@ func TestStdHandler(t *testing.T) {
|
||||
},
|
||||
|
||||
{
|
||||
name: "handler returns user-visible error wrapped by private error",
|
||||
name: "handler-returns-vizerror-wrapped-by-private-error",
|
||||
rh: handlerErr(0, fmt.Errorf("private internal error: %w", vizerror.New("visible error"))),
|
||||
r: req(bgCtx, "http://example.com/foo"),
|
||||
wantCode: 500,
|
||||
@ -280,7 +280,7 @@ func TestStdHandler(t *testing.T) {
|
||||
},
|
||||
|
||||
{
|
||||
name: "handler returns JSON-formatted HTTPError",
|
||||
name: "handler-returns-JSON-formatted-HTTPError",
|
||||
rh: ReturnHandlerFunc(func(w http.ResponseWriter, r *http.Request) error {
|
||||
h := Error(http.StatusBadRequest, `{"isjson": true}`, errors.New("uh"))
|
||||
h.Header = http.Header{"Content-Type": {"application/json"}}
|
||||
@ -303,7 +303,7 @@ func TestStdHandler(t *testing.T) {
|
||||
},
|
||||
|
||||
{
|
||||
name: "handler returns user-visible error wrapped by private error with request ID",
|
||||
name: "handler-returns-vizerror-wrapped-by-private-error-with-request-ID",
|
||||
rh: handlerErr(0, fmt.Errorf("private internal error: %w", vizerror.New("visible error"))),
|
||||
r: req(RequestIDKey.WithValue(bgCtx, exampleRequestID), "http://example.com/foo"),
|
||||
wantCode: 500,
|
||||
@ -322,7 +322,7 @@ func TestStdHandler(t *testing.T) {
|
||||
},
|
||||
|
||||
{
|
||||
name: "handler returns generic error",
|
||||
name: "handler-returns-generic-error",
|
||||
rh: handlerErr(0, testErr),
|
||||
r: req(bgCtx, "http://example.com/foo"),
|
||||
wantCode: 500,
|
||||
@ -340,7 +340,7 @@ func TestStdHandler(t *testing.T) {
|
||||
},
|
||||
|
||||
{
|
||||
name: "handler returns generic error with request ID",
|
||||
name: "handler-returns-generic-error-with-request-ID",
|
||||
rh: handlerErr(0, testErr),
|
||||
r: req(RequestIDKey.WithValue(bgCtx, exampleRequestID), "http://example.com/foo"),
|
||||
wantCode: 500,
|
||||
@ -359,7 +359,7 @@ func TestStdHandler(t *testing.T) {
|
||||
},
|
||||
|
||||
{
|
||||
name: "handler returns error after writing response",
|
||||
name: "handler-returns-error-after-writing-response",
|
||||
rh: handlerErr(200, testErr),
|
||||
r: req(bgCtx, "http://example.com/foo"),
|
||||
wantCode: 200,
|
||||
@ -376,7 +376,7 @@ func TestStdHandler(t *testing.T) {
|
||||
},
|
||||
|
||||
{
|
||||
name: "handler returns error after writing response with request ID",
|
||||
name: "handler-returns-error-after-writing-response-with-request-ID",
|
||||
rh: handlerErr(200, testErr),
|
||||
r: req(RequestIDKey.WithValue(bgCtx, exampleRequestID), "http://example.com/foo"),
|
||||
wantCode: 200,
|
||||
@ -394,7 +394,7 @@ func TestStdHandler(t *testing.T) {
|
||||
},
|
||||
|
||||
{
|
||||
name: "handler returns HTTPError after writing response",
|
||||
name: "handler-returns-HTTPError-after-writing-response",
|
||||
rh: handlerErr(200, Error(404, "not found", testErr)),
|
||||
r: req(bgCtx, "http://example.com/foo"),
|
||||
wantCode: 200,
|
||||
@ -411,7 +411,7 @@ func TestStdHandler(t *testing.T) {
|
||||
},
|
||||
|
||||
{
|
||||
name: "handler does nothing",
|
||||
name: "handler-does-nothing",
|
||||
rh: handlerFunc(func(http.ResponseWriter, *http.Request) error { return nil }),
|
||||
r: req(bgCtx, "http://example.com/foo"),
|
||||
wantCode: 200,
|
||||
@ -427,7 +427,7 @@ func TestStdHandler(t *testing.T) {
|
||||
},
|
||||
|
||||
{
|
||||
name: "handler hijacks conn",
|
||||
name: "handler-hijacks-conn",
|
||||
rh: handlerFunc(func(w http.ResponseWriter, r *http.Request) error {
|
||||
_, _, err := w.(http.Hijacker).Hijack()
|
||||
if err != nil {
|
||||
@ -450,7 +450,7 @@ func TestStdHandler(t *testing.T) {
|
||||
},
|
||||
|
||||
{
|
||||
name: "error handler gets run",
|
||||
name: "error-handler-gets-run",
|
||||
rh: handlerErr(0, Error(404, "not found", nil)), // status code changed in errHandler
|
||||
r: req(bgCtx, "http://example.com/"),
|
||||
wantCode: 200,
|
||||
@ -472,7 +472,7 @@ func TestStdHandler(t *testing.T) {
|
||||
},
|
||||
|
||||
{
|
||||
name: "error handler gets run with request ID",
|
||||
name: "error-handler-gets-run-with-request-ID",
|
||||
rh: handlerErr(0, Error(404, "not found", nil)), // status code changed in errHandler
|
||||
r: req(RequestIDKey.WithValue(bgCtx, exampleRequestID), "http://example.com/"),
|
||||
wantCode: 200,
|
||||
|
||||
@ -33,13 +33,13 @@ func TestResolverEqual(t *testing.T) {
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "nil vs non-nil",
|
||||
name: "nil-vs-non-nil",
|
||||
a: nil,
|
||||
b: &Resolver{},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "non-nil vs nil",
|
||||
name: "non-nil-vs-nil",
|
||||
a: &Resolver{},
|
||||
b: nil,
|
||||
want: false,
|
||||
@ -51,13 +51,13 @@ func TestResolverEqual(t *testing.T) {
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "not equal addrs",
|
||||
name: "not-equal-addrs",
|
||||
a: &Resolver{Addr: "dns.example.com"},
|
||||
b: &Resolver{Addr: "dns2.example.com"},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "not equal bootstrap",
|
||||
name: "not-equal-bootstrap",
|
||||
a: &Resolver{
|
||||
Addr: "dns.example.com",
|
||||
BootstrapResolution: []netip.Addr{netip.MustParseAddr("8.8.8.8")},
|
||||
@ -69,13 +69,13 @@ func TestResolverEqual(t *testing.T) {
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "equal UseWithExitNode",
|
||||
name: "equal-UseWithExitNode",
|
||||
a: &Resolver{Addr: "dns.example.com", UseWithExitNode: true},
|
||||
b: &Resolver{Addr: "dns.example.com", UseWithExitNode: true},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "not equal UseWithExitNode",
|
||||
name: "not-equal-UseWithExitNode",
|
||||
a: &Resolver{Addr: "dns.example.com", UseWithExitNode: true},
|
||||
b: &Resolver{Addr: "dns.example.com", UseWithExitNode: false},
|
||||
want: false,
|
||||
|
||||
@ -16,77 +16,77 @@ func TestCompare(t *testing.T) {
|
||||
want int
|
||||
}{
|
||||
{
|
||||
name: "both empty",
|
||||
name: "both-empty",
|
||||
want: 0,
|
||||
},
|
||||
{
|
||||
name: "v1 empty",
|
||||
name: "v1-empty",
|
||||
v2: "1.2.3",
|
||||
want: -1,
|
||||
},
|
||||
{
|
||||
name: "v2 empty",
|
||||
name: "v2-empty",
|
||||
v1: "1.2.3",
|
||||
want: 1,
|
||||
},
|
||||
|
||||
{
|
||||
name: "semver major",
|
||||
name: "semver-major",
|
||||
v1: "2.0.0",
|
||||
v2: "1.9.9",
|
||||
want: 1,
|
||||
},
|
||||
{
|
||||
name: "semver major",
|
||||
name: "semver-major",
|
||||
v1: "2.0.0",
|
||||
v2: "1.9.9",
|
||||
want: 1,
|
||||
},
|
||||
{
|
||||
name: "semver minor",
|
||||
name: "semver-minor",
|
||||
v1: "1.9.0",
|
||||
v2: "1.8.9",
|
||||
want: 1,
|
||||
},
|
||||
{
|
||||
name: "semver patch",
|
||||
name: "semver-patch",
|
||||
v1: "1.9.9",
|
||||
v2: "1.9.8",
|
||||
want: 1,
|
||||
},
|
||||
{
|
||||
name: "semver equal",
|
||||
name: "semver-equal",
|
||||
v1: "1.9.8",
|
||||
v2: "1.9.8",
|
||||
want: 0,
|
||||
},
|
||||
|
||||
{
|
||||
name: "tailscale major",
|
||||
name: "tailscale-major",
|
||||
v1: "1.0-0",
|
||||
v2: "0.97-105",
|
||||
want: 1,
|
||||
},
|
||||
{
|
||||
name: "tailscale minor",
|
||||
name: "tailscale-minor",
|
||||
v1: "0.98-0",
|
||||
v2: "0.97-105",
|
||||
want: 1,
|
||||
},
|
||||
{
|
||||
name: "tailscale patch",
|
||||
name: "tailscale-patch",
|
||||
v1: "0.97-120",
|
||||
v2: "0.97-105",
|
||||
want: 1,
|
||||
},
|
||||
{
|
||||
name: "tailscale equal",
|
||||
name: "tailscale-equal",
|
||||
v1: "0.97-105",
|
||||
v2: "0.97-105",
|
||||
want: 0,
|
||||
},
|
||||
{
|
||||
name: "tailscale weird extra field",
|
||||
name: "tailscale-weird-extra-field",
|
||||
v1: "0.96.1-0", // more fields == larger
|
||||
v2: "0.96-105",
|
||||
want: 1,
|
||||
@ -96,7 +96,7 @@ func TestCompare(t *testing.T) {
|
||||
// of strconv.ParseUint with these characters would have lead us to
|
||||
// panic. We're now only looking at ascii numbers, so test these are
|
||||
// compared as text.
|
||||
name: "only ascii numbers",
|
||||
name: "only-ascii-numbers",
|
||||
v1: "۱۱", // 2x EXTENDED ARABIC-INDIC DIGIT ONE
|
||||
v2: "۲", // 1x EXTENDED ARABIC-INDIC DIGIT TWO
|
||||
want: -1,
|
||||
@ -104,55 +104,55 @@ func TestCompare(t *testing.T) {
|
||||
|
||||
// A few specific OS version tests below.
|
||||
{
|
||||
name: "windows version",
|
||||
name: "windows-version",
|
||||
v1: "10.0.19045.3324",
|
||||
v2: "10.0.18362",
|
||||
want: 1,
|
||||
},
|
||||
{
|
||||
name: "windows 11 is everything above 10.0.22000",
|
||||
name: "windows-11-above-10_0_22000",
|
||||
v1: "10.0.22631.2262",
|
||||
v2: "10.0.22000",
|
||||
want: 1,
|
||||
},
|
||||
{
|
||||
name: "android short version",
|
||||
name: "android-short-version",
|
||||
v1: "10",
|
||||
v2: "7",
|
||||
want: 1,
|
||||
},
|
||||
{
|
||||
name: "android longer version",
|
||||
name: "android-longer-version",
|
||||
v1: "7.1.2",
|
||||
v2: "7",
|
||||
want: 1,
|
||||
},
|
||||
{
|
||||
name: "iOS version",
|
||||
name: "iOS-version",
|
||||
v1: "15.6.1",
|
||||
v2: "15.6",
|
||||
want: 1,
|
||||
},
|
||||
{
|
||||
name: "Linux short kernel version",
|
||||
name: "linux-short-kernel-version",
|
||||
v1: "4.4.302+",
|
||||
v2: "4.0",
|
||||
want: 1,
|
||||
},
|
||||
{
|
||||
name: "Linux long kernel version",
|
||||
name: "linux-long-kernel-version",
|
||||
v1: "4.14.255-311-248.529.amzn2.x86_64",
|
||||
v2: "4.0",
|
||||
want: 1,
|
||||
},
|
||||
{
|
||||
name: "FreeBSD version",
|
||||
name: "freebsd-version",
|
||||
v1: "14.0-CURRENT",
|
||||
v2: "14",
|
||||
want: 1,
|
||||
},
|
||||
{
|
||||
name: "Synology version",
|
||||
name: "synology-version",
|
||||
v1: "Synology 6.2.4; kernel=3.10.105",
|
||||
v2: "Synology 6",
|
||||
want: 1,
|
||||
|
||||
@ -360,17 +360,17 @@ func TestGetTypeHasher(t *testing.T) {
|
||||
out32: "\x01\x04\x00\x00\x00\x00\x00\x00\x00\x01\x03\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00*\v\x00\x00\x00\x00\x00\x00\x0010.1.3.4/32\v\x00\x00\x00\x00\x00\x00\x0010.0.0.0/24\x00\x01\x01\x00\x00\x00\x00\x00\x00\x00\n\x00\x00\x00\x00\x00\x00\x001.2.3.4/32\x01 \x00\x00\x00\x01\x00\x02\x00\x01\x04\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00\x01\x01\x00\x00\x00\x00\x00\x00\x00\x01\x01\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04!\x01\x01\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00foo\x00\x01\x01\x00\x00\x00\x00\x00\x00\x00\v\x00\x00\x00\x00\x00\x00\x00foooooooooo\x00\x01\x01\x00\x00\x00\x00\x00\x00\x00\f\x00\x00\x00\x00\x00\x00\x00baaaaaarrrrr\x00\x01\x00\x02\x00\x00\x00\x01\x01\x00\x00\x00\x00\x00\x00\x00\v\x00\x00\x00\x00\x00\x00\x00foooooooooo\x00\x01\x01\x00\x00\x00\x00\x00\x00\x00\f\x00\x00\x00\x00\x00\x00\x00baaaaaarrrrr\x00\x01\x00\x02\x00\x00\x00\x01\x01\x00\x00\x00\x00\x00\x00\x00\v\x00\x00\x00\x00\x00\x00\x00foooooooooo\x00\x01\x01\x00\x00\x00\x00\x00\x00\x00\f\x00\x00\x00\x00\x00\x00\x00baaaaaarrrrr\x00\x01\x00\x02\x00\x00\x00",
|
||||
},
|
||||
{
|
||||
name: "netip.Addr",
|
||||
name: "netip-Addr",
|
||||
val: netip.MustParseAddr("fe80::123%foo"),
|
||||
out: u64(16+3) + u64(0x80fe) + u64(0x2301<<48) + "foo",
|
||||
},
|
||||
{
|
||||
name: "ptr-netip.Addr",
|
||||
name: "ptr-netip-Addr",
|
||||
val: &someIP,
|
||||
out: u8(1) + u64(4) + u32(0x04030201),
|
||||
},
|
||||
{
|
||||
name: "ptr-nil-netip.Addr",
|
||||
name: "ptr-nil-netip-Addr",
|
||||
val: (*netip.Addr)(nil),
|
||||
out: "\x00",
|
||||
},
|
||||
@ -469,7 +469,7 @@ func TestGetTypeHasher(t *testing.T) {
|
||||
out: "\x01\x01\x00\x00\x00\x02\x00\x00\x00\x03\x04\x00\x00\x00\x05\x00\x00\x00\x06\x00\x00\x00\a\b\x00\x00\x00",
|
||||
},
|
||||
{
|
||||
name: "tailcfg.Node",
|
||||
name: "tailcfg-Node",
|
||||
val: &tailcfg.Node{},
|
||||
out: "ANY", // magic value; just check it doesn't fail to hash
|
||||
out32: "ANY",
|
||||
|
||||
@ -36,17 +36,17 @@ func TestExpectFilter(t *testing.T) {
|
||||
wantErr string // if non-empty, an error is expected containing this text
|
||||
}{
|
||||
{
|
||||
name: "single event",
|
||||
name: "single-event",
|
||||
events: []int{42},
|
||||
expectFunc: eventbustest.Type[EventFoo](),
|
||||
},
|
||||
{
|
||||
name: "multiple events, single expectation",
|
||||
name: "multiple-events-single-expectation",
|
||||
events: []int{42, 1, 2, 3, 4, 5},
|
||||
expectFunc: eventbustest.Type[EventFoo](),
|
||||
},
|
||||
{
|
||||
name: "filter on event with function",
|
||||
name: "filter-on-event-with-function",
|
||||
events: []int{24, 42},
|
||||
expectFunc: func(event EventFoo) (bool, error) {
|
||||
if event.Value == 42 {
|
||||
@ -77,7 +77,7 @@ func TestExpectFilter(t *testing.T) {
|
||||
wantErr: "value > 10",
|
||||
},
|
||||
{
|
||||
name: "first event has to be func",
|
||||
name: "first-event-has-to-be-func",
|
||||
events: []int{24, 42},
|
||||
expectFunc: func(event EventFoo) (bool, error) {
|
||||
if event.Value != 42 {
|
||||
@ -99,7 +99,7 @@ func TestExpectFilter(t *testing.T) {
|
||||
wantErr: "wrong result (-got, +want)",
|
||||
},
|
||||
{
|
||||
name: "no events",
|
||||
name: "no-events",
|
||||
events: []int{},
|
||||
expectFunc: func(event EventFoo) (bool, error) {
|
||||
return true, nil
|
||||
@ -151,37 +151,37 @@ func TestExpectEvents(t *testing.T) {
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "No expectations",
|
||||
name: "no-expectations",
|
||||
events: []any{EventFoo{}},
|
||||
expectEvents: []any{},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "One event",
|
||||
name: "one-event",
|
||||
events: []any{EventFoo{}},
|
||||
expectEvents: []any{eventbustest.Type[EventFoo]()},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Two events",
|
||||
name: "two-events",
|
||||
events: []any{EventFoo{}, EventBar{}},
|
||||
expectEvents: []any{eventbustest.Type[EventFoo](), eventbustest.Type[EventBar]()},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Two expected events with another in the middle",
|
||||
name: "two-expected-events-with-another-in-middle",
|
||||
events: []any{EventFoo{}, EventBaz{}, EventBar{}},
|
||||
expectEvents: []any{eventbustest.Type[EventFoo](), eventbustest.Type[EventBar]()},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Missing event",
|
||||
name: "missing-event",
|
||||
events: []any{EventFoo{}, EventBaz{}},
|
||||
expectEvents: []any{eventbustest.Type[EventFoo](), eventbustest.Type[EventBar]()},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "One event with specific value",
|
||||
name: "one-event-with-specific-value",
|
||||
events: []any{EventFoo{42}},
|
||||
expectEvents: []any{
|
||||
func(ev EventFoo) (bool, error) {
|
||||
@ -194,7 +194,7 @@ func TestExpectEvents(t *testing.T) {
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Two event with one specific value",
|
||||
name: "two-events-with-one-specific-value",
|
||||
events: []any{EventFoo{43}, EventFoo{42}},
|
||||
expectEvents: []any{
|
||||
func(ev EventFoo) (bool, error) {
|
||||
@ -207,7 +207,7 @@ func TestExpectEvents(t *testing.T) {
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "One event with wrong value",
|
||||
name: "one-event-with-wrong-value",
|
||||
events: []any{EventFoo{43}},
|
||||
expectEvents: []any{
|
||||
func(ev EventFoo) (bool, error) {
|
||||
@ -220,7 +220,7 @@ func TestExpectEvents(t *testing.T) {
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Two events with specific values",
|
||||
name: "two-events-with-specific-values",
|
||||
events: []any{EventFoo{42}, EventFoo{42}, EventBar{"42"}},
|
||||
expectEvents: []any{
|
||||
func(ev EventFoo) (bool, error) {
|
||||
@ -283,37 +283,37 @@ func TestExpectExactlyEventsFilter(t *testing.T) {
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "No expectations",
|
||||
name: "no-expectations",
|
||||
events: []any{EventFoo{}},
|
||||
expectEvents: []any{},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "One event",
|
||||
name: "one-event",
|
||||
events: []any{EventFoo{}},
|
||||
expectEvents: []any{eventbustest.Type[EventFoo]()},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Two events",
|
||||
name: "two-events",
|
||||
events: []any{EventFoo{}, EventBar{}},
|
||||
expectEvents: []any{eventbustest.Type[EventFoo](), eventbustest.Type[EventBar]()},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Two expected events with another in the middle",
|
||||
name: "two-expected-events-with-another-in-middle",
|
||||
events: []any{EventFoo{}, EventBaz{}, EventBar{}},
|
||||
expectEvents: []any{eventbustest.Type[EventFoo](), eventbustest.Type[EventBar]()},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Missing event",
|
||||
name: "missing-event",
|
||||
events: []any{EventFoo{}, EventBaz{}},
|
||||
expectEvents: []any{eventbustest.Type[EventFoo](), eventbustest.Type[EventBar]()},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "One event with value",
|
||||
name: "one-event-with-value",
|
||||
events: []any{EventFoo{42}},
|
||||
expectEvents: []any{
|
||||
func(ev EventFoo) (bool, error) {
|
||||
@ -326,7 +326,7 @@ func TestExpectExactlyEventsFilter(t *testing.T) {
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Two event with one specific value",
|
||||
name: "two-events-with-one-specific-value",
|
||||
events: []any{EventFoo{43}, EventFoo{42}},
|
||||
expectEvents: []any{
|
||||
func(ev EventFoo) (bool, error) {
|
||||
@ -339,7 +339,7 @@ func TestExpectExactlyEventsFilter(t *testing.T) {
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "One event with wrong value",
|
||||
name: "one-event-with-wrong-value",
|
||||
events: []any{EventFoo{43}},
|
||||
expectEvents: []any{
|
||||
func(ev EventFoo) (bool, error) {
|
||||
@ -352,7 +352,7 @@ func TestExpectExactlyEventsFilter(t *testing.T) {
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Two events with specific values",
|
||||
name: "two-events-with-specific-values",
|
||||
events: []any{EventFoo{42}, EventFoo{42}, EventBar{"42"}},
|
||||
expectEvents: []any{
|
||||
func(ev EventFoo) (bool, error) {
|
||||
|
||||
@ -960,32 +960,32 @@ func TestPickFirewallModeFromInstalledRules(t *testing.T) {
|
||||
want FirewallMode
|
||||
}{
|
||||
{
|
||||
name: "using iptables legacy",
|
||||
name: "using-iptables-legacy",
|
||||
det: &testFWDetector{iptRuleCount: 1},
|
||||
want: FirewallModeIPTables,
|
||||
},
|
||||
{
|
||||
name: "using nftables",
|
||||
name: "using-nftables",
|
||||
det: &testFWDetector{nftRuleCount: 1},
|
||||
want: FirewallModeNfTables,
|
||||
},
|
||||
{
|
||||
name: "using both iptables and nftables",
|
||||
name: "using-both-iptables-and-nftables",
|
||||
det: &testFWDetector{iptRuleCount: 2, nftRuleCount: 2},
|
||||
want: FirewallModeNfTables,
|
||||
},
|
||||
{
|
||||
name: "not using any firewall, both available",
|
||||
name: "no-firewall-both-available",
|
||||
det: &testFWDetector{},
|
||||
want: FirewallModeNfTables,
|
||||
},
|
||||
{
|
||||
name: "not using any firewall, iptables available only",
|
||||
name: "no-firewall-iptables-only",
|
||||
det: &testFWDetector{iptRuleCount: 1, nftErr: errors.New("nft error")},
|
||||
want: FirewallModeIPTables,
|
||||
},
|
||||
{
|
||||
name: "not using any firewall, nftables available only",
|
||||
name: "no-firewall-nftables-only",
|
||||
det: &testFWDetector{iptErr: errors.New("iptables error"), nftRuleCount: 1},
|
||||
want: FirewallModeNfTables,
|
||||
},
|
||||
|
||||
@ -226,42 +226,42 @@ func TestPolicyScopeContains(t *testing.T) {
|
||||
wantAStrictlyContainsB: false,
|
||||
},
|
||||
{
|
||||
name: "UserScope(1234)/UserScope(1234)",
|
||||
name: "UserScope-1234/UserScope-1234",
|
||||
scopeA: UserScopeOf("1234"),
|
||||
scopeB: UserScopeOf("1234"),
|
||||
wantAContainsB: true,
|
||||
wantAStrictlyContainsB: false,
|
||||
},
|
||||
{
|
||||
name: "UserScope(1234)/UserScope(5678)",
|
||||
name: "UserScope-1234/UserScope-5678",
|
||||
scopeA: UserScopeOf("1234"),
|
||||
scopeB: UserScopeOf("5678"),
|
||||
wantAContainsB: false,
|
||||
wantAStrictlyContainsB: false,
|
||||
},
|
||||
{
|
||||
name: "ProfileScope(A)/UserScope(A/1234)",
|
||||
name: "ProfileScope-A/UserScope-A-1234",
|
||||
scopeA: PolicyScope{kind: ProfileSetting, profileID: "A"},
|
||||
scopeB: PolicyScope{kind: UserSetting, userID: "1234", profileID: "A"},
|
||||
wantAContainsB: true,
|
||||
wantAStrictlyContainsB: true,
|
||||
},
|
||||
{
|
||||
name: "ProfileScope(A)/UserScope(B/1234)",
|
||||
name: "ProfileScope-A/UserScope-B-1234",
|
||||
scopeA: PolicyScope{kind: ProfileSetting, profileID: "A"},
|
||||
scopeB: PolicyScope{kind: UserSetting, userID: "1234", profileID: "B"},
|
||||
wantAContainsB: false,
|
||||
wantAStrictlyContainsB: false,
|
||||
},
|
||||
{
|
||||
name: "UserScope(1234)/UserScope(A/1234)",
|
||||
name: "UserScope-1234/UserScope-A-1234",
|
||||
scopeA: PolicyScope{kind: UserSetting, userID: "1234"},
|
||||
scopeB: PolicyScope{kind: UserSetting, userID: "1234", profileID: "A"},
|
||||
wantAContainsB: true,
|
||||
wantAStrictlyContainsB: true,
|
||||
},
|
||||
{
|
||||
name: "UserScope(1234)/UserScope(A/5678)",
|
||||
name: "UserScope-1234/UserScope-A-5678",
|
||||
scopeA: PolicyScope{kind: UserSetting, userID: "1234"},
|
||||
scopeB: PolicyScope{kind: UserSetting, userID: "5678", profileID: "A"},
|
||||
wantAContainsB: false,
|
||||
|
||||
@ -44,7 +44,7 @@ func TestGetString(t *testing.T) {
|
||||
wantMetrics []metrics.TestState
|
||||
}{
|
||||
{
|
||||
name: "read existing value",
|
||||
name: "read-existing-value",
|
||||
key: pkey.AdminConsoleVisibility,
|
||||
handlerValue: "hide",
|
||||
wantValue: "hide",
|
||||
@ -54,13 +54,13 @@ func TestGetString(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "read non-existing value",
|
||||
name: "read-non-existing-value",
|
||||
key: pkey.EnableServerMode,
|
||||
handlerError: ErrNotConfigured,
|
||||
wantError: nil,
|
||||
},
|
||||
{
|
||||
name: "read non-existing value, non-blank default",
|
||||
name: "read-non-existing-value-non-blank-default",
|
||||
key: pkey.EnableServerMode,
|
||||
handlerError: ErrNotConfigured,
|
||||
defaultValue: "test",
|
||||
@ -68,7 +68,7 @@ func TestGetString(t *testing.T) {
|
||||
wantError: nil,
|
||||
},
|
||||
{
|
||||
name: "reading value returns other error",
|
||||
name: "reading-value-returns-other-error",
|
||||
key: pkey.NetworkDevicesVisibility,
|
||||
handlerError: someOtherError,
|
||||
wantError: someOtherError,
|
||||
@ -124,27 +124,27 @@ func TestGetUint64(t *testing.T) {
|
||||
wantError error
|
||||
}{
|
||||
{
|
||||
name: "read existing value",
|
||||
name: "read-existing-value",
|
||||
key: pkey.LogSCMInteractions,
|
||||
handlerValue: 1,
|
||||
wantValue: 1,
|
||||
},
|
||||
{
|
||||
name: "read non-existing value",
|
||||
name: "read-non-existing-value",
|
||||
key: pkey.LogSCMInteractions,
|
||||
handlerValue: 0,
|
||||
handlerError: ErrNotConfigured,
|
||||
wantValue: 0,
|
||||
},
|
||||
{
|
||||
name: "read non-existing value, non-zero default",
|
||||
name: "read-non-existing-value-non-zero-default",
|
||||
key: pkey.LogSCMInteractions,
|
||||
defaultValue: 2,
|
||||
handlerError: ErrNotConfigured,
|
||||
wantValue: 2,
|
||||
},
|
||||
{
|
||||
name: "reading value returns other error",
|
||||
name: "reading-value-returns-other-error",
|
||||
key: pkey.FlushDNSOnSessionUnlock,
|
||||
handlerError: someOtherError,
|
||||
wantError: someOtherError,
|
||||
@ -191,7 +191,7 @@ func TestGetBoolean(t *testing.T) {
|
||||
wantMetrics []metrics.TestState
|
||||
}{
|
||||
{
|
||||
name: "read existing value",
|
||||
name: "read-existing-value",
|
||||
key: pkey.FlushDNSOnSessionUnlock,
|
||||
handlerValue: true,
|
||||
wantValue: true,
|
||||
@ -201,14 +201,14 @@ func TestGetBoolean(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "read non-existing value",
|
||||
name: "read-non-existing-value",
|
||||
key: pkey.LogSCMInteractions,
|
||||
handlerValue: false,
|
||||
handlerError: ErrNotConfigured,
|
||||
wantValue: false,
|
||||
},
|
||||
{
|
||||
name: "reading value returns other error",
|
||||
name: "reading-value-returns-other-error",
|
||||
key: pkey.FlushDNSOnSessionUnlock,
|
||||
handlerError: someOtherError,
|
||||
wantError: someOtherError, // expect error...
|
||||
@ -266,7 +266,7 @@ func TestGetPreferenceOption(t *testing.T) {
|
||||
wantMetrics []metrics.TestState
|
||||
}{
|
||||
{
|
||||
name: "always by policy",
|
||||
name: "always-by-policy",
|
||||
key: pkey.EnableIncomingConnections,
|
||||
handlerValue: "always",
|
||||
wantValue: ptype.AlwaysByPolicy,
|
||||
@ -276,7 +276,7 @@ func TestGetPreferenceOption(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "never by policy",
|
||||
name: "never-by-policy",
|
||||
key: pkey.EnableIncomingConnections,
|
||||
handlerValue: "never",
|
||||
wantValue: ptype.NeverByPolicy,
|
||||
@ -286,7 +286,7 @@ func TestGetPreferenceOption(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "use default",
|
||||
name: "use-default",
|
||||
key: pkey.EnableIncomingConnections,
|
||||
handlerValue: "",
|
||||
wantValue: ptype.ShowChoiceByPolicy,
|
||||
@ -296,13 +296,13 @@ func TestGetPreferenceOption(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "read non-existing value",
|
||||
name: "read-non-existing-value",
|
||||
key: pkey.EnableIncomingConnections,
|
||||
handlerError: ErrNotConfigured,
|
||||
wantValue: ptype.ShowChoiceByPolicy,
|
||||
},
|
||||
{
|
||||
name: "other error is returned",
|
||||
name: "other-error-is-returned",
|
||||
key: pkey.EnableIncomingConnections,
|
||||
handlerError: someOtherError,
|
||||
wantValue: ptype.ShowChoiceByPolicy,
|
||||
@ -359,7 +359,7 @@ func TestGetVisibility(t *testing.T) {
|
||||
wantMetrics []metrics.TestState
|
||||
}{
|
||||
{
|
||||
name: "hidden by policy",
|
||||
name: "hidden-by-policy",
|
||||
key: pkey.AdminConsoleVisibility,
|
||||
handlerValue: "hide",
|
||||
wantValue: ptype.HiddenByPolicy,
|
||||
@ -369,7 +369,7 @@ func TestGetVisibility(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "visibility default",
|
||||
name: "visibility-default",
|
||||
key: pkey.AdminConsoleVisibility,
|
||||
handlerValue: "show",
|
||||
wantValue: ptype.VisibleByPolicy,
|
||||
@ -379,14 +379,14 @@ func TestGetVisibility(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "read non-existing value",
|
||||
name: "read-non-existing-value",
|
||||
key: pkey.AdminConsoleVisibility,
|
||||
handlerValue: "show",
|
||||
handlerError: ErrNotConfigured,
|
||||
wantValue: ptype.VisibleByPolicy,
|
||||
},
|
||||
{
|
||||
name: "other error is returned",
|
||||
name: "other-error-is-returned",
|
||||
key: pkey.AdminConsoleVisibility,
|
||||
handlerValue: "show",
|
||||
handlerError: someOtherError,
|
||||
@ -445,7 +445,7 @@ func TestGetDuration(t *testing.T) {
|
||||
wantMetrics []metrics.TestState
|
||||
}{
|
||||
{
|
||||
name: "read existing value",
|
||||
name: "read-existing-value",
|
||||
key: pkey.KeyExpirationNoticeTime,
|
||||
handlerValue: "2h",
|
||||
wantValue: 2 * time.Hour,
|
||||
@ -456,7 +456,7 @@ func TestGetDuration(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid duration value",
|
||||
name: "invalid-duration-value",
|
||||
key: pkey.KeyExpirationNoticeTime,
|
||||
handlerValue: "-20",
|
||||
wantValue: 24 * time.Hour,
|
||||
@ -468,21 +468,21 @@ func TestGetDuration(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "read non-existing value",
|
||||
name: "read-non-existing-value",
|
||||
key: pkey.KeyExpirationNoticeTime,
|
||||
handlerError: ErrNotConfigured,
|
||||
wantValue: 24 * time.Hour,
|
||||
defaultValue: 24 * time.Hour,
|
||||
},
|
||||
{
|
||||
name: "read non-existing value different default",
|
||||
name: "read-non-existing-value-different-default",
|
||||
key: pkey.KeyExpirationNoticeTime,
|
||||
handlerError: ErrNotConfigured,
|
||||
wantValue: 0 * time.Second,
|
||||
defaultValue: 0 * time.Second,
|
||||
},
|
||||
{
|
||||
name: "other error is returned",
|
||||
name: "other-error-is-returned",
|
||||
key: pkey.KeyExpirationNoticeTime,
|
||||
handlerError: someOtherError,
|
||||
wantValue: 24 * time.Hour,
|
||||
@ -541,7 +541,7 @@ func TestGetStringArray(t *testing.T) {
|
||||
wantMetrics []metrics.TestState
|
||||
}{
|
||||
{
|
||||
name: "read existing value",
|
||||
name: "read-existing-value",
|
||||
key: pkey.AllowedSuggestedExitNodes,
|
||||
handlerValue: []string{"foo", "bar"},
|
||||
wantValue: []string{"foo", "bar"},
|
||||
@ -551,13 +551,13 @@ func TestGetStringArray(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "read non-existing value",
|
||||
name: "read-non-existing-value",
|
||||
key: pkey.AllowedSuggestedExitNodes,
|
||||
handlerError: ErrNotConfigured,
|
||||
wantError: nil,
|
||||
},
|
||||
{
|
||||
name: "read non-existing value, non nil default",
|
||||
name: "read-non-existing-value-non-nil-default",
|
||||
key: pkey.AllowedSuggestedExitNodes,
|
||||
handlerError: ErrNotConfigured,
|
||||
defaultValue: []string{"foo", "bar"},
|
||||
@ -565,7 +565,7 @@ func TestGetStringArray(t *testing.T) {
|
||||
wantError: nil,
|
||||
},
|
||||
{
|
||||
name: "reading value returns other error",
|
||||
name: "reading-value-returns-other-error",
|
||||
key: pkey.AllowedSuggestedExitNodes,
|
||||
handlerError: someOtherError,
|
||||
wantError: someOtherError,
|
||||
|
||||
@ -180,7 +180,7 @@ func Test_endpoint_maybeProbeUDPLifetimeLocked(t *testing.T) {
|
||||
wantMaybe bool
|
||||
}{
|
||||
{
|
||||
name: "nil probeUDPLifetime",
|
||||
name: "nil-probeUDPLifetime",
|
||||
localDisco: higher,
|
||||
remoteDisco: &lower,
|
||||
probeUDPLifetimeFn: func() *probeUDPLifetime {
|
||||
@ -189,28 +189,28 @@ func Test_endpoint_maybeProbeUDPLifetimeLocked(t *testing.T) {
|
||||
bestAddr: addr,
|
||||
},
|
||||
{
|
||||
name: "local higher disco key",
|
||||
name: "local-higher-disco-key",
|
||||
localDisco: higher,
|
||||
remoteDisco: &lower,
|
||||
probeUDPLifetimeFn: newProbeUDPLifetime,
|
||||
bestAddr: addr,
|
||||
},
|
||||
{
|
||||
name: "remote no disco key",
|
||||
name: "remote-no-disco-key",
|
||||
localDisco: higher,
|
||||
remoteDisco: nil,
|
||||
probeUDPLifetimeFn: newProbeUDPLifetime,
|
||||
bestAddr: addr,
|
||||
},
|
||||
{
|
||||
name: "invalid bestAddr",
|
||||
name: "invalid-bestAddr",
|
||||
localDisco: lower,
|
||||
remoteDisco: &higher,
|
||||
probeUDPLifetimeFn: newProbeUDPLifetime,
|
||||
bestAddr: addrQuality{},
|
||||
},
|
||||
{
|
||||
name: "cycle started too recently",
|
||||
name: "cycle-started-too-recently",
|
||||
localDisco: lower,
|
||||
remoteDisco: &higher,
|
||||
probeUDPLifetimeFn: func() *probeUDPLifetime {
|
||||
@ -222,7 +222,7 @@ func Test_endpoint_maybeProbeUDPLifetimeLocked(t *testing.T) {
|
||||
bestAddr: addr,
|
||||
},
|
||||
{
|
||||
name: "maybe cliff 0 cycle not active",
|
||||
name: "maybe-cliff-0-cycle-not-active",
|
||||
localDisco: lower,
|
||||
remoteDisco: &higher,
|
||||
probeUDPLifetimeFn: func() *probeUDPLifetime {
|
||||
@ -238,7 +238,7 @@ func Test_endpoint_maybeProbeUDPLifetimeLocked(t *testing.T) {
|
||||
wantMaybe: true,
|
||||
},
|
||||
{
|
||||
name: "maybe cliff 0",
|
||||
name: "maybe-cliff-0",
|
||||
localDisco: lower,
|
||||
remoteDisco: &higher,
|
||||
probeUDPLifetimeFn: func() *probeUDPLifetime {
|
||||
@ -254,7 +254,7 @@ func Test_endpoint_maybeProbeUDPLifetimeLocked(t *testing.T) {
|
||||
wantMaybe: true,
|
||||
},
|
||||
{
|
||||
name: "maybe cliff 1",
|
||||
name: "maybe-cliff-1",
|
||||
localDisco: lower,
|
||||
remoteDisco: &higher,
|
||||
probeUDPLifetimeFn: func() *probeUDPLifetime {
|
||||
@ -270,7 +270,7 @@ func Test_endpoint_maybeProbeUDPLifetimeLocked(t *testing.T) {
|
||||
wantMaybe: true,
|
||||
},
|
||||
{
|
||||
name: "maybe cliff 2",
|
||||
name: "maybe-cliff-2",
|
||||
localDisco: lower,
|
||||
remoteDisco: &higher,
|
||||
probeUDPLifetimeFn: func() *probeUDPLifetime {
|
||||
@ -341,13 +341,13 @@ func Test_epAddr_isDirectUDP(t *testing.T) {
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "false derp magic addr",
|
||||
name: "false-derp-magic-addr",
|
||||
ap: netip.AddrPortFrom(tailcfg.DerpMagicIPAddr, 0),
|
||||
vni: packet.VirtualNetworkID{},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "false vni set",
|
||||
name: "false-vni-set",
|
||||
ap: netip.MustParseAddrPort("192.0.2.1:7"),
|
||||
vni: vni,
|
||||
want: false,
|
||||
@ -397,42 +397,42 @@ func Test_endpoint_udpRelayEndpointReady(t *testing.T) {
|
||||
wantBestAddr addrQuality
|
||||
}{
|
||||
{
|
||||
name: "bestAddr trusted direct",
|
||||
name: "bestAddr-trusted-direct",
|
||||
curBestAddr: directAddrQuality,
|
||||
trustBestAddrUntil: mono.Now().Add(1 * time.Hour),
|
||||
maybeBest: peerRelayAddrQuality,
|
||||
wantBestAddr: directAddrQuality,
|
||||
},
|
||||
{
|
||||
name: "bestAddr untrusted direct",
|
||||
name: "bestAddr-untrusted-direct",
|
||||
curBestAddr: directAddrQuality,
|
||||
trustBestAddrUntil: mono.Now().Add(-1 * time.Hour),
|
||||
maybeBest: peerRelayAddrQuality,
|
||||
wantBestAddr: peerRelayAddrQuality,
|
||||
},
|
||||
{
|
||||
name: "maybeBest same relay server higher latency bestAddr trusted",
|
||||
name: "maybeBest-same-relay-higher-latency-trusted",
|
||||
curBestAddr: peerRelayAddrQuality,
|
||||
trustBestAddrUntil: mono.Now().Add(1 * time.Hour),
|
||||
maybeBest: peerRelayAddrQualityHigherLatencySameServer,
|
||||
wantBestAddr: peerRelayAddrQualityHigherLatencySameServer,
|
||||
},
|
||||
{
|
||||
name: "maybeBest diff relay server higher latency bestAddr trusted",
|
||||
name: "maybeBest-diff-relay-higher-latency-trusted",
|
||||
curBestAddr: peerRelayAddrQuality,
|
||||
trustBestAddrUntil: mono.Now().Add(1 * time.Hour),
|
||||
maybeBest: peerRelayAddrQualityHigherLatencyDiffServer,
|
||||
wantBestAddr: peerRelayAddrQuality,
|
||||
},
|
||||
{
|
||||
name: "maybeBest diff relay server lower latency bestAddr trusted",
|
||||
name: "maybeBest-diff-relay-lower-latency-trusted",
|
||||
curBestAddr: peerRelayAddrQuality,
|
||||
trustBestAddrUntil: mono.Now().Add(1 * time.Hour),
|
||||
maybeBest: peerRelayAddrQualityLowerLatencyDiffServer,
|
||||
wantBestAddr: peerRelayAddrQualityLowerLatencyDiffServer,
|
||||
},
|
||||
{
|
||||
name: "maybeBest diff relay server equal latency bestAddr trusted",
|
||||
name: "maybeBest-diff-relay-equal-latency-trusted",
|
||||
curBestAddr: peerRelayAddrQuality,
|
||||
trustBestAddrUntil: mono.Now().Add(1 * time.Hour),
|
||||
maybeBest: peerRelayAddrQualityEqualLatencyDiffServer,
|
||||
|
||||
@ -184,19 +184,19 @@ func TestBpfDiscardV4(t *testing.T) {
|
||||
accept bool
|
||||
}{
|
||||
{
|
||||
name: "base accepted datagram",
|
||||
name: "base-accepted-datagram",
|
||||
replace: map[int]byte{},
|
||||
accept: true,
|
||||
},
|
||||
{
|
||||
name: "more fragments",
|
||||
name: "more-fragments",
|
||||
replace: map[int]byte{
|
||||
6: 0x20,
|
||||
},
|
||||
accept: false,
|
||||
},
|
||||
{
|
||||
name: "some fragment",
|
||||
name: "some-fragment",
|
||||
replace: map[int]byte{
|
||||
7: 0x01,
|
||||
},
|
||||
|
||||
@ -1217,7 +1217,7 @@ func testTwoDevicePing(t *testing.T, d *devices) {
|
||||
}
|
||||
|
||||
outerT := t
|
||||
t.Run("ping 1.0.0.1", func(t *testing.T) {
|
||||
t.Run("ping-1_0_0_1", func(t *testing.T) {
|
||||
setT(t)
|
||||
defer setT(outerT)
|
||||
ping1(t)
|
||||
@ -1225,7 +1225,7 @@ func testTwoDevicePing(t *testing.T, d *devices) {
|
||||
checkStats(t, m2, m2Conns)
|
||||
})
|
||||
|
||||
t.Run("ping 1.0.0.2", func(t *testing.T) {
|
||||
t.Run("ping-1_0_0_2", func(t *testing.T) {
|
||||
setT(t)
|
||||
defer setT(outerT)
|
||||
ping2(t)
|
||||
@ -1233,7 +1233,7 @@ func testTwoDevicePing(t *testing.T, d *devices) {
|
||||
checkStats(t, m2, m2Conns)
|
||||
})
|
||||
|
||||
t.Run("ping 1.0.0.2 via SendPacket", func(t *testing.T) {
|
||||
t.Run("ping-1_0_0_2-via-SendPacket", func(t *testing.T) {
|
||||
setT(t)
|
||||
defer setT(outerT)
|
||||
msg1to2 := tuntest.Ping(netip.MustParseAddr("1.0.0.2"), netip.MustParseAddr("1.0.0.1"))
|
||||
@ -1251,7 +1251,7 @@ func testTwoDevicePing(t *testing.T, d *devices) {
|
||||
checkStats(t, m2, m2Conns)
|
||||
})
|
||||
|
||||
t.Run("no-op dev1 reconfig", func(t *testing.T) {
|
||||
t.Run("no-op-dev1-reconfig", func(t *testing.T) {
|
||||
setT(t)
|
||||
defer setT(outerT)
|
||||
if err := m1.Reconfig(m1cfg); err != nil {
|
||||
@ -2731,7 +2731,7 @@ func TestAddrForSendLockedForWireGuardOnly(t *testing.T) {
|
||||
want epAddr
|
||||
}{
|
||||
{
|
||||
name: "no endpoints",
|
||||
name: "no-endpoints",
|
||||
sendInitialPing: false,
|
||||
validAddr: false,
|
||||
sendFollowUpPing: false,
|
||||
@ -2740,7 +2740,7 @@ func TestAddrForSendLockedForWireGuardOnly(t *testing.T) {
|
||||
want: epAddr{},
|
||||
},
|
||||
{
|
||||
name: "singular endpoint does not request ping",
|
||||
name: "singular-endpoint-no-ping-request",
|
||||
sendInitialPing: false,
|
||||
validAddr: true,
|
||||
sendFollowUpPing: false,
|
||||
@ -2754,7 +2754,7 @@ func TestAddrForSendLockedForWireGuardOnly(t *testing.T) {
|
||||
want: epAddr{ap: netip.MustParseAddrPort("1.1.1.1:111")},
|
||||
},
|
||||
{
|
||||
name: "ping sent within wireguardPingInterval should not request ping",
|
||||
name: "ping-within-wireguardPingInterval-no-request",
|
||||
sendInitialPing: true,
|
||||
validAddr: true,
|
||||
sendFollowUpPing: false,
|
||||
@ -2772,7 +2772,7 @@ func TestAddrForSendLockedForWireGuardOnly(t *testing.T) {
|
||||
want: epAddr{ap: netip.MustParseAddrPort("1.1.1.1:111")},
|
||||
},
|
||||
{
|
||||
name: "ping sent outside of wireguardPingInterval should request ping",
|
||||
name: "ping-outside-wireguardPingInterval-requests-ping",
|
||||
sendInitialPing: true,
|
||||
validAddr: true,
|
||||
sendFollowUpPing: true,
|
||||
@ -2790,7 +2790,7 @@ func TestAddrForSendLockedForWireGuardOnly(t *testing.T) {
|
||||
want: epAddr{ap: netip.MustParseAddrPort("1.1.1.1:111")},
|
||||
},
|
||||
{
|
||||
name: "choose lowest latency for useable IPv4 and IPv6",
|
||||
name: "choose-lowest-latency-v4-and-v6",
|
||||
sendInitialPing: true,
|
||||
validAddr: true,
|
||||
sendFollowUpPing: false,
|
||||
@ -2808,7 +2808,7 @@ func TestAddrForSendLockedForWireGuardOnly(t *testing.T) {
|
||||
want: epAddr{ap: netip.MustParseAddrPort("[2345:0425:2CA1:0000:0000:0567:5673:23b5]:222")},
|
||||
},
|
||||
{
|
||||
name: "choose IPv6 address when latency is the same for v4 and v6",
|
||||
name: "choose-IPv6-when-equal-latency",
|
||||
sendInitialPing: true,
|
||||
validAddr: true,
|
||||
sendFollowUpPing: false,
|
||||
@ -3378,73 +3378,73 @@ func Test_packetLooksLike(t *testing.T) {
|
||||
wantIsGeneveEncap bool
|
||||
}{
|
||||
{
|
||||
name: "STUN binding success response",
|
||||
name: "STUN-binding-success-response",
|
||||
msg: stun.Response(stun.NewTxID(), netip.MustParseAddrPort("127.0.0.1:1")),
|
||||
wantPacketLooksLikeType: packetLooksLikeSTUNBinding,
|
||||
wantIsGeneveEncap: false,
|
||||
},
|
||||
{
|
||||
name: "naked disco",
|
||||
name: "naked-disco",
|
||||
msg: nakedDisco,
|
||||
wantPacketLooksLikeType: packetLooksLikeDisco,
|
||||
wantIsGeneveEncap: false,
|
||||
},
|
||||
{
|
||||
name: "geneve encap disco",
|
||||
name: "geneve-encap-disco",
|
||||
msg: geneveEncapDisco,
|
||||
wantPacketLooksLikeType: packetLooksLikeDisco,
|
||||
wantIsGeneveEncap: true,
|
||||
},
|
||||
{
|
||||
name: "geneve encap too short disco",
|
||||
name: "geneve-encap-too-short-disco",
|
||||
msg: geneveEncapDisco[:len(geneveEncapDisco)-key.DiscoPublicRawLen],
|
||||
wantPacketLooksLikeType: packetLooksLikeWireGuard,
|
||||
wantIsGeneveEncap: false,
|
||||
},
|
||||
{
|
||||
name: "geneve encap disco nonzero geneve version",
|
||||
name: "geneve-encap-disco-nonzero-geneve-version",
|
||||
msg: geneveEncapDiscoNonZeroGeneveVersion,
|
||||
wantPacketLooksLikeType: packetLooksLikeWireGuard,
|
||||
wantIsGeneveEncap: false,
|
||||
},
|
||||
{
|
||||
name: "geneve encap disco nonzero geneve reserved bits",
|
||||
name: "geneve-encap-disco-nonzero-geneve-reserved-bits",
|
||||
msg: geneveEncapDiscoNonZeroGeneveReservedBits,
|
||||
wantPacketLooksLikeType: packetLooksLikeWireGuard,
|
||||
wantIsGeneveEncap: false,
|
||||
},
|
||||
{
|
||||
name: "geneve encap disco nonzero geneve vni lsb",
|
||||
name: "geneve-encap-disco-nonzero-geneve-vni-lsb",
|
||||
msg: geneveEncapDiscoNonZeroGeneveVNILSB,
|
||||
wantPacketLooksLikeType: packetLooksLikeWireGuard,
|
||||
wantIsGeneveEncap: false,
|
||||
},
|
||||
{
|
||||
name: "geneve encap wireguard",
|
||||
name: "geneve-encap-wireguard",
|
||||
msg: geneveEncapWireGuard,
|
||||
wantPacketLooksLikeType: packetLooksLikeWireGuard,
|
||||
wantIsGeneveEncap: true,
|
||||
},
|
||||
{
|
||||
name: "naked WireGuard Initiation type",
|
||||
name: "naked-WireGuard-Initiation-type",
|
||||
msg: nakedWireGuardInitiation,
|
||||
wantPacketLooksLikeType: packetLooksLikeWireGuard,
|
||||
wantIsGeneveEncap: false,
|
||||
},
|
||||
{
|
||||
name: "naked WireGuard Response type",
|
||||
name: "naked-WireGuard-Response-type",
|
||||
msg: nakedWireGuardResponse,
|
||||
wantPacketLooksLikeType: packetLooksLikeWireGuard,
|
||||
wantIsGeneveEncap: false,
|
||||
},
|
||||
{
|
||||
name: "naked WireGuard Cookie Reply type",
|
||||
name: "naked-WireGuard-Cookie-Reply-type",
|
||||
msg: nakedWireGuardCookieReply,
|
||||
wantPacketLooksLikeType: packetLooksLikeWireGuard,
|
||||
wantIsGeneveEncap: false,
|
||||
},
|
||||
{
|
||||
name: "naked WireGuard Transport type",
|
||||
name: "naked-WireGuard-Transport-type",
|
||||
msg: nakedWireGuardTransport,
|
||||
wantPacketLooksLikeType: packetLooksLikeWireGuard,
|
||||
wantIsGeneveEncap: false,
|
||||
@ -3481,22 +3481,22 @@ func Test_looksLikeInitiationMsg(t *testing.T) {
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "valid initiation",
|
||||
name: "valid-initiation",
|
||||
b: initMsg,
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "invalid message type field",
|
||||
name: "invalid-message-type-field",
|
||||
b: initMsgSizeTransportType,
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "too small",
|
||||
name: "too-small",
|
||||
b: initMsg[:device.MessageInitiationSize-1],
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "too big",
|
||||
name: "too-big",
|
||||
b: append(initMsg, 0),
|
||||
want: false,
|
||||
},
|
||||
@ -3538,7 +3538,7 @@ func Test_nodeHasCap(t *testing.T) {
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "match v4",
|
||||
name: "match-v4",
|
||||
filt: filter.New([]filtertype.Match{
|
||||
{
|
||||
Srcs: []netip.Prefix{netip.MustParsePrefix("2.2.2.2/32")},
|
||||
@ -3556,7 +3556,7 @@ func Test_nodeHasCap(t *testing.T) {
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "match v6",
|
||||
name: "match-v6",
|
||||
filt: filter.New([]filtertype.Match{
|
||||
{
|
||||
Srcs: []netip.Prefix{netip.MustParsePrefix("::2/128")},
|
||||
@ -3574,7 +3574,7 @@ func Test_nodeHasCap(t *testing.T) {
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "no match CapMatch Dst",
|
||||
name: "no-match-CapMatch-Dst",
|
||||
filt: filter.New([]filtertype.Match{
|
||||
{
|
||||
Srcs: []netip.Prefix{netip.MustParsePrefix("::2/128")},
|
||||
@ -3592,7 +3592,7 @@ func Test_nodeHasCap(t *testing.T) {
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "no match peer cap",
|
||||
name: "no-match-peer-cap",
|
||||
filt: filter.New([]filtertype.Match{
|
||||
{
|
||||
Srcs: []netip.Prefix{netip.MustParsePrefix("::2/128")},
|
||||
@ -3610,7 +3610,7 @@ func Test_nodeHasCap(t *testing.T) {
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "nil src",
|
||||
name: "nil-src",
|
||||
filt: filter.New([]filtertype.Match{
|
||||
{
|
||||
Srcs: []netip.Prefix{netip.MustParsePrefix("2.2.2.2/32")},
|
||||
@ -3628,7 +3628,7 @@ func Test_nodeHasCap(t *testing.T) {
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "nil dst",
|
||||
name: "nil-dst",
|
||||
filt: filter.New([]filtertype.Match{
|
||||
{
|
||||
Srcs: []netip.Prefix{netip.MustParsePrefix("2.2.2.2/32")},
|
||||
@ -3706,7 +3706,7 @@ func TestConn_SetNetworkMap_updateRelayServersSet(t *testing.T) {
|
||||
wantRelayClientEnabled bool
|
||||
}{
|
||||
{
|
||||
name: "candidate relay server",
|
||||
name: "candidate-relay-server",
|
||||
filt: filter.New([]filtertype.Match{
|
||||
{
|
||||
Srcs: peerNodeCandidateRelay.Addresses,
|
||||
@ -3730,7 +3730,7 @@ func TestConn_SetNetworkMap_updateRelayServersSet(t *testing.T) {
|
||||
wantRelayClientEnabled: true,
|
||||
},
|
||||
{
|
||||
name: "no candidate relay server because self has tailcfg.NodeAttrDisableRelayClient",
|
||||
name: "no-candidate-self-has-DisableRelayClient", // self has tailcfg.NodeAttrDisableRelayClient
|
||||
filt: filter.New([]filtertype.Match{
|
||||
{
|
||||
Srcs: peerNodeCandidateRelay.Addresses,
|
||||
@ -3748,7 +3748,7 @@ func TestConn_SetNetworkMap_updateRelayServersSet(t *testing.T) {
|
||||
wantRelayClientEnabled: false,
|
||||
},
|
||||
{
|
||||
name: "no candidate relay server because self has tailcfg.NodeAttrOnlyTCP443",
|
||||
name: "no-candidate-self-has-OnlyTCP443", // self has tailcfg.NodeAttrOnlyTCP443
|
||||
filt: filter.New([]filtertype.Match{
|
||||
{
|
||||
Srcs: peerNodeCandidateRelay.Addresses,
|
||||
@ -3766,7 +3766,7 @@ func TestConn_SetNetworkMap_updateRelayServersSet(t *testing.T) {
|
||||
wantRelayClientEnabled: false,
|
||||
},
|
||||
{
|
||||
name: "self candidate relay server",
|
||||
name: "self-candidate-relay-server",
|
||||
filt: filter.New([]filtertype.Match{
|
||||
{
|
||||
Srcs: selfNode.Addresses,
|
||||
@ -3790,7 +3790,7 @@ func TestConn_SetNetworkMap_updateRelayServersSet(t *testing.T) {
|
||||
wantRelayClientEnabled: true,
|
||||
},
|
||||
{
|
||||
name: "no candidate relay server",
|
||||
name: "no-candidate-relay-server",
|
||||
filt: filter.New([]filtertype.Match{
|
||||
{
|
||||
Srcs: peerNodeNotCandidateRelayCapVer.Addresses,
|
||||
@ -3911,7 +3911,7 @@ func TestConn_receiveIP(t *testing.T) {
|
||||
wantNoteRecvActivityCalled bool
|
||||
}{
|
||||
{
|
||||
name: "naked disco",
|
||||
name: "naked-disco",
|
||||
b: looksLikeNakedDisco,
|
||||
ipp: netip.MustParseAddrPort("127.0.0.1:7777"),
|
||||
cache: &epAddrEndpointCache{},
|
||||
@ -3923,7 +3923,7 @@ func TestConn_receiveIP(t *testing.T) {
|
||||
wantNoteRecvActivityCalled: false,
|
||||
},
|
||||
{
|
||||
name: "geneve encap disco",
|
||||
name: "geneve-encap-disco",
|
||||
b: looksLikeGeneveDisco,
|
||||
ipp: netip.MustParseAddrPort("127.0.0.1:7777"),
|
||||
cache: &epAddrEndpointCache{},
|
||||
@ -3935,7 +3935,7 @@ func TestConn_receiveIP(t *testing.T) {
|
||||
wantNoteRecvActivityCalled: false,
|
||||
},
|
||||
{
|
||||
name: "STUN binding",
|
||||
name: "STUN-binding",
|
||||
b: looksLikeSTUNBinding,
|
||||
ipp: netip.MustParseAddrPort("127.0.0.1:7777"),
|
||||
cache: &epAddrEndpointCache{},
|
||||
@ -3947,7 +3947,7 @@ func TestConn_receiveIP(t *testing.T) {
|
||||
wantNoteRecvActivityCalled: false,
|
||||
},
|
||||
{
|
||||
name: "naked WireGuard init lazyEndpoint empty peerMap",
|
||||
name: "naked-WireGuard-init-lazyEndpoint-empty-peerMap",
|
||||
b: looksLikeNakedWireGuardInit,
|
||||
ipp: netip.MustParseAddrPort("127.0.0.1:7777"),
|
||||
cache: &epAddrEndpointCache{},
|
||||
@ -3959,7 +3959,7 @@ func TestConn_receiveIP(t *testing.T) {
|
||||
wantNoteRecvActivityCalled: false,
|
||||
},
|
||||
{
|
||||
name: "naked WireGuard init endpoint matching peerMap entry",
|
||||
name: "naked-WireGuard-init-endpoint-matching-peerMap-entry",
|
||||
b: looksLikeNakedWireGuardInit,
|
||||
ipp: netip.MustParseAddrPort("127.0.0.1:7777"),
|
||||
cache: &epAddrEndpointCache{},
|
||||
@ -3973,7 +3973,7 @@ func TestConn_receiveIP(t *testing.T) {
|
||||
wantNoteRecvActivityCalled: true,
|
||||
},
|
||||
{
|
||||
name: "geneve WireGuard init lazyEndpoint empty peerMap",
|
||||
name: "geneve-WireGuard-init-lazyEndpoint-empty-peerMap",
|
||||
b: looksLikeGeneveWireGuardInit,
|
||||
ipp: netip.MustParseAddrPort("127.0.0.1:7777"),
|
||||
cache: &epAddrEndpointCache{},
|
||||
@ -3985,7 +3985,7 @@ func TestConn_receiveIP(t *testing.T) {
|
||||
wantNoteRecvActivityCalled: false,
|
||||
},
|
||||
{
|
||||
name: "geneve WireGuard init lazyEndpoint matching peerMap activity noted",
|
||||
name: "geneve-WireGuard-init-lazyEndpoint-matching-peerMap-activity-noted",
|
||||
b: looksLikeGeneveWireGuardInit,
|
||||
ipp: netip.MustParseAddrPort("127.0.0.1:7777"),
|
||||
cache: &epAddrEndpointCache{},
|
||||
@ -4001,7 +4001,7 @@ func TestConn_receiveIP(t *testing.T) {
|
||||
wantNoteRecvActivityCalled: true,
|
||||
},
|
||||
{
|
||||
name: "geneve WireGuard init lazyEndpoint matching peerMap no activity noted",
|
||||
name: "geneve-WireGuard-init-lazyEndpoint-matching-peerMap-no-activity-noted",
|
||||
b: looksLikeGeneveWireGuardInit,
|
||||
ipp: netip.MustParseAddrPort("127.0.0.1:7777"),
|
||||
cache: &epAddrEndpointCache{},
|
||||
@ -4151,25 +4151,25 @@ func Test_lazyEndpoint_InitiationMessagePublicKey(t *testing.T) {
|
||||
wantNoteRecvActivityCalled bool
|
||||
}{
|
||||
{
|
||||
name: "noteRecvActivity called",
|
||||
name: "noteRecvActivity-called",
|
||||
callWithPeerMapKey: true,
|
||||
maybeEPMatchingKey: false,
|
||||
wantNoteRecvActivityCalled: true,
|
||||
},
|
||||
{
|
||||
name: "maybeEP early return",
|
||||
name: "maybeEP-early-return",
|
||||
callWithPeerMapKey: true,
|
||||
maybeEPMatchingKey: true,
|
||||
wantNoteRecvActivityCalled: false,
|
||||
},
|
||||
{
|
||||
name: "not in peerMap early return",
|
||||
name: "not-in-peerMap-early-return",
|
||||
callWithPeerMapKey: false,
|
||||
maybeEPMatchingKey: false,
|
||||
wantNoteRecvActivityCalled: false,
|
||||
},
|
||||
{
|
||||
name: "not in peerMap maybeEP early return",
|
||||
name: "not-in-peerMap-maybeEP-early-return",
|
||||
callWithPeerMapKey: false,
|
||||
maybeEPMatchingKey: true,
|
||||
wantNoteRecvActivityCalled: false,
|
||||
@ -4232,25 +4232,25 @@ func Test_lazyEndpoint_FromPeer(t *testing.T) {
|
||||
wantEpAddrInPeerMap bool
|
||||
}{
|
||||
{
|
||||
name: "epAddr in peerMap",
|
||||
name: "epAddr-in-peerMap",
|
||||
callWithPeerMapKey: true,
|
||||
maybeEPMatchingKey: false,
|
||||
wantEpAddrInPeerMap: true,
|
||||
},
|
||||
{
|
||||
name: "maybeEP early return",
|
||||
name: "maybeEP-early-return",
|
||||
callWithPeerMapKey: true,
|
||||
maybeEPMatchingKey: true,
|
||||
wantEpAddrInPeerMap: false,
|
||||
},
|
||||
{
|
||||
name: "not in peerMap early return",
|
||||
name: "not-in-peerMap-early-return",
|
||||
callWithPeerMapKey: false,
|
||||
maybeEPMatchingKey: false,
|
||||
wantEpAddrInPeerMap: false,
|
||||
},
|
||||
{
|
||||
name: "not in peerMap maybeEP early return",
|
||||
name: "not-in-peerMap-maybeEP-early-return",
|
||||
callWithPeerMapKey: false,
|
||||
maybeEPMatchingKey: true,
|
||||
wantEpAddrInPeerMap: false,
|
||||
|
||||
@ -141,7 +141,7 @@ func TestRelayManager_handleNewServerEndpointRunLoop(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
// Test for http://go/corp/32978
|
||||
name: "eq server+ep neq VNI higher lamport",
|
||||
name: "eq-server-ep-neq-VNI-higher-lamport",
|
||||
events: []newRelayServerEndpointEvent{
|
||||
serverAendpointALamport1VNI1,
|
||||
serverAendpointALamport2VNI2,
|
||||
@ -151,7 +151,7 @@ func TestRelayManager_handleNewServerEndpointRunLoop(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "eq server+ep neq VNI lower lamport",
|
||||
name: "eq-server-ep-neq-VNI-lower-lamport",
|
||||
events: []newRelayServerEndpointEvent{
|
||||
serverAendpointALamport2VNI2,
|
||||
serverAendpointALamport1VNI1,
|
||||
@ -161,7 +161,7 @@ func TestRelayManager_handleNewServerEndpointRunLoop(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "eq server+vni neq ep lower lamport",
|
||||
name: "eq-server-vni-neq-ep-lower-lamport",
|
||||
events: []newRelayServerEndpointEvent{
|
||||
serverAendpointALamport2VNI2,
|
||||
serverAendpointBLamport1VNI2,
|
||||
@ -171,7 +171,7 @@ func TestRelayManager_handleNewServerEndpointRunLoop(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "eq server+vni neq ep higher lamport",
|
||||
name: "eq-server-vni-neq-ep-higher-lamport",
|
||||
events: []newRelayServerEndpointEvent{
|
||||
serverAendpointBLamport1VNI2,
|
||||
serverAendpointALamport2VNI2,
|
||||
@ -181,7 +181,7 @@ func TestRelayManager_handleNewServerEndpointRunLoop(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "eq server+endpoint+vni higher lamport",
|
||||
name: "eq-server-endpoint-vni-higher-lamport",
|
||||
events: []newRelayServerEndpointEvent{
|
||||
serverAendpointALamport1VNI1,
|
||||
serverAendpointALamport2VNI1,
|
||||
@ -191,7 +191,7 @@ func TestRelayManager_handleNewServerEndpointRunLoop(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "eq server+endpoint+vni lower lamport",
|
||||
name: "eq-server-endpoint-vni-lower-lamport",
|
||||
events: []newRelayServerEndpointEvent{
|
||||
serverAendpointALamport2VNI1,
|
||||
serverAendpointALamport1VNI1,
|
||||
@ -201,7 +201,7 @@ func TestRelayManager_handleNewServerEndpointRunLoop(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "eq endpoint+vni+lamport neq server",
|
||||
name: "eq-endpoint-vni-lamport-neq-server",
|
||||
events: []newRelayServerEndpointEvent{
|
||||
serverAendpointALamport1VNI1,
|
||||
serverBendpointALamport1VNI1,
|
||||
@ -212,7 +212,7 @@ func TestRelayManager_handleNewServerEndpointRunLoop(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "trusted last best with matching server",
|
||||
name: "trusted-last-best-with-matching-server",
|
||||
events: []newRelayServerEndpointEvent{
|
||||
serverAendpointALamport1VNI1LastBestMatching,
|
||||
},
|
||||
|
||||
@ -54,13 +54,13 @@ ip rule add -6 pref 5270 table 52
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "no config",
|
||||
name: "no-config",
|
||||
in: nil,
|
||||
want: `
|
||||
up` + basic,
|
||||
},
|
||||
{
|
||||
name: "local addr only",
|
||||
name: "local-addr-only",
|
||||
in: &Config{
|
||||
LocalAddrs: mustCIDRs("100.101.102.103/10"),
|
||||
NetfilterMode: netfilterOff,
|
||||
@ -71,7 +71,7 @@ ip addr add 100.101.102.103/10 dev tailscale0` + basic,
|
||||
},
|
||||
|
||||
{
|
||||
name: "addr and routes",
|
||||
name: "addr-and-routes",
|
||||
in: &Config{
|
||||
LocalAddrs: mustCIDRs("100.101.102.103/10"),
|
||||
Routes: mustCIDRs("100.100.100.100/32", "192.168.16.0/24"),
|
||||
@ -85,7 +85,7 @@ ip route add 192.168.16.0/24 dev tailscale0 table 52` + basic,
|
||||
},
|
||||
|
||||
{
|
||||
name: "addr and routes and subnet routes",
|
||||
name: "addr-routes-and-subnet-routes",
|
||||
in: &Config{
|
||||
LocalAddrs: mustCIDRs("100.101.102.103/10"),
|
||||
Routes: mustCIDRs("100.100.100.100/32", "192.168.16.0/24"),
|
||||
@ -100,7 +100,7 @@ ip route add 192.168.16.0/24 dev tailscale0 table 52` + basic,
|
||||
},
|
||||
|
||||
{
|
||||
name: "addr and routes and subnet routes with netfilter",
|
||||
name: "addr-routes-subnet-routes-with-netfilter",
|
||||
in: &Config{
|
||||
LocalAddrs: mustCIDRs("100.101.102.104/10"),
|
||||
Routes: mustCIDRs("100.100.100.100/32", "10.0.0.0/8"),
|
||||
@ -141,7 +141,7 @@ v6/nat/ts-postrouting -m mark --mark 0x40000/0xff0000 -j MASQUERADE
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "addr and routes and subnet routes with netfilter but no stateful filtering",
|
||||
name: "addr-routes-subnet-routes-netfilter-no-stateful",
|
||||
in: &Config{
|
||||
LocalAddrs: mustCIDRs("100.101.102.104/10"),
|
||||
Routes: mustCIDRs("100.100.100.100/32", "10.0.0.0/8"),
|
||||
@ -180,7 +180,7 @@ v6/nat/ts-postrouting -m mark --mark 0x40000/0xff0000 -j MASQUERADE
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "addr and routes with netfilter",
|
||||
name: "addr-and-routes-with-netfilter",
|
||||
in: &Config{
|
||||
LocalAddrs: mustCIDRs("100.101.102.104/10"),
|
||||
Routes: mustCIDRs("100.100.100.100/32", "10.0.0.0/8"),
|
||||
@ -215,7 +215,7 @@ v6/nat/POSTROUTING -j ts-postrouting
|
||||
},
|
||||
|
||||
{
|
||||
name: "addr and routes and subnet routes with netfilter but no SNAT",
|
||||
name: "addr-routes-subnet-routes-netfilter-no-SNAT",
|
||||
in: &Config{
|
||||
LocalAddrs: mustCIDRs("100.101.102.104/10"),
|
||||
Routes: mustCIDRs("100.100.100.100/32", "10.0.0.0/8"),
|
||||
@ -251,7 +251,7 @@ v6/nat/POSTROUTING -j ts-postrouting
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "addr and routes with netfilter",
|
||||
name: "addr-and-routes-with-netfilter-2",
|
||||
in: &Config{
|
||||
LocalAddrs: mustCIDRs("100.101.102.104/10"),
|
||||
Routes: mustCIDRs("100.100.100.100/32", "10.0.0.0/8"),
|
||||
@ -286,7 +286,7 @@ v6/nat/POSTROUTING -j ts-postrouting
|
||||
},
|
||||
|
||||
{
|
||||
name: "addr and routes with half netfilter",
|
||||
name: "addr-and-routes-with-half-netfilter",
|
||||
in: &Config{
|
||||
LocalAddrs: mustCIDRs("100.101.102.104/10"),
|
||||
Routes: mustCIDRs("100.100.100.100/32", "10.0.0.0/8"),
|
||||
@ -310,7 +310,7 @@ v6/filter/ts-forward -o tailscale0 -j ACCEPT
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "addr and routes with netfilter2",
|
||||
name: "addr-and-routes-with-netfilter2",
|
||||
in: &Config{
|
||||
LocalAddrs: mustCIDRs("100.101.102.104/10"),
|
||||
Routes: mustCIDRs("100.100.100.100/32", "10.0.0.0/8"),
|
||||
@ -344,7 +344,7 @@ v6/nat/POSTROUTING -j ts-postrouting
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "addr, routes, and local routes with netfilter",
|
||||
name: "addr-routes-local-routes-with-netfilter",
|
||||
in: &Config{
|
||||
LocalAddrs: mustCIDRs("100.101.102.104/10"),
|
||||
Routes: mustCIDRs("100.100.100.100/32", "0.0.0.0/0"),
|
||||
@ -380,7 +380,7 @@ v6/nat/POSTROUTING -j ts-postrouting
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "addr, routes, and local routes with no netfilter",
|
||||
name: "addr-routes-local-routes-no-netfilter",
|
||||
in: &Config{
|
||||
LocalAddrs: mustCIDRs("100.101.102.104/10"),
|
||||
Routes: mustCIDRs("100.100.100.100/32", "0.0.0.0/0"),
|
||||
@ -396,7 +396,7 @@ ip route add throw 10.0.0.0/8 table 52
|
||||
ip route add throw 192.168.0.0/24 table 52` + basic,
|
||||
},
|
||||
{
|
||||
name: "subnet routes with connmark for rp_filter",
|
||||
name: "subnet-routes-connmark-for-rp_filter",
|
||||
in: &Config{
|
||||
LocalAddrs: mustCIDRs("100.101.102.104/10"),
|
||||
Routes: mustCIDRs("100.100.100.100/32"),
|
||||
@ -433,7 +433,7 @@ v6/nat/ts-postrouting -m mark --mark 0x40000/0xff0000 -j MASQUERADE
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "subnet routes (connmark always enabled)",
|
||||
name: "subnet-routes-connmark-always-enabled",
|
||||
in: &Config{
|
||||
LocalAddrs: mustCIDRs("100.101.102.104/10"),
|
||||
Routes: mustCIDRs("100.100.100.100/32"),
|
||||
@ -470,7 +470,7 @@ v6/nat/ts-postrouting -m mark --mark 0x40000/0xff0000 -j MASQUERADE
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "connmark with stateful filtering",
|
||||
name: "connmark-with-stateful-filtering",
|
||||
in: &Config{
|
||||
LocalAddrs: mustCIDRs("100.101.102.104/10"),
|
||||
Routes: mustCIDRs("100.100.100.100/32"),
|
||||
|
||||
@ -26,7 +26,7 @@ func TestWatchdog(t *testing.T) {
|
||||
maxWaitMultiple = 15
|
||||
}
|
||||
|
||||
t.Run("default watchdog does not fire", func(t *testing.T) {
|
||||
t.Run("default-watchdog-does-not-fire", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
bus := eventbustest.NewBus(t)
|
||||
ht := health.NewTracker(bus)
|
||||
@ -55,7 +55,7 @@ func TestWatchdogMetrics(t *testing.T) {
|
||||
wantCounts map[watchdogEvent]int64
|
||||
}{
|
||||
{
|
||||
name: "single event types",
|
||||
name: "single-event-types",
|
||||
events: []watchdogEvent{RequestStatus, PeerForIPEvent, Ping},
|
||||
wantCounts: map[watchdogEvent]int64{
|
||||
RequestStatus: 1,
|
||||
@ -64,7 +64,7 @@ func TestWatchdogMetrics(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "repeated events",
|
||||
name: "repeated-events",
|
||||
events: []watchdogEvent{RequestStatus, RequestStatus, Ping, RequestStatus},
|
||||
wantCounts: map[watchdogEvent]int64{
|
||||
RequestStatus: 3,
|
||||
|
||||
@ -90,14 +90,14 @@ func TestDeviceConfig(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("device1 config", func(t *testing.T) {
|
||||
t.Run("device1-config", func(t *testing.T) {
|
||||
if err := ReconfigDevice(device1, cfg1, t.Logf); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cmp(t, device1, cfg1)
|
||||
})
|
||||
|
||||
t.Run("device2 config", func(t *testing.T) {
|
||||
t.Run("device2-config", func(t *testing.T) {
|
||||
if err := ReconfigDevice(device2, cfg2, t.Logf); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -105,7 +105,7 @@ func TestDeviceConfig(t *testing.T) {
|
||||
})
|
||||
|
||||
// This is only to test that Config and Reconfig are properly synchronized.
|
||||
t.Run("device2 config/reconfig", func(t *testing.T) {
|
||||
t.Run("device2-config-reconfig", func(t *testing.T) {
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(2)
|
||||
|
||||
@ -122,7 +122,7 @@ func TestDeviceConfig(t *testing.T) {
|
||||
wg.Wait()
|
||||
})
|
||||
|
||||
t.Run("device1 modify peer", func(t *testing.T) {
|
||||
t.Run("device1-modify-peer", func(t *testing.T) {
|
||||
cfg1.Peers[0].DiscoKey = key.DiscoPublicFromRaw32(mem.B([]byte{0: 1, 31: 0}))
|
||||
if err := ReconfigDevice(device1, cfg1, t.Logf); err != nil {
|
||||
t.Fatal(err)
|
||||
@ -130,7 +130,7 @@ func TestDeviceConfig(t *testing.T) {
|
||||
cmp(t, device1, cfg1)
|
||||
})
|
||||
|
||||
t.Run("device1 replace endpoint", func(t *testing.T) {
|
||||
t.Run("device1-replace-endpoint", func(t *testing.T) {
|
||||
cfg1.Peers[0].DiscoKey = key.DiscoPublicFromRaw32(mem.B([]byte{0: 2, 31: 0}))
|
||||
if err := ReconfigDevice(device1, cfg1, t.Logf); err != nil {
|
||||
t.Fatal(err)
|
||||
@ -138,7 +138,7 @@ func TestDeviceConfig(t *testing.T) {
|
||||
cmp(t, device1, cfg1)
|
||||
})
|
||||
|
||||
t.Run("device1 add new peer", func(t *testing.T) {
|
||||
t.Run("device1-add-new-peer", func(t *testing.T) {
|
||||
cfg1.Peers = append(cfg1.Peers, Peer{
|
||||
PublicKey: k3,
|
||||
AllowedIPs: []netip.Prefix{ip3},
|
||||
@ -178,7 +178,7 @@ func TestDeviceConfig(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("device1 remove peer", func(t *testing.T) {
|
||||
t.Run("device1-remove-peer", func(t *testing.T) {
|
||||
removeKey := cfg1.Peers[len(cfg1.Peers)-1].PublicKey
|
||||
cfg1.Peers = cfg1.Peers[:len(cfg1.Peers)-1]
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user