Browse Source

client: return original ctx error

Fix https://github.com/coreos/etcd/issues/3209.
Gyu-Ho Lee 9 years ago
parent
commit
8d0d10cce5
2 changed files with 49 additions and 3 deletions
  1. 3 1
      client/client.go
  2. 46 2
      client/client_test.go

+ 3 - 1
client/client.go

@@ -342,7 +342,9 @@ func (c *httpClusterClient) Do(ctx context.Context, act httpAction) (*http.Respo
 		resp, body, err = hc.Do(ctx, action)
 		resp, body, err = hc.Do(ctx, action)
 		if err != nil {
 		if err != nil {
 			cerr.Errors = append(cerr.Errors, err)
 			cerr.Errors = append(cerr.Errors, err)
-			// mask previous errors with context error, which is controlled by user
+			if err == ctx.Err() {
+				return nil, nil, ctx.Err()
+			}
 			if err == context.Canceled || err == context.DeadlineExceeded {
 			if err == context.Canceled || err == context.DeadlineExceeded {
 				return nil, nil, err
 				return nil, nil, err
 			}
 			}

+ 46 - 2
client/client_test.go

@@ -295,7 +295,7 @@ func TestSimpleHTTPClientDoHeaderTimeout(t *testing.T) {
 			t.Fatalf("expected non-nil error, got nil")
 			t.Fatalf("expected non-nil error, got nil")
 		}
 		}
 	case <-time.After(time.Second):
 	case <-time.After(time.Second):
-		t.Fatalf("unexpected timeout when waitting for the test to finish")
+		t.Fatalf("unexpected timeout when waiting for the test to finish")
 	}
 	}
 }
 }
 
 
@@ -444,7 +444,51 @@ func TestHTTPClusterClientDoDeadlineExceedContext(t *testing.T) {
 			t.Errorf("err = %+v, want %+v", err, context.DeadlineExceeded)
 			t.Errorf("err = %+v, want %+v", err, context.DeadlineExceeded)
 		}
 		}
 	case <-time.After(time.Second):
 	case <-time.After(time.Second):
-		t.Fatalf("unexpected timeout when waitting for request to deadline exceed")
+		t.Fatalf("unexpected timeout when waiting for request to deadline exceed")
+	}
+}
+
+type fakeCancelContext struct{}
+
+var fakeCancelContextError = errors.New("fake context canceled")
+
+func (f fakeCancelContext) Deadline() (time.Time, bool) { return time.Time{}, false }
+func (f fakeCancelContext) Done() <-chan struct{} {
+	d := make(chan struct{}, 1)
+	d <- struct{}{}
+	return d
+}
+func (f fakeCancelContext) Err() error                        { return fakeCancelContextError }
+func (f fakeCancelContext) Value(key interface{}) interface{} { return 1 }
+
+func withTimeout(parent context.Context, timeout time.Duration) (context.Context, context.CancelFunc) {
+	return parent, func() { parent = nil }
+}
+
+func TestHTTPClusterClientDoCanceledContext(t *testing.T) {
+	fakeURL := url.URL{}
+	tr := newFakeTransport()
+	tr.finishCancel <- struct{}{}
+	c := &httpClusterClient{
+		clientFactory: newHTTPClientFactory(tr, DefaultCheckRedirect, 0),
+		endpoints:     []url.URL{fakeURL},
+	}
+
+	errc := make(chan error)
+	go func() {
+		ctx, cancel := withTimeout(fakeCancelContext{}, time.Millisecond)
+		cancel()
+		_, _, err := c.Do(ctx, &fakeAction{})
+		errc <- err
+	}()
+
+	select {
+	case err := <-errc:
+		if err != fakeCancelContextError {
+			t.Errorf("err = %+v, want %+v", err, fakeCancelContextError)
+		}
+	case <-time.After(time.Second):
+		t.Fatalf("unexpected timeout when waiting for request to fake context canceled")
 	}
 	}
 }
 }