.github, tool/listpkgs: automatically find tests which use tstest.RequireRoot
Updates tailscale/corp#40007 Change-Id: I677d3d9e276cb6633a14ac07e4b58ea08e52fac4 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
committed by
Brad Fitzpatrick
parent
ca5db865b4
commit
cf59a6fb23
@@ -361,7 +361,7 @@ jobs:
|
|||||||
run: chown -R $(id -u):$(id -g) $PWD
|
run: chown -R $(id -u):$(id -g) $PWD
|
||||||
- name: privileged tests
|
- name: privileged tests
|
||||||
working-directory: src
|
working-directory: src
|
||||||
run: ./tool/go test ./util/linuxfw ./derp/xdp
|
run: ./tool/go test $(./tool/go run ./tool/listpkgs --has-root-tests)
|
||||||
|
|
||||||
vm:
|
vm:
|
||||||
needs: gomod-cache
|
needs: gomod-cache
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import (
|
|||||||
"gvisor.dev/gvisor/pkg/tcpip/checksum"
|
"gvisor.dev/gvisor/pkg/tcpip/checksum"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||||
"tailscale.com/net/stun"
|
"tailscale.com/net/stun"
|
||||||
|
"tailscale.com/tstest"
|
||||||
)
|
)
|
||||||
|
|
||||||
type xdpAction uint32
|
type xdpAction uint32
|
||||||
@@ -271,6 +272,7 @@ func getIPv6STUNBindingResp() []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestXDP(t *testing.T) {
|
func TestXDP(t *testing.T) {
|
||||||
|
tstest.RequireRoot(t)
|
||||||
ipv4STUNBindingReqTX := getIPv4STUNBindingReq(nil)
|
ipv4STUNBindingReqTX := getIPv4STUNBindingReq(nil)
|
||||||
ipv6STUNBindingReqTX := getIPv6STUNBindingReq(nil)
|
ipv6STUNBindingReqTX := getIPv6STUNBindingReq(nil)
|
||||||
|
|
||||||
@@ -957,10 +959,6 @@ func TestXDP(t *testing.T) {
|
|||||||
server, err := NewSTUNServer(&STUNServerConfig{DeviceName: "fake", DstPort: defaultSTUNPort},
|
server, err := NewSTUNServer(&STUNServerConfig{DeviceName: "fake", DstPort: defaultSTUNPort},
|
||||||
&noAttachOption{})
|
&noAttachOption{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, unix.EPERM) {
|
|
||||||
// TODO(jwhited): get this running
|
|
||||||
t.Skip("skipping due to EPERM error; test requires elevated privileges")
|
|
||||||
}
|
|
||||||
t.Fatalf("error constructing STUN server: %v", err)
|
t.Fatalf("error constructing STUN server: %v", err)
|
||||||
}
|
}
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|||||||
@@ -386,7 +386,14 @@ type localState struct {
|
|||||||
serverActions map[string]*tailcfg.SSHAction
|
serverActions map[string]*tailcfg.SSHAction
|
||||||
}
|
}
|
||||||
|
|
||||||
var currentUser = os.Getenv("USER") // Use the current user for the test.
|
var currentUser = func() string {
|
||||||
|
// Prefer user.Current because the USER env var is not set in
|
||||||
|
// some environments (e.g. the golang:latest container used by CI).
|
||||||
|
if u, err := user.Current(); err == nil {
|
||||||
|
return u.Username
|
||||||
|
}
|
||||||
|
return os.Getenv("USER")
|
||||||
|
}()
|
||||||
|
|
||||||
func (ts *localState) Dialer() *tsdial.Dialer {
|
func (ts *localState) Dialer() *tsdial.Dialer {
|
||||||
return &tsdial.Dialer{}
|
return &tsdial.Dialer{}
|
||||||
|
|||||||
@@ -10,9 +10,12 @@ import (
|
|||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/build/constraint"
|
"go/build/constraint"
|
||||||
|
"io/fs"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"slices"
|
"slices"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@@ -27,11 +30,17 @@ var (
|
|||||||
withoutTagsAnyStr = flag.String("without-tags-any", "", "if non-empty, a comma-separated list of build constraints to exclude (a package will be omitted if it contains any of these build tags)")
|
withoutTagsAnyStr = flag.String("without-tags-any", "", "if non-empty, a comma-separated list of build constraints to exclude (a package will be omitted if it contains any of these build tags)")
|
||||||
shard = flag.String("shard", "", "if non-empty, a string of the form 'N/M' to only print packages in shard N of M (e.g. '1/3', '2/3', '3/3/' for different thirds of the list)")
|
shard = flag.String("shard", "", "if non-empty, a string of the form 'N/M' to only print packages in shard N of M (e.g. '1/3', '2/3', '3/3/' for different thirds of the list)")
|
||||||
affectedByTag = flag.String("affected-by-tag", "", "if non-empty, only list packages whose test binary would be affected by the presence or absence of this build tag")
|
affectedByTag = flag.String("affected-by-tag", "", "if non-empty, only list packages whose test binary would be affected by the presence or absence of this build tag")
|
||||||
|
hasRootTests = flag.Bool("has-root-tests", false, "list packages (as ./relative/path) containing _test.go files that call tstest.RequireRoot")
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
if *hasRootTests {
|
||||||
|
printRootTestPkgs()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
patterns := flag.Args()
|
patterns := flag.Args()
|
||||||
if len(patterns) == 0 {
|
if len(patterns) == 0 {
|
||||||
flag.Usage()
|
flag.Usage()
|
||||||
@@ -281,3 +290,64 @@ func fileMentionsTag(filename, tag string) (bool, error) {
|
|||||||
}
|
}
|
||||||
return tags[tag], nil
|
return tags[tag], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// printRootTestPkgs walks the current directory tree looking for _test.go
|
||||||
|
// files that contain "tstest.RequireRoot" and prints the unique package
|
||||||
|
// directories as ./relative/path.
|
||||||
|
func printRootTestPkgs() {
|
||||||
|
root, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
seen := map[string]bool{}
|
||||||
|
var dirs []string
|
||||||
|
filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
name := d.Name()
|
||||||
|
if d.IsDir() {
|
||||||
|
// Skip hidden dirs and common non-Go dirs.
|
||||||
|
if strings.HasPrefix(name, ".") || name == "vendor" || name == "node_modules" {
|
||||||
|
return filepath.SkipDir
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if !strings.HasSuffix(name, "_test.go") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
rel, err := filepath.Rel(root, path)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
dir := filepath.Dir(rel)
|
||||||
|
if seen[dir] {
|
||||||
|
return nil // already found a match in this dir
|
||||||
|
}
|
||||||
|
if fileContains(path, "tstest.RequireRoot") {
|
||||||
|
seen[dir] = true
|
||||||
|
dirs = append(dirs, dir)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
sort.Strings(dirs)
|
||||||
|
for _, d := range dirs {
|
||||||
|
fmt.Println("./" + filepath.ToSlash(d))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fileContains reports whether the file at path contains the given substring.
|
||||||
|
func fileContains(path, substr string) bool {
|
||||||
|
f, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
s := bufio.NewScanner(f)
|
||||||
|
for s.Scan() {
|
||||||
|
if strings.Contains(s.Text(), substr) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"os"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -522,10 +521,7 @@ func TestAddMatchSubnetRouteMarkRuleAccept(t *testing.T) {
|
|||||||
|
|
||||||
func newSysConn(t *testing.T) *nftables.Conn {
|
func newSysConn(t *testing.T) *nftables.Conn {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
if os.Geteuid() != 0 {
|
tstest.RequireRoot(t)
|
||||||
t.Skip(t.Name(), " requires privileges to create a namespace in order to run")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
runtime.LockOSThread()
|
runtime.LockOSThread()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user