1// Copyright 2015 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// +build !plan9
6
7package ctxhttp
8
9import (
10	"io"
11	"io/ioutil"
12	"net/http"
13	"net/http/httptest"
14	"testing"
15	"time"
16
17	"golang.org/x/net/context"
18)
19
20const (
21	requestDuration = 100 * time.Millisecond
22	requestBody     = "ok"
23)
24
25func okHandler(w http.ResponseWriter, r *http.Request) {
26	time.Sleep(requestDuration)
27	io.WriteString(w, requestBody)
28}
29
30func TestNoTimeout(t *testing.T) {
31	ts := httptest.NewServer(http.HandlerFunc(okHandler))
32	defer ts.Close()
33
34	ctx := context.Background()
35	res, err := Get(ctx, nil, ts.URL)
36	if err != nil {
37		t.Fatal(err)
38	}
39	defer res.Body.Close()
40	slurp, err := ioutil.ReadAll(res.Body)
41	if err != nil {
42		t.Fatal(err)
43	}
44	if string(slurp) != requestBody {
45		t.Errorf("body = %q; want %q", slurp, requestBody)
46	}
47}
48
49func TestCancelBeforeHeaders(t *testing.T) {
50	ctx, cancel := context.WithCancel(context.Background())
51
52	blockServer := make(chan struct{})
53	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
54		cancel()
55		<-blockServer
56		io.WriteString(w, requestBody)
57	}))
58	defer ts.Close()
59	defer close(blockServer)
60
61	res, err := Get(ctx, nil, ts.URL)
62	if err == nil {
63		res.Body.Close()
64		t.Fatal("Get returned unexpected nil error")
65	}
66	if err != context.Canceled {
67		t.Errorf("err = %v; want %v", err, context.Canceled)
68	}
69}
70
71func TestCancelAfterHangingRequest(t *testing.T) {
72	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
73		w.WriteHeader(http.StatusOK)
74		w.(http.Flusher).Flush()
75		<-w.(http.CloseNotifier).CloseNotify()
76	}))
77	defer ts.Close()
78
79	ctx, cancel := context.WithCancel(context.Background())
80	resp, err := Get(ctx, nil, ts.URL)
81	if err != nil {
82		t.Fatalf("unexpected error in Get: %v", err)
83	}
84
85	// Cancel befer reading the body.
86	// Reading Request.Body should fail, since the request was
87	// canceled before anything was written.
88	cancel()
89
90	done := make(chan struct{})
91
92	go func() {
93		b, err := ioutil.ReadAll(resp.Body)
94		if len(b) != 0 || err == nil {
95			t.Errorf(`Read got (%q, %v); want ("", error)`, b, err)
96		}
97		close(done)
98	}()
99
100	select {
101	case <-time.After(1 * time.Second):
102		t.Errorf("Test timed out")
103	case <-done:
104	}
105}
106