Skip to content

Commit 5761e66

Browse files
authored
Merge pull request #5326 from vvoland/5303-27.x
[27.x backport] tests/run: fix flaky `RunAttachTermination` test
2 parents a35c363 + c7f3031 commit 5761e66

File tree

1 file changed

+103
-14
lines changed

1 file changed

+103
-14
lines changed

cli/command/container/run_test.go

+103-14
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"errors"
66
"io"
77
"net"
8-
"os/signal"
98
"syscall"
109
"testing"
1110
"time"
@@ -38,15 +37,85 @@ func TestRunLabel(t *testing.T) {
3837
assert.NilError(t, cmd.Execute())
3938
}
4039

41-
func TestRunAttachTermination(t *testing.T) {
40+
func TestRunAttach(t *testing.T) {
4241
p, tty, err := pty.Open()
4342
assert.NilError(t, err)
43+
defer func() {
44+
_ = tty.Close()
45+
_ = p.Close()
46+
}()
47+
48+
var conn net.Conn
49+
attachCh := make(chan struct{})
50+
fakeCLI := test.NewFakeCli(&fakeClient{
51+
createContainerFunc: func(_ *container.Config, _ *container.HostConfig, _ *network.NetworkingConfig, _ *specs.Platform, _ string) (container.CreateResponse, error) {
52+
return container.CreateResponse{
53+
ID: "id",
54+
}, nil
55+
},
56+
containerAttachFunc: func(ctx context.Context, containerID string, options container.AttachOptions) (types.HijackedResponse, error) {
57+
server, client := net.Pipe()
58+
conn = server
59+
t.Cleanup(func() {
60+
_ = server.Close()
61+
})
62+
attachCh <- struct{}{}
63+
return types.NewHijackedResponse(client, types.MediaTypeRawStream), nil
64+
},
65+
waitFunc: func(_ string) (<-chan container.WaitResponse, <-chan error) {
66+
responseChan := make(chan container.WaitResponse, 1)
67+
errChan := make(chan error)
68+
69+
responseChan <- container.WaitResponse{
70+
StatusCode: 33,
71+
}
72+
return responseChan, errChan
73+
},
74+
// use new (non-legacy) wait API
75+
// see: 38591f20d07795aaef45d400df89ca12f29c603b
76+
Version: "1.30",
77+
}, func(fc *test.FakeCli) {
78+
fc.SetOut(streams.NewOut(tty))
79+
fc.SetIn(streams.NewIn(tty))
80+
})
81+
82+
cmd := NewRunCommand(fakeCLI)
83+
cmd.SetArgs([]string{"-it", "busybox"})
84+
cmd.SilenceUsage = true
85+
cmdErrC := make(chan error, 1)
86+
go func() {
87+
cmdErrC <- cmd.Execute()
88+
}()
89+
90+
// run command should attempt to attach to the container
91+
select {
92+
case <-time.After(5 * time.Second):
93+
t.Fatal("containerAttachFunc was not called before the 5 second timeout")
94+
case <-attachCh:
95+
}
96+
97+
// end stream from "container" so that we'll detach
98+
conn.Close()
99+
100+
select {
101+
case cmdErr := <-cmdErrC:
102+
assert.Equal(t, cmdErr, cli.StatusError{
103+
StatusCode: 33,
104+
})
105+
case <-time.After(2 * time.Second):
106+
t.Fatal("cmd did not return within timeout")
107+
}
108+
}
44109

110+
func TestRunAttachTermination(t *testing.T) {
111+
p, tty, err := pty.Open()
112+
assert.NilError(t, err)
45113
defer func() {
46114
_ = tty.Close()
47115
_ = p.Close()
48116
}()
49117

118+
var conn net.Conn
50119
killCh := make(chan struct{})
51120
attachCh := make(chan struct{})
52121
fakeCLI := test.NewFakeCli(&fakeClient{
@@ -61,42 +130,62 @@ func TestRunAttachTermination(t *testing.T) {
61130
},
62131
containerAttachFunc: func(ctx context.Context, containerID string, options container.AttachOptions) (types.HijackedResponse, error) {
63132
server, client := net.Pipe()
133+
conn = server
64134
t.Cleanup(func() {
65135
_ = server.Close()
66136
})
67137
attachCh <- struct{}{}
68138
return types.NewHijackedResponse(client, types.MediaTypeRawStream), nil
69139
},
70-
Version: "1.36",
140+
waitFunc: func(_ string) (<-chan container.WaitResponse, <-chan error) {
141+
responseChan := make(chan container.WaitResponse, 1)
142+
errChan := make(chan error)
143+
144+
responseChan <- container.WaitResponse{
145+
StatusCode: 130,
146+
}
147+
return responseChan, errChan
148+
},
149+
// use new (non-legacy) wait API
150+
// see: 38591f20d07795aaef45d400df89ca12f29c603b
151+
Version: "1.30",
71152
}, func(fc *test.FakeCli) {
72153
fc.SetOut(streams.NewOut(tty))
73154
fc.SetIn(streams.NewIn(tty))
74155
})
75-
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGTERM)
76-
defer cancel()
77-
78-
assert.Equal(t, fakeCLI.In().IsTerminal(), true)
79-
assert.Equal(t, fakeCLI.Out().IsTerminal(), true)
80156

81157
cmd := NewRunCommand(fakeCLI)
82158
cmd.SetArgs([]string{"-it", "busybox"})
83159
cmd.SilenceUsage = true
160+
cmdErrC := make(chan error, 1)
84161
go func() {
85-
assert.ErrorIs(t, cmd.ExecuteContext(ctx), context.Canceled)
162+
cmdErrC <- cmd.Execute()
86163
}()
87164

165+
// run command should attempt to attach to the container
88166
select {
89167
case <-time.After(5 * time.Second):
90-
t.Fatal("containerAttachFunc was not called before the 5 second timeout")
168+
t.Fatal("containerAttachFunc was not called before the timeout")
91169
case <-attachCh:
92170
}
93171

94-
assert.NilError(t, syscall.Kill(syscall.Getpid(), syscall.SIGTERM))
172+
assert.NilError(t, syscall.Kill(syscall.Getpid(), syscall.SIGINT))
173+
// end stream from "container" so that we'll detach
174+
conn.Close()
175+
95176
select {
96-
case <-time.After(5 * time.Second):
97-
cancel()
98-
t.Fatal("containerKillFunc was not called before the 5 second timeout")
99177
case <-killCh:
178+
case <-time.After(5 * time.Second):
179+
t.Fatal("containerKillFunc was not called before the timeout")
180+
}
181+
182+
select {
183+
case cmdErr := <-cmdErrC:
184+
assert.Equal(t, cmdErr, cli.StatusError{
185+
StatusCode: 130,
186+
})
187+
case <-time.After(2 * time.Second):
188+
t.Fatal("cmd did not return before the timeout")
100189
}
101190
}
102191

0 commit comments

Comments
 (0)