Compare commits
4 Commits
bradfitz/c
...
s/tsnetd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1693329169 | ||
|
|
8e840489ed | ||
|
|
2cf6e12790 | ||
|
|
c11af12a49 |
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@@ -90,11 +90,11 @@ jobs:
|
||||
- name: build test wrapper
|
||||
run: ./tool/go build -o /tmp/testwrapper ./cmd/testwrapper
|
||||
- name: test all
|
||||
run: ./tool/go test ${{matrix.buildflags}} -exec=/tmp/testwrapper
|
||||
run: PATH=$PWD/tool:$PATH /tmp/testwrapper ./... ${{matrix.buildflags}}
|
||||
env:
|
||||
GOARCH: ${{ matrix.goarch }}
|
||||
- name: bench all
|
||||
run: ./tool/go test ${{matrix.buildflags}} -exec=/tmp/testwrapper -test.bench=. -test.benchtime=1x -test.run=^$
|
||||
run: PATH=$PWD/tool:$PATH /tmp/testwrapper ./... ${{matrix.buildflags}} -bench=. -benchtime=1x -run=^$
|
||||
env:
|
||||
GOARCH: ${{ matrix.goarch }}
|
||||
- name: check that no tracked files changed
|
||||
|
||||
@@ -7,16 +7,20 @@
|
||||
package flakytest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// InTestWrapper returns whether or not this binary is running under our test
|
||||
// wrapper.
|
||||
func InTestWrapper() bool {
|
||||
return os.Getenv("TS_IN_TESTWRAPPER") != ""
|
||||
}
|
||||
// FlakyTestLogMessage is a sentinel value that is printed to stderr when a
|
||||
// flaky test is marked. This is used by cmd/testwrapper to detect flaky tests
|
||||
// and retry them.
|
||||
const FlakyTestLogMessage = "flakytest: this is a known flaky test"
|
||||
|
||||
// FlakeAttemptEnv is an environment variable that is set by cmd/testwrapper
|
||||
// when a flaky test is retried. It contains the attempt number, starting at 1.
|
||||
const FlakeAttemptEnv = "TS_TESTWRAPPER_ATTEMPT"
|
||||
|
||||
var issueRegexp = regexp.MustCompile(`\Ahttps://github\.com/tailscale/[a-zA-Z0-9_.-]+/issues/\d+\z`)
|
||||
|
||||
@@ -30,16 +34,6 @@ func Mark(t testing.TB, issue string) {
|
||||
t.Fatalf("bad issue format: %q", issue)
|
||||
}
|
||||
|
||||
if !InTestWrapper() {
|
||||
return
|
||||
}
|
||||
|
||||
t.Cleanup(func() {
|
||||
if t.Failed() {
|
||||
t.Logf("flakytest: signaling test wrapper to retry test")
|
||||
|
||||
// Signal to test wrapper that we should restart.
|
||||
os.Exit(123)
|
||||
}
|
||||
})
|
||||
fmt.Fprintln(os.Stderr, FlakyTestLogMessage) // sentinel value for testwrapper
|
||||
t.Logf("flakytest: issue tracking this flaky test: %s", issue)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,10 @@
|
||||
|
||||
package flakytest
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestIssueFormat(t *testing.T) {
|
||||
testCases := []struct {
|
||||
@@ -24,3 +27,14 @@ func TestIssueFormat(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlakeRun(t *testing.T) {
|
||||
Mark(t, "https://github.com/tailscale/tailscale/issues/0") // random issue
|
||||
e := os.Getenv(FlakeAttemptEnv)
|
||||
if e == "" {
|
||||
t.Skip("not running in testwrapper")
|
||||
}
|
||||
if e == "1" {
|
||||
t.Fatal("failing on purpose")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,62 +1,231 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
// testwrapper is a wrapper for retrying flaky tests, using the -exec flag of
|
||||
// 'go test'. Tests that are flaky can use the 'flakytest' subpackage to mark
|
||||
// themselves as flaky and be retried on failure.
|
||||
// testwrapper is a wrapper for retrying flaky tests. It is an alternative to
|
||||
// `go test` and re-runs failed marked flaky tests (using the flakytest pkg). It
|
||||
// takes different arguments than go test and requires the first positional
|
||||
// argument to be the pattern to test.
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/exp/maps"
|
||||
"tailscale.com/cmd/testwrapper/flakytest"
|
||||
)
|
||||
|
||||
const (
|
||||
retryStatus = 123
|
||||
maxIterations = 3
|
||||
)
|
||||
const maxAttempts = 3
|
||||
|
||||
type testAttempt struct {
|
||||
name testName
|
||||
outcome string // "pass", "fail", "skip"
|
||||
logs bytes.Buffer
|
||||
isMarkedFlaky bool // set if the test is marked as flaky
|
||||
}
|
||||
|
||||
type testName struct {
|
||||
pkg string // "tailscale.com/types/key"
|
||||
name string // "TestFoo"
|
||||
}
|
||||
|
||||
type packageTests struct {
|
||||
// pattern is the package pattern to run.
|
||||
// Must be a single pattern, not a list of patterns.
|
||||
pattern string // "./...", "./types/key"
|
||||
// tests is a list of tests to run. If empty, all tests in the package are
|
||||
// run.
|
||||
tests []string // ["TestFoo", "TestBar"]
|
||||
}
|
||||
|
||||
type goTestOutput struct {
|
||||
Time time.Time
|
||||
Action string
|
||||
Package string
|
||||
Test string
|
||||
Output string
|
||||
}
|
||||
|
||||
var debug = os.Getenv("TS_TESTWRAPPER_DEBUG") != ""
|
||||
|
||||
func runTests(ctx context.Context, attempt int, pt *packageTests, otherArgs []string) []*testAttempt {
|
||||
args := []string{"test", "-json", pt.pattern}
|
||||
args = append(args, otherArgs...)
|
||||
if len(pt.tests) > 0 {
|
||||
runArg := strings.Join(pt.tests, "|")
|
||||
args = append(args, "-run", runArg)
|
||||
}
|
||||
if debug {
|
||||
fmt.Println("running", strings.Join(args, " "))
|
||||
}
|
||||
cmd := exec.CommandContext(ctx, "go", args...)
|
||||
r, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
log.Printf("error creating stdout pipe: %v", err)
|
||||
}
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
cmd.Env = os.Environ()
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%d", flakytest.FlakeAttemptEnv, attempt))
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
log.Printf("error starting test: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer close(done)
|
||||
cmd.Wait()
|
||||
}()
|
||||
|
||||
jd := json.NewDecoder(r)
|
||||
resultMap := make(map[testName]*testAttempt)
|
||||
var out []*testAttempt
|
||||
for {
|
||||
var goOutput goTestOutput
|
||||
if err := jd.Decode(&goOutput); err != nil {
|
||||
if errors.Is(err, io.EOF) || errors.Is(err, os.ErrClosed) {
|
||||
break
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
if goOutput.Test == "" {
|
||||
continue
|
||||
}
|
||||
name := testName{
|
||||
pkg: goOutput.Package,
|
||||
name: goOutput.Test,
|
||||
}
|
||||
if test, _, isSubtest := strings.Cut(goOutput.Test, "/"); isSubtest {
|
||||
name.name = test
|
||||
if goOutput.Action == "output" {
|
||||
resultMap[name].logs.WriteString(goOutput.Output)
|
||||
}
|
||||
continue
|
||||
}
|
||||
switch goOutput.Action {
|
||||
case "start":
|
||||
// ignore
|
||||
case "run":
|
||||
resultMap[name] = &testAttempt{
|
||||
name: name,
|
||||
}
|
||||
case "skip", "pass", "fail":
|
||||
resultMap[name].outcome = goOutput.Action
|
||||
out = append(out, resultMap[name])
|
||||
case "output":
|
||||
if strings.TrimSpace(goOutput.Output) == flakytest.FlakyTestLogMessage {
|
||||
resultMap[name].isMarkedFlaky = true
|
||||
} else {
|
||||
resultMap[name].logs.WriteString(goOutput.Output)
|
||||
}
|
||||
}
|
||||
}
|
||||
<-done
|
||||
return out
|
||||
}
|
||||
|
||||
func main() {
|
||||
ctx := context.Background()
|
||||
debug := os.Getenv("TS_TESTWRAPPER_DEBUG") != ""
|
||||
|
||||
log.SetPrefix("testwrapper: ")
|
||||
if !debug {
|
||||
log.SetFlags(0)
|
||||
// We only need to parse the -v flag to figure out whether to print the logs
|
||||
// for a test. We don't need to parse any other flags, so we just use the
|
||||
// flag package to parse the -v flag and then pass the rest of the args
|
||||
// through to 'go test'.
|
||||
// We run `go test -json` which returns the same information as `go test -v`,
|
||||
// but in a machine-readable format. So this flag is only for testwrapper's
|
||||
// output.
|
||||
v := flag.Bool("v", false, "verbose")
|
||||
|
||||
flag.Usage = func() {
|
||||
fmt.Println("usage: testwrapper [testwrapper-flags] [pattern] [build/test flags & test binary flags]")
|
||||
fmt.Println()
|
||||
fmt.Println("testwrapper-flags:")
|
||||
flag.CommandLine.PrintDefaults()
|
||||
fmt.Println()
|
||||
fmt.Println("examples:")
|
||||
fmt.Println("\ttestwrapper -v ./... -count=1")
|
||||
fmt.Println("\ttestwrapper ./pkg/foo -run TestBar -count=1")
|
||||
fmt.Println()
|
||||
fmt.Println("Unlike 'go test', testwrapper requires a package pattern as the first positional argument and only supports a single pattern.")
|
||||
}
|
||||
flag.Parse()
|
||||
|
||||
args := flag.Args()
|
||||
if len(args) < 1 || strings.HasPrefix(args[0], "-") {
|
||||
fmt.Println("no pattern specified")
|
||||
flag.Usage()
|
||||
os.Exit(1)
|
||||
} else if len(args) > 1 && !strings.HasPrefix(args[1], "-") {
|
||||
fmt.Println("expected single pattern")
|
||||
flag.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
pattern, otherArgs := args[0], args[1:]
|
||||
|
||||
toRun := []*packageTests{ // packages still to test
|
||||
{pattern: pattern},
|
||||
}
|
||||
|
||||
for i := 1; i <= maxIterations; i++ {
|
||||
if i > 1 {
|
||||
log.Printf("retrying flaky tests (%d of %d)", i, maxIterations)
|
||||
}
|
||||
cmd := exec.CommandContext(ctx, os.Args[1], os.Args[2:]...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Env = append(os.Environ(), "TS_IN_TESTWRAPPER=1")
|
||||
err := cmd.Run()
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
pkgAttempts := make(map[string]int) // tracks how many times we've tried a package
|
||||
|
||||
var exitErr *exec.ExitError
|
||||
if !errors.As(err, &exitErr) {
|
||||
if debug {
|
||||
log.Printf("error isn't an ExitError")
|
||||
attempt := 0
|
||||
for len(toRun) > 0 {
|
||||
attempt++
|
||||
var pt *packageTests
|
||||
pt, toRun = toRun[0], toRun[1:]
|
||||
|
||||
toRetry := make(map[string][]string) // pkg -> tests to retry
|
||||
|
||||
failed := false
|
||||
for _, tr := range runTests(ctx, attempt, pt, otherArgs) {
|
||||
if *v || tr.outcome == "fail" {
|
||||
io.Copy(os.Stderr, &tr.logs)
|
||||
}
|
||||
if tr.outcome != "fail" {
|
||||
continue
|
||||
}
|
||||
if tr.isMarkedFlaky {
|
||||
toRetry[tr.name.pkg] = append(toRetry[tr.name.pkg], tr.name.name)
|
||||
} else {
|
||||
failed = true
|
||||
}
|
||||
}
|
||||
if failed {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if code := exitErr.ExitCode(); code != retryStatus {
|
||||
if debug {
|
||||
log.Printf("code (%d) != retryStatus (%d)", code, retryStatus)
|
||||
pkgs := maps.Keys(toRetry)
|
||||
sort.Strings(pkgs)
|
||||
for _, pkg := range pkgs {
|
||||
tests := toRetry[pkg]
|
||||
sort.Strings(tests)
|
||||
pkgAttempts[pkg]++
|
||||
if pkgAttempts[pkg] >= maxAttempts {
|
||||
fmt.Println("Too many attempts for flaky tests:", pkg, tests)
|
||||
continue
|
||||
}
|
||||
os.Exit(code)
|
||||
fmt.Println("\nRetrying flaky tests:", pkg, tests)
|
||||
toRun = append(toRun, &packageTests{
|
||||
pattern: pkg,
|
||||
tests: tests,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("test did not pass in %d iterations", maxIterations)
|
||||
os.Exit(1)
|
||||
for _, a := range pkgAttempts {
|
||||
if a >= maxAttempts {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
fmt.Println("PASS")
|
||||
}
|
||||
|
||||
176
cmd/tsmultiserve/main.go
Normal file
176
cmd/tsmultiserve/main.go
Normal file
@@ -0,0 +1,176 @@
|
||||
// Server tsmultiserve is a TCP proxy that can register and listen on multiple tailscale addresses
|
||||
// using tsnet.
|
||||
//
|
||||
// The main motivation for this is to run multiple services on the same host, but give
|
||||
// them memorable names and use canonical ports.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// tsmultiserve [ts-node:ts-port:dst-host:dst-port ...]
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// tsmultiserve cameras:http:localhost:8001 cameras:rtsp:localhost:rtsp phone:sip:localhost:sip
|
||||
//
|
||||
// This will register two nodes on your tailnet, "cameras" and "phone". On cameras it will forward
|
||||
// port 80 to localhost:8001 and port 554 (rtsp) to localhost:554, and on phone it will forward port
|
||||
// 5060 (sip) to localhost:5060.
|
||||
//
|
||||
// You can get the same effect if you:
|
||||
// 1. Run multiple tailscaleds in separate network namespaces or containers, but that can get complicated.
|
||||
// 2. Use the caddy-tailscale extension, but that's HTTP only.
|
||||
// 2. Use an HTTP proxy & vitual hosts, but now you have to set your own DNS. Also HTTP (or TLS) only.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"tailscale.com/ipn"
|
||||
"tailscale.com/tsnet"
|
||||
)
|
||||
|
||||
var logf = func(string, ...any) {}
|
||||
|
||||
var (
|
||||
statedir string
|
||||
verbose bool
|
||||
)
|
||||
|
||||
func authkeyForHost(h string) string {
|
||||
authkey := os.Getenv("TS_AUTHKEY_" + h)
|
||||
if authkey != "" {
|
||||
log.Printf("%v: using authkey from $TS_AUTHKEY_%s", h, h)
|
||||
return authkey
|
||||
}
|
||||
authkey = os.Getenv("TS_AUTHKEY")
|
||||
if authkey != "" {
|
||||
log.Printf("%v: using authkey from $TS_AUTHKEY", h)
|
||||
return authkey
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func up(node string, cfg *ipn.ServeConfig) {
|
||||
ctx := context.Background()
|
||||
statedir := filepath.Join(statedir, node)
|
||||
|
||||
err := os.MkdirAll(statedir, 0770)
|
||||
if err != nil {
|
||||
log.Fatalf("%v: could not make state directory (%s): %v", node, statedir, err)
|
||||
}
|
||||
srv := &tsnet.Server{
|
||||
Hostname: node,
|
||||
Dir: statedir,
|
||||
Logf: logf,
|
||||
AuthKey: authkeyForHost(node),
|
||||
}
|
||||
defer srv.Close()
|
||||
|
||||
lc, err := srv.LocalClient()
|
||||
if err != nil {
|
||||
log.Fatalf("%v: could not get local client: %v", node, err)
|
||||
}
|
||||
|
||||
watcher, err := lc.WatchIPNBus(ctx, ipn.NotifyWatchEngineUpdates|ipn.NotifyInitialState|ipn.NotifyNoPrivateKeys)
|
||||
if err != nil {
|
||||
log.Fatalf("%v: %v", node, err)
|
||||
}
|
||||
defer watcher.Close()
|
||||
login:
|
||||
for {
|
||||
n, err := watcher.Next()
|
||||
if err != nil {
|
||||
log.Fatalf("%v: %v", node, err)
|
||||
}
|
||||
if n.ErrMessage != nil {
|
||||
log.Fatalf("%v: %v", node, err)
|
||||
}
|
||||
if state := n.State; state != nil {
|
||||
switch *state {
|
||||
case ipn.Running:
|
||||
break login
|
||||
case ipn.NeedsLogin:
|
||||
if srv.AuthKey == "" {
|
||||
status, err := lc.Status(ctx)
|
||||
if err != nil {
|
||||
log.Fatalf("%v: %v", node, err)
|
||||
}
|
||||
// TODO figure out why this doesn't work without polling. AuthURL isn't always set
|
||||
// immediately after NeedsLogin, possibly a race?
|
||||
for status.AuthURL == "" {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
status, err = lc.Status(ctx)
|
||||
if err != nil {
|
||||
log.Fatalf("%v: %v", node, err)
|
||||
}
|
||||
}
|
||||
log.Printf("%v login: %s", node, status.AuthURL)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err = lc.SetServeConfig(ctx, cfg)
|
||||
if err != nil {
|
||||
log.Fatalf("%v: could not set serve config: %v", node, err)
|
||||
}
|
||||
}
|
||||
|
||||
func usage() {
|
||||
fmt.Fprintf(os.Stderr, "usage:\n")
|
||||
fmt.Fprintf(os.Stderr, "\ttsmultiserve tailscale-host:tailscale-port:target-host:target-port ...\n\n")
|
||||
fmt.Fprintf(os.Stderr, "flags:\n")
|
||||
flag.PrintDefaults()
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
func main() {
|
||||
log.SetFlags(0)
|
||||
flag.Usage = usage
|
||||
configdir, _ := os.UserConfigDir() // Ignore error. Empty string means we fall back to current directory.
|
||||
flag.StringVar(&statedir, "state-dir", filepath.Join(configdir, "tsmultiserve"), "directory to keep tailscale state")
|
||||
flag.BoolVar(&verbose, "verbose", false, "be verbose")
|
||||
flag.Parse()
|
||||
|
||||
if verbose {
|
||||
logf = log.Printf
|
||||
}
|
||||
|
||||
if flag.NArg() == 0 {
|
||||
usage()
|
||||
}
|
||||
|
||||
nodes := map[string]*ipn.ServeConfig{}
|
||||
for _, arg := range flag.Args() {
|
||||
parts := strings.Split(arg, ":")
|
||||
if len(parts) != 4 {
|
||||
log.Fatalf("could not parse proxy directive")
|
||||
}
|
||||
host, port, dst := parts[0], parts[1], parts[2]+":"+parts[3]
|
||||
|
||||
p, err := net.LookupPort("tcp", port)
|
||||
if err != nil {
|
||||
log.Fatalf("could not lookup port (%v): %v", port, err)
|
||||
}
|
||||
|
||||
if nodes[host] == nil {
|
||||
nodes[host] = &ipn.ServeConfig{TCP: map[uint16]*ipn.TCPPortHandler{}}
|
||||
}
|
||||
|
||||
nodes[host].TCP[uint16(p)] = &ipn.TCPPortHandler{TCPForward: dst}
|
||||
}
|
||||
|
||||
for n, cfg := range nodes {
|
||||
up(n, cfg)
|
||||
}
|
||||
|
||||
select {}
|
||||
}
|
||||
@@ -583,19 +583,20 @@ func TestDialPlan(t *testing.T) {
|
||||
}},
|
||||
want: goodAddr,
|
||||
},
|
||||
{
|
||||
name: "multiple-priority-fast-path",
|
||||
plan: &tailcfg.ControlDialPlan{Candidates: []tailcfg.ControlIPCandidate{
|
||||
// Dials some good IPs and our bad one (which
|
||||
// hangs forever), which then hits the fast
|
||||
// path where we bail without waiting.
|
||||
{IP: brokenAddr, Priority: 1, DialTimeoutSec: 10},
|
||||
{IP: goodAddr, Priority: 1, DialTimeoutSec: 10},
|
||||
{IP: other2Addr, Priority: 1, DialTimeoutSec: 10},
|
||||
{IP: otherAddr, Priority: 2, DialTimeoutSec: 10},
|
||||
}},
|
||||
want: otherAddr,
|
||||
},
|
||||
// TODO(#8442): fix this test
|
||||
// {
|
||||
// name: "multiple-priority-fast-path",
|
||||
// plan: &tailcfg.ControlDialPlan{Candidates: []tailcfg.ControlIPCandidate{
|
||||
// // Dials some good IPs and our bad one (which
|
||||
// // hangs forever), which then hits the fast
|
||||
// // path where we bail without waiting.
|
||||
// {IP: brokenAddr, Priority: 1, DialTimeoutSec: 10},
|
||||
// {IP: goodAddr, Priority: 1, DialTimeoutSec: 10},
|
||||
// {IP: other2Addr, Priority: 1, DialTimeoutSec: 10},
|
||||
// {IP: otherAddr, Priority: 2, DialTimeoutSec: 10},
|
||||
// }},
|
||||
// want: otherAddr,
|
||||
// },
|
||||
{
|
||||
name: "multiple-priority-slow-path",
|
||||
plan: &tailcfg.ControlDialPlan{Candidates: []tailcfg.ControlIPCandidate{
|
||||
|
||||
@@ -283,7 +283,7 @@ func inContainer() opt.Bool {
|
||||
return nil
|
||||
})
|
||||
lineread.File("/proc/mounts", func(line []byte) error {
|
||||
if mem.Contains(mem.B(line), mem.S("fuse.lxcfs")) {
|
||||
if mem.Contains(mem.B(line), mem.S("lxcfs /proc/cpuinfo fuse.lxcfs")) {
|
||||
ret.Set(true)
|
||||
return io.EOF
|
||||
}
|
||||
|
||||
@@ -139,7 +139,13 @@ func TestHash(t *testing.T) {
|
||||
{in: tuple{netip.AddrPortFrom(netip.AddrFrom4([4]byte{192, 168, 0, 1}), 1234), netip.AddrPortFrom(netip.AddrFrom4([4]byte{192, 168, 0, 1}), 1235)}, wantEq: false},
|
||||
{in: tuple{netip.AddrPortFrom(netip.AddrFrom4([4]byte{192, 168, 0, 1}), 1234), netip.AddrPortFrom(netip.AddrFrom4([4]byte{192, 168, 0, 2}), 1234)}, wantEq: false},
|
||||
{in: tuple{netip.Prefix{}, netip.Prefix{}}, wantEq: true},
|
||||
{in: tuple{netip.Prefix{}, netip.PrefixFrom(netip.Addr{}, 1)}, wantEq: false},
|
||||
|
||||
// In go1.21 PrefixFrom will now return a zero value Prefix if the
|
||||
// provided Addr is unspecified. This is a change from previous
|
||||
// behavior, so we disable this test for now.
|
||||
// TODO(#8419): renable after go1.21 is released.
|
||||
// {in: tuple{netip.Prefix{}, netip.PrefixFrom(netip.Addr{}, 1)}, wantEq: true},
|
||||
|
||||
{in: tuple{netip.Prefix{}, netip.PrefixFrom(netip.AddrFrom4([4]byte{}), 0)}, wantEq: false},
|
||||
{in: tuple{netip.PrefixFrom(netip.AddrFrom4([4]byte{}), 1), netip.PrefixFrom(netip.AddrFrom4([4]byte{}), 1)}, wantEq: true},
|
||||
{in: tuple{netip.PrefixFrom(netip.AddrFrom4([4]byte{192, 168, 0, 1}), 1), netip.PrefixFrom(netip.AddrFrom4([4]byte{192, 168, 0, 1}), 1)}, wantEq: true},
|
||||
@@ -460,8 +466,8 @@ func TestGetTypeHasher(t *testing.T) {
|
||||
{
|
||||
name: "packet_filter",
|
||||
val: filterRules,
|
||||
out: "\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\x01\x03\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\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\x00\x00\x00\x00\x01\x00\x02\x00\x01\x04\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\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 \x00\x01\x01\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00foo\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",
|
||||
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\x01\x03\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\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 \x00\x01\x01\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00foo\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",
|
||||
out: "\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\x01\x03\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\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\x00\x00\x00\x00\x01\x00\x02\x00\x01\x04\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\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\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",
|
||||
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\x01\x03\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\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\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",
|
||||
@@ -581,6 +587,10 @@ func TestGetTypeHasher(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.name == "packet_filter" {
|
||||
// TODO(#8419): Re-enable when we move to Go 1.21.
|
||||
t.Skip("this has a different output between Go 1.20 and Go 1.21, so skip it for now")
|
||||
}
|
||||
rv := reflect.ValueOf(tt.val)
|
||||
va := reflect.New(rv.Type()).Elem()
|
||||
va.Set(rv)
|
||||
|
||||
Reference in New Issue
Block a user