Commit 49ab0dba authored by Alex Brainman's avatar Alex Brainman

internal/poll: add tests for Windows file and serial ports

I also wanted to test net sockets, but I do not know how to
access their file handles. So I did not implement socket tests.

Updates #21172

Change-Id: I5062c0e65a817571d755397d60762c175f9791ce
Reviewed-on: https://go-review.googlesource.com/53530Reviewed-by: default avatarIan Lance Taylor <iant@golang.org>
parent 310ba828
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Export guts for testing on windows.
// Since testing imports os and os imports internal/poll,
// the internal/poll tests can not be in package poll.
package poll
var (
LogInitFD = &logInitFD
)
func (fd *FD) IsPartOfNetpoll() bool {
return fd.pd.runtimeCtx != 0
}
...@@ -295,6 +295,9 @@ type FD struct { ...@@ -295,6 +295,9 @@ type FD struct {
isDir bool isDir bool
} }
// logInitFD is set by tests to enable file descriptor initialization logging.
var logInitFD func(net string, fd *FD, err error)
// Init initializes the FD. The Sysfd field should already be set. // Init initializes the FD. The Sysfd field should already be set.
// This can be called multiple times on a single FD. // This can be called multiple times on a single FD.
// The net argument is a network name from the net package (e.g., "tcp"), // The net argument is a network name from the net package (e.g., "tcp"),
...@@ -319,6 +322,7 @@ func (fd *FD) Init(net string) (string, error) { ...@@ -319,6 +322,7 @@ func (fd *FD) Init(net string) (string, error) {
return "", errors.New("internal error: unknown network type " + net) return "", errors.New("internal error: unknown network type " + net)
} }
var err error
if !fd.isFile && !fd.isConsole && !fd.isDir { if !fd.isFile && !fd.isConsole && !fd.isDir {
// Only call init for a network socket. // Only call init for a network socket.
// This means that we don't add files to the runtime poller. // This means that we don't add files to the runtime poller.
...@@ -331,9 +335,13 @@ func (fd *FD) Init(net string) (string, error) { ...@@ -331,9 +335,13 @@ func (fd *FD) Init(net string) (string, error) {
// somehow call ExecIO, then ExecIO, and therefore the // somehow call ExecIO, then ExecIO, and therefore the
// calling method, will return an error, because // calling method, will return an error, because
// fd.pd.runtimeCtx will be 0. // fd.pd.runtimeCtx will be 0.
if err := fd.pd.init(fd); err != nil { err = fd.pd.init(fd)
return "", err }
} if logInitFD != nil {
logInitFD(net, fd, err)
}
if err != nil {
return "", err
} }
if hasLoadSetFileCompletionNotificationModes { if hasLoadSetFileCompletionNotificationModes {
// We do not use events, so we can skip them always. // We do not use events, so we can skip them always.
......
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package poll_test
import (
"fmt"
"internal/poll"
"os"
"sync"
"syscall"
"testing"
)
type loggedFD struct {
Net string
FD *poll.FD
Err error
}
var (
logMu sync.Mutex
loggedFDs map[syscall.Handle]*loggedFD
)
func logFD(net string, fd *poll.FD, err error) {
logMu.Lock()
defer logMu.Unlock()
loggedFDs[fd.Sysfd] = &loggedFD{
Net: net,
FD: fd,
Err: err,
}
}
func init() {
loggedFDs = make(map[syscall.Handle]*loggedFD)
*poll.LogInitFD = logFD
}
func findLoggedFD(h syscall.Handle) (lfd *loggedFD, found bool) {
logMu.Lock()
defer logMu.Unlock()
lfd, found = loggedFDs[h]
return lfd, found
}
// checkFileIsNotPartOfNetpoll verifies that f is not managed by netpoll.
// It returns error, if check fails.
func checkFileIsNotPartOfNetpoll(f *os.File) error {
lfd, found := findLoggedFD(syscall.Handle(f.Fd()))
if !found {
return fmt.Errorf("%v fd=%v: is not found in the log", f.Name(), f.Fd())
}
if lfd.FD.IsPartOfNetpoll() {
return fmt.Errorf("%v fd=%v: is part of netpoll, but should not be (logged: net=%v err=%v)", f.Name(), f.Fd(), lfd.Net, lfd.Err)
}
return nil
}
func TestFileFdsAreInitialised(t *testing.T) {
exe, err := os.Executable()
if err != nil {
t.Fatal(err)
}
f, err := os.Open(exe)
if err != nil {
t.Fatal(err)
}
defer f.Close()
err = checkFileIsNotPartOfNetpoll(f)
if err != nil {
t.Fatal(err)
}
}
func TestSerialFdsAreInitialised(t *testing.T) {
for _, name := range []string{"COM1", "COM2", "COM3", "COM4"} {
t.Run(name, func(t *testing.T) {
h, err := syscall.CreateFile(syscall.StringToUTF16Ptr(name),
syscall.GENERIC_READ|syscall.GENERIC_WRITE,
0,
nil,
syscall.OPEN_EXISTING,
syscall.FILE_ATTRIBUTE_NORMAL|syscall.FILE_FLAG_OVERLAPPED,
0)
if err != nil {
if errno, ok := err.(syscall.Errno); ok {
switch errno {
case syscall.ERROR_FILE_NOT_FOUND,
syscall.ERROR_ACCESS_DENIED:
t.Log("Skipping: ", err)
return
}
}
t.Fatal(err)
}
f := os.NewFile(uintptr(h), name)
defer f.Close()
err = checkFileIsNotPartOfNetpoll(f)
if err != nil {
t.Fatal(err)
}
})
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment