Thanks to visit codestin.com
Credit goes to github.com

Skip to content

fix: Make TestAgent and TestWorkspaceAgentPTY less flaky #1562

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 20 additions & 7 deletions agent/agent_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package agent_test

import (
"bufio"
"context"
"encoding/json"
"fmt"
Expand Down Expand Up @@ -204,6 +205,11 @@ func TestAgent(t *testing.T) {
id := uuid.NewString()
netConn, err := conn.ReconnectingPTY(id, 100, 100)
require.NoError(t, err)
bufRead := bufio.NewReader(netConn)

// Brief pause to reduce the likelihood that we send keystrokes while
// the shell is simultaneously sending a prompt.
time.Sleep(100 * time.Millisecond)
Comment on lines +210 to +212
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should properly be buffered on the server-side, were you seeing it differently?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's a problem with the server, just an inherent race. The actual issue I was seeing was that the test was sending the command before it received the prompt, which means the command text actually got echoed twice. This is because after bash prints the prompt, it helpfully re-echoes anything that was pending in the input buffer, in order to make line editing work properly.

For instance, if you type sleep 10<ENTER>echo foo<ENTER> quickly, you get output on your terminal that looks like:

$ sleep 10
echo foo
$ echo foo
foo

It would certainly be cleaner to wait for the prompt and then send the input, but I'm not sure that we can easily/portably do that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh I see. Makes sense!


data, err := json.Marshal(agent.ReconnectingPTYRequest{
Data: "echo test\r\n",
Expand All @@ -212,28 +218,35 @@ func TestAgent(t *testing.T) {
_, err = netConn.Write(data)
require.NoError(t, err)

findEcho := func() {
expectLine := func(matcher func(string) bool) {
for {
read, err := netConn.Read(data)
line, err := bufRead.ReadString('\n')
require.NoError(t, err)
if strings.Contains(string(data[:read]), "test") {
if matcher(line) {
break
}
}
}
matchEchoCommand := func(line string) bool {
return strings.Contains(line, "echo test")
}
matchEchoOutput := func(line string) bool {
return strings.Contains(line, "test") && !strings.Contains(line, "echo")
}

// Once for typing the command...
findEcho()
expectLine(matchEchoCommand)
// And another time for the actual output.
findEcho()
expectLine(matchEchoOutput)

_ = netConn.Close()
netConn, err = conn.ReconnectingPTY(id, 100, 100)
require.NoError(t, err)
bufRead = bufio.NewReader(netConn)

// Same output again!
findEcho()
findEcho()
expectLine(matchEchoCommand)
expectLine(matchEchoOutput)
})

t.Run("Dial", func(t *testing.T) {
Expand Down
25 changes: 19 additions & 6 deletions coderd/workspaceagents_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package coderd_test

import (
"bufio"
"context"
"encoding/json"
"runtime"
"strings"
"testing"
"time"

"github.com/google/uuid"
"github.com/pion/webrtc/v3"
Expand Down Expand Up @@ -230,6 +232,11 @@ func TestWorkspaceAgentPTY(t *testing.T) {
require.NoError(t, err)
_, err = conn.Write(data)
require.NoError(t, err)
bufRead := bufio.NewReader(conn)

// Brief pause to reduce the likelihood that we send keystrokes while
// the shell is simultaneously sending a prompt.
time.Sleep(100 * time.Millisecond)

data, err = json.Marshal(agent.ReconnectingPTYRequest{
Data: "echo test\r\n",
Expand All @@ -238,16 +245,22 @@ func TestWorkspaceAgentPTY(t *testing.T) {
_, err = conn.Write(data)
require.NoError(t, err)

findEcho := func() {
expectLine := func(matcher func(string) bool) {
for {
read, err := conn.Read(data)
line, err := bufRead.ReadString('\n')
require.NoError(t, err)
if strings.Contains(string(data[:read]), "test") {
return
if matcher(line) {
break
}
}
}
matchEchoCommand := func(line string) bool {
return strings.Contains(line, "echo test")
}
matchEchoOutput := func(line string) bool {
return strings.Contains(line, "test") && !strings.Contains(line, "echo")
}

findEcho()
findEcho()
expectLine(matchEchoCommand)
expectLine(matchEchoOutput)
}