Fixed ws dial input error being dropped
This commit is contained in:
1 parent
02e3d910a2
commit
b714ee14d5
2 files changed
+38
-1
No files matched your search
@@ -321,14 +321,17 @@ func interact(
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
// Reading input can't be interrupted, so it has a goroutine of its own,
|
// Reading input can't be interrupted, so it has a goroutine of its own,
|
||||||
// left blocked if ctx is cancelled first.
|
// left blocked if ctx is cancelled first. Its error, if any, is sent
|
||||||
|
// before lines is closed.
|
||||||
lines := make(chan string)
|
lines := make(chan string)
|
||||||
|
inputErr := make(chan error, 1)
|
||||||
go func() {
|
go func() {
|
||||||
defer close(lines)
|
defer close(lines)
|
||||||
scanner := bufio.NewScanner(input)
|
scanner := bufio.NewScanner(input)
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
lines <- scanner.Text()
|
lines <- scanner.Text()
|
||||||
}
|
}
|
||||||
|
inputErr <- scanner.Err()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
@@ -339,6 +342,11 @@ func interact(
|
|||||||
return err
|
return err
|
||||||
case line, ok := <-lines:
|
case line, ok := <-lines:
|
||||||
if !ok {
|
if !ok {
|
||||||
|
err := <-inputErr
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("reading input: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
// The end of input: stop sending, keep listening.
|
// The end of input: stop sending, keep listening.
|
||||||
lines = nil
|
lines = nil
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package ws
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -281,6 +282,34 @@ func TestDialStdin(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Without --message, a failure reading stdin ends dial with an error, unlike
|
||||||
|
// the end of stdin.
|
||||||
|
func TestDialStdinError(t *testing.T) {
|
||||||
|
_, url := wsServer(t)
|
||||||
|
stdin, input := io.Pipe()
|
||||||
|
out := &syncBuffer{}
|
||||||
|
|
||||||
|
done := make(chan error, 1)
|
||||||
|
go func() {
|
||||||
|
done <- dial(context.Background(), stdin, out, dialSettings{
|
||||||
|
url: url,
|
||||||
|
timeout: time.Second,
|
||||||
|
})
|
||||||
|
}()
|
||||||
|
|
||||||
|
waitFor(t, out, `< {"type":"welcome"`)
|
||||||
|
input.CloseWithError(errors.New("disk on fire"))
|
||||||
|
|
||||||
|
select {
|
||||||
|
case err := <-done:
|
||||||
|
if err == nil || !strings.Contains(err.Error(), "reading input: disk on fire") {
|
||||||
|
t.Fatalf("dial = %v; want the input error", err)
|
||||||
|
}
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Fatal("dial did not return after the input error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Without --message, dial ends when the server closes the connection.
|
// Without --message, dial ends when the server closes the connection.
|
||||||
func TestDialStdinServerClose(t *testing.T) {
|
func TestDialStdinServerClose(t *testing.T) {
|
||||||
hub, url := wsServer(t)
|
hub, url := wsServer(t)
|
||||||
|
|||||||
Reference in new issue
Block a user