Skip to content

Commit 963e014

Browse files
authored
Merge pull request opencontainers#3158 from kolyshkin/nsenter-tests
libct/nsenter/nsenter_test.go: fix and improve
2 parents 7fcfb3f + 33dcb99 commit 963e014

File tree

1 file changed

+78
-72
lines changed

1 file changed

+78
-72
lines changed

libcontainer/nsenter/nsenter_test.go

Lines changed: 78 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"errors"
77
"fmt"
88
"io"
9-
"io/ioutil"
109
"os"
1110
"os/exec"
1211
"strings"
@@ -17,21 +16,9 @@ import (
1716
"golang.org/x/sys/unix"
1817
)
1918

20-
type pid struct {
21-
Pid int `json:"Pid"`
22-
}
23-
24-
type logentry struct {
25-
Msg string `json:"msg"`
26-
Level string `json:"level"`
27-
}
28-
2919
func TestNsenterValidPaths(t *testing.T) {
3020
args := []string{"nsenter-exec"}
31-
parent, child, err := newPipe()
32-
if err != nil {
33-
t.Fatalf("failed to create pipe %v", err)
34-
}
21+
parent, child := newPipe(t)
3522

3623
namespaces := []string{
3724
// join pid ns of the current process
@@ -47,8 +34,9 @@ func TestNsenterValidPaths(t *testing.T) {
4734
}
4835

4936
if err := cmd.Start(); err != nil {
50-
t.Fatalf("nsenter failed to start %v", err)
37+
t.Fatalf("nsenter failed to start: %v", err)
5138
}
39+
child.Close()
5240

5341
// write cloneFlags
5442
r := nl.NewNetlinkRequest(int(libcontainer.InitMsg), 0)
@@ -66,36 +54,18 @@ func TestNsenterValidPaths(t *testing.T) {
6654

6755
initWaiter(t, parent)
6856

69-
decoder := json.NewDecoder(parent)
70-
var pid *pid
71-
7257
if err := cmd.Wait(); err != nil {
73-
t.Fatalf("nsenter exits with a non-zero exit status")
74-
}
75-
if err := decoder.Decode(&pid); err != nil {
76-
dir, _ := ioutil.ReadDir(fmt.Sprintf("/proc/%d/ns", os.Getpid()))
77-
for _, d := range dir {
78-
t.Log(d.Name())
79-
}
80-
t.Fatalf("%v", err)
58+
t.Fatalf("nsenter error: %v", err)
8159
}
8260

83-
p, err := os.FindProcess(pid.Pid)
84-
if err != nil {
85-
t.Fatalf("%v", err)
86-
}
87-
_, _ = p.Wait()
61+
reapChildren(t, parent)
8862
}
8963

9064
func TestNsenterInvalidPaths(t *testing.T) {
9165
args := []string{"nsenter-exec"}
92-
parent, child, err := newPipe()
93-
if err != nil {
94-
t.Fatalf("failed to create pipe %v", err)
95-
}
66+
parent, child := newPipe(t)
9667

9768
namespaces := []string{
98-
// join pid ns of the current process
9969
fmt.Sprintf("pid:/proc/%d/ns/pid", -1),
10070
}
10171
cmd := &exec.Cmd{
@@ -106,8 +76,10 @@ func TestNsenterInvalidPaths(t *testing.T) {
10676
}
10777

10878
if err := cmd.Start(); err != nil {
109-
t.Fatal(err)
79+
t.Fatalf("nsenter failed to start: %v", err)
11080
}
81+
child.Close()
82+
11183
// write cloneFlags
11284
r := nl.NewNetlinkRequest(int(libcontainer.InitMsg), 0)
11385
r.AddData(&libcontainer.Int32msg{
@@ -130,13 +102,9 @@ func TestNsenterInvalidPaths(t *testing.T) {
130102

131103
func TestNsenterIncorrectPathType(t *testing.T) {
132104
args := []string{"nsenter-exec"}
133-
parent, child, err := newPipe()
134-
if err != nil {
135-
t.Fatalf("failed to create pipe %v", err)
136-
}
105+
parent, child := newPipe(t)
137106

138107
namespaces := []string{
139-
// join pid ns of the current process
140108
fmt.Sprintf("net:/proc/%d/ns/pid", os.Getpid()),
141109
}
142110
cmd := &exec.Cmd{
@@ -147,8 +115,10 @@ func TestNsenterIncorrectPathType(t *testing.T) {
147115
}
148116

149117
if err := cmd.Start(); err != nil {
150-
t.Fatal(err)
118+
t.Fatalf("nsenter failed to start: %v", err)
151119
}
120+
child.Close()
121+
152122
// write cloneFlags
153123
r := nl.NewNetlinkRequest(int(libcontainer.InitMsg), 0)
154124
r.AddData(&libcontainer.Int32msg{
@@ -165,24 +135,14 @@ func TestNsenterIncorrectPathType(t *testing.T) {
165135

166136
initWaiter(t, parent)
167137
if err := cmd.Wait(); err == nil {
168-
t.Fatalf("nsenter exits with a zero exit status")
138+
t.Fatalf("nsenter error: %v", err)
169139
}
170140
}
171141

172142
func TestNsenterChildLogging(t *testing.T) {
173143
args := []string{"nsenter-exec"}
174-
parent, child, err := newPipe()
175-
if err != nil {
176-
t.Fatalf("failed to create exec pipe %v", err)
177-
}
178-
logread, logwrite, err := os.Pipe()
179-
if err != nil {
180-
t.Fatalf("failed to create log pipe %v", err)
181-
}
182-
defer func() {
183-
_ = logwrite.Close()
184-
_ = logread.Close()
185-
}()
144+
parent, child := newPipe(t)
145+
logread, logwrite := newPipe(t)
186146

187147
namespaces := []string{
188148
// join pid ns of the current process
@@ -198,8 +158,11 @@ func TestNsenterChildLogging(t *testing.T) {
198158
}
199159

200160
if err := cmd.Start(); err != nil {
201-
t.Fatalf("nsenter failed to start %v", err)
161+
t.Fatalf("nsenter failed to start: %v", err)
202162
}
163+
child.Close()
164+
logwrite.Close()
165+
203166
// write cloneFlags
204167
r := nl.NewNetlinkRequest(int(libcontainer.InitMsg), 0)
205168
r.AddData(&libcontainer.Int32msg{
@@ -216,20 +179,12 @@ func TestNsenterChildLogging(t *testing.T) {
216179

217180
initWaiter(t, parent)
218181

219-
logsDecoder := json.NewDecoder(logread)
220-
var logentry *logentry
221-
222-
err = logsDecoder.Decode(&logentry)
223-
if err != nil {
224-
t.Fatalf("child log: %v", err)
225-
}
226-
if logentry.Level == "" || logentry.Msg == "" {
227-
t.Fatalf("child log: empty log fields: level=\"%s\" msg=\"%s\"", logentry.Level, logentry.Msg)
228-
}
229-
182+
getLogs(t, logread)
230183
if err := cmd.Wait(); err != nil {
231-
t.Fatalf("nsenter exits with a non-zero exit status")
184+
t.Fatalf("nsenter error: %v", err)
232185
}
186+
187+
reapChildren(t, parent)
233188
}
234189

235190
func init() {
@@ -238,12 +193,19 @@ func init() {
238193
}
239194
}
240195

241-
func newPipe() (parent *os.File, child *os.File, err error) {
196+
func newPipe(t *testing.T) (parent *os.File, child *os.File) {
197+
t.Helper()
242198
fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM|unix.SOCK_CLOEXEC, 0)
243199
if err != nil {
244-
return nil, nil, err
200+
t.Fatal("socketpair failed:", err)
245201
}
246-
return os.NewFile(uintptr(fds[1]), "parent"), os.NewFile(uintptr(fds[0]), "child"), nil
202+
parent = os.NewFile(uintptr(fds[1]), "parent")
203+
child = os.NewFile(uintptr(fds[0]), "child")
204+
t.Cleanup(func() {
205+
parent.Close()
206+
child.Close()
207+
})
208+
return
247209
}
248210

249211
// initWaiter reads back the initial \0 from runc init
@@ -261,3 +223,47 @@ func initWaiter(t *testing.T, r io.Reader) {
261223
}
262224
t.Fatalf("waiting for init preliminary setup: %v", err)
263225
}
226+
227+
func reapChildren(t *testing.T, parent *os.File) {
228+
t.Helper()
229+
decoder := json.NewDecoder(parent)
230+
decoder.DisallowUnknownFields()
231+
var pid struct {
232+
Pid2 int `json:"stage2_pid"`
233+
Pid1 int `json:"stage1_pid"`
234+
}
235+
if err := decoder.Decode(&pid); err != nil {
236+
t.Fatal(err)
237+
}
238+
239+
// Reap children.
240+
_, _ = unix.Wait4(pid.Pid1, nil, 0, nil)
241+
_, _ = unix.Wait4(pid.Pid2, nil, 0, nil)
242+
243+
// Sanity check.
244+
if pid.Pid1 == 0 || pid.Pid2 == 0 {
245+
t.Fatal("got pids:", pid)
246+
}
247+
}
248+
249+
func getLogs(t *testing.T, logread *os.File) {
250+
logsDecoder := json.NewDecoder(logread)
251+
logsDecoder.DisallowUnknownFields()
252+
var logentry struct {
253+
Level string `json:"level"`
254+
Msg string `json:"msg"`
255+
}
256+
257+
for {
258+
if err := logsDecoder.Decode(&logentry); err != nil {
259+
if errors.Is(err, io.EOF) {
260+
return
261+
}
262+
t.Fatal("init log decoding error:", err)
263+
}
264+
t.Logf("logentry: %+v", logentry)
265+
if logentry.Level == "" || logentry.Msg == "" {
266+
t.Fatalf("init log: empty log entry: %+v", logentry)
267+
}
268+
}
269+
}

0 commit comments

Comments
 (0)