소스 검색

Ensure that non-JSON-parsing errors are returned to the caller

Signed-off-by: Stefan Gehrig <stefan.gehrig.hn@googlemail.com>
Co-authored-by: Cory Snider <corhere@gmail.com>
Stefan Gehrig 1 년 전
부모
커밋
0d27579fc7
2개의 변경된 파일49개의 추가작업 그리고 2개의 파일을 삭제
  1. 6 2
      client/container_wait.go
  2. 43 0
      client/container_wait_test.go

+ 6 - 2
client/container_wait.go

@@ -72,8 +72,12 @@ func (cli *Client) ContainerWait(ctx context.Context, containerID string, condit
 			//
 			// If there's a JSON parsing error, read the real error message
 			// off the body and send it to the client.
-			_, _ = io.ReadAll(io.LimitReader(stream, containerWaitErrorMsgLimit))
-			errC <- errors.New(responseText.String())
+			if errors.As(err, new(*json.SyntaxError)) {
+				_, _ = io.ReadAll(io.LimitReader(stream, containerWaitErrorMsgLimit))
+				errC <- errors.New(responseText.String())
+			} else {
+				errC <- err
+			}
 			return
 		}
 

+ 43 - 0
client/container_wait_test.go

@@ -9,11 +9,14 @@ import (
 	"log"
 	"net/http"
 	"strings"
+	"syscall"
 	"testing"
+	"testing/iotest"
 	"time"
 
 	"github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/errdefs"
+	"github.com/pkg/errors"
 	"gotest.tools/v3/assert"
 	is "gotest.tools/v3/assert/cmp"
 )
@@ -117,6 +120,46 @@ func TestContainerWaitProxyInterruptLong(t *testing.T) {
 	}
 }
 
+func TestContainerWaitErrorHandling(t *testing.T) {
+	for _, test := range []struct {
+		name string
+		rdr  io.Reader
+		exp  error
+	}{
+		{name: "invalid json", rdr: strings.NewReader(`{]`), exp: errors.New("{]")},
+		{name: "context canceled", rdr: iotest.ErrReader(context.Canceled), exp: context.Canceled},
+		{name: "context deadline exceeded", rdr: iotest.ErrReader(context.DeadlineExceeded), exp: context.DeadlineExceeded},
+		{name: "connection reset", rdr: iotest.ErrReader(syscall.ECONNRESET), exp: syscall.ECONNRESET},
+	} {
+		t.Run(test.name, func(t *testing.T) {
+			ctx, cancel := context.WithCancel(context.Background())
+			defer cancel()
+
+			client := &Client{
+				version: "1.30",
+				client: newMockClient(func(req *http.Request) (*http.Response, error) {
+					return &http.Response{
+						StatusCode: http.StatusOK,
+						Body:       io.NopCloser(test.rdr),
+					}, nil
+				}),
+			}
+			resultC, errC := client.ContainerWait(ctx, "container_id", "")
+			select {
+			case err := <-errC:
+				if err.Error() != test.exp.Error() {
+					t.Fatalf("ContainerWait() errC = %v; want %v", err, test.exp)
+				}
+				return
+			case result := <-resultC:
+				t.Fatalf("expected to not get a wait result, got %d", result.StatusCode)
+				return
+			}
+			// Unexpected - we should not reach this line
+		})
+	}
+}
+
 func ExampleClient_ContainerWait_withTimeout() {
 	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
 	defer cancel()