blob: 0aa217f5862d313d9b73d623d4f5e1f2b1cc6aa6 [file] [log] [blame]
John Boiles57852792018-01-05 14:37:05 -08001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20package common
21
22import (
23 "context"
24 "fmt"
25 "net"
26 "net/http"
27 "net/url"
28 "os"
29 "syscall"
30 "testing"
John Boiles57852792018-01-05 14:37:05 -080031 "time"
Yuxuan 'fishy' Wangb71f11e2021-03-22 15:01:00 -070032
33 "github.com/apache/thrift/lib/go/thrift"
John Boiles57852792018-01-05 14:37:05 -080034)
35
36type slowHttpHandler struct{}
37
38func (slowHttpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
39 time.Sleep(1 * time.Second)
40}
41
42func TestHttpContextTimeout(t *testing.T) {
Yuxuan 'fishy' Wang91565d42024-08-14 09:01:15 -070043 const (
44 host = "127.0.0.1"
45 port = 9096
46 )
47 addr := fmt.Sprintf("%s:%d", host, port)
48 unit := test_unit{host, port, "", "http", "binary", false}
John Boiles57852792018-01-05 14:37:05 -080049
Yuxuan 'fishy' Wang91565d42024-08-14 09:01:15 -070050 server := &http.Server{Addr: addr, Handler: slowHttpHandler{}}
John Boiles57852792018-01-05 14:37:05 -080051 go server.ListenAndServe()
52
Yuxuan 'fishy' Wang91565d42024-08-14 09:01:15 -070053 client, trans, err := StartClient(addr, unit.transport, unit.protocol, unit.ssl)
John Boiles57852792018-01-05 14:37:05 -080054 if err != nil {
55 t.Errorf("Unable to start client: %v", err)
56 return
57 }
58 defer trans.Close()
59
60 unwrapErr := func(err error) error {
61 for {
Yuxuan 'fishy' Wang17373a32021-08-26 11:04:27 -070062 //lint:ignore S1034 type switch is more appropriate here.
John Boiles57852792018-01-05 14:37:05 -080063 switch err.(type) {
64 case thrift.TTransportException:
65 err = err.(thrift.TTransportException).Err()
66 case *url.Error:
67 err = err.(*url.Error).Err
68 case *net.OpError:
69 err = err.(*net.OpError).Err
70 case *os.SyscallError:
71 err = err.(*os.SyscallError).Err
72 default:
73 return err
74 }
75 }
76 }
77
78 serverStartupDeadline := time.Now().Add(5 * time.Second)
79 for {
80 ctx, _ := context.WithTimeout(context.Background(), 50*time.Millisecond)
81 err = client.TestVoid(ctx)
82 err = unwrapErr(err)
83 if err != syscall.ECONNREFUSED || time.Now().After(serverStartupDeadline) {
84 break
85 }
86 time.Sleep(time.Millisecond)
87 }
88
89 if err == nil {
90 t.Errorf("Request completed (should have timed out)")
91 return
92 }
93
94 // We've got to switch on `err.Error()` here since go1.7 doesn't properly return
95 // `context.DeadlineExceeded` error and `http.errRequestCanceled` is not exported.
96 // See https://github.com/golang/go/issues/17711
97 switch err.Error() {
98 case context.DeadlineExceeded.Error(), "net/http: request canceled":
99 // Expected error
100 default:
101 t.Errorf("Unexpected error: %s", err)
102 }
103}