Skip to content

Commit 49ab0db

Browse files
committed
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/53530 Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent 310ba82 commit 49ab0db

File tree

3 files changed

+139
-3
lines changed

3 files changed

+139
-3
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2017 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// Export guts for testing on windows.
6+
// Since testing imports os and os imports internal/poll,
7+
// the internal/poll tests can not be in package poll.
8+
9+
package poll
10+
11+
var (
12+
LogInitFD = &logInitFD
13+
)
14+
15+
func (fd *FD) IsPartOfNetpoll() bool {
16+
return fd.pd.runtimeCtx != 0
17+
}

src/internal/poll/fd_windows.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,9 @@ type FD struct {
295295
isDir bool
296296
}
297297

298+
// logInitFD is set by tests to enable file descriptor initialization logging.
299+
var logInitFD func(net string, fd *FD, err error)
300+
298301
// Init initializes the FD. The Sysfd field should already be set.
299302
// This can be called multiple times on a single FD.
300303
// 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) {
319322
return "", errors.New("internal error: unknown network type " + net)
320323
}
321324

325+
var err error
322326
if !fd.isFile && !fd.isConsole && !fd.isDir {
323327
// Only call init for a network socket.
324328
// This means that we don't add files to the runtime poller.
@@ -331,9 +335,13 @@ func (fd *FD) Init(net string) (string, error) {
331335
// somehow call ExecIO, then ExecIO, and therefore the
332336
// calling method, will return an error, because
333337
// fd.pd.runtimeCtx will be 0.
334-
if err := fd.pd.init(fd); err != nil {
335-
return "", err
336-
}
338+
err = fd.pd.init(fd)
339+
}
340+
if logInitFD != nil {
341+
logInitFD(net, fd, err)
342+
}
343+
if err != nil {
344+
return "", err
337345
}
338346
if hasLoadSetFileCompletionNotificationModes {
339347
// We do not use events, so we can skip them always.

src/internal/poll/fd_windows_test.go

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// Copyright 2017 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package poll_test
6+
7+
import (
8+
"fmt"
9+
"internal/poll"
10+
"os"
11+
"sync"
12+
"syscall"
13+
"testing"
14+
)
15+
16+
type loggedFD struct {
17+
Net string
18+
FD *poll.FD
19+
Err error
20+
}
21+
22+
var (
23+
logMu sync.Mutex
24+
loggedFDs map[syscall.Handle]*loggedFD
25+
)
26+
27+
func logFD(net string, fd *poll.FD, err error) {
28+
logMu.Lock()
29+
defer logMu.Unlock()
30+
31+
loggedFDs[fd.Sysfd] = &loggedFD{
32+
Net: net,
33+
FD: fd,
34+
Err: err,
35+
}
36+
}
37+
38+
func init() {
39+
loggedFDs = make(map[syscall.Handle]*loggedFD)
40+
*poll.LogInitFD = logFD
41+
}
42+
43+
func findLoggedFD(h syscall.Handle) (lfd *loggedFD, found bool) {
44+
logMu.Lock()
45+
defer logMu.Unlock()
46+
47+
lfd, found = loggedFDs[h]
48+
return lfd, found
49+
}
50+
51+
// checkFileIsNotPartOfNetpoll verifies that f is not managed by netpoll.
52+
// It returns error, if check fails.
53+
func checkFileIsNotPartOfNetpoll(f *os.File) error {
54+
lfd, found := findLoggedFD(syscall.Handle(f.Fd()))
55+
if !found {
56+
return fmt.Errorf("%v fd=%v: is not found in the log", f.Name(), f.Fd())
57+
}
58+
if lfd.FD.IsPartOfNetpoll() {
59+
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)
60+
}
61+
return nil
62+
}
63+
64+
func TestFileFdsAreInitialised(t *testing.T) {
65+
exe, err := os.Executable()
66+
if err != nil {
67+
t.Fatal(err)
68+
}
69+
f, err := os.Open(exe)
70+
if err != nil {
71+
t.Fatal(err)
72+
}
73+
defer f.Close()
74+
75+
err = checkFileIsNotPartOfNetpoll(f)
76+
if err != nil {
77+
t.Fatal(err)
78+
}
79+
}
80+
81+
func TestSerialFdsAreInitialised(t *testing.T) {
82+
for _, name := range []string{"COM1", "COM2", "COM3", "COM4"} {
83+
t.Run(name, func(t *testing.T) {
84+
h, err := syscall.CreateFile(syscall.StringToUTF16Ptr(name),
85+
syscall.GENERIC_READ|syscall.GENERIC_WRITE,
86+
0,
87+
nil,
88+
syscall.OPEN_EXISTING,
89+
syscall.FILE_ATTRIBUTE_NORMAL|syscall.FILE_FLAG_OVERLAPPED,
90+
0)
91+
if err != nil {
92+
if errno, ok := err.(syscall.Errno); ok {
93+
switch errno {
94+
case syscall.ERROR_FILE_NOT_FOUND,
95+
syscall.ERROR_ACCESS_DENIED:
96+
t.Log("Skipping: ", err)
97+
return
98+
}
99+
}
100+
t.Fatal(err)
101+
}
102+
f := os.NewFile(uintptr(h), name)
103+
defer f.Close()
104+
105+
err = checkFileIsNotPartOfNetpoll(f)
106+
if err != nil {
107+
t.Fatal(err)
108+
}
109+
})
110+
}
111+
}

0 commit comments

Comments
 (0)