github.com/pingcap/failpoint@v0.0.0-20240412033321-fd0796e60f86/http_test.go (about)

     1  // Copyright 2021 PingCAP, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package failpoint_test
    16  
    17  import (
    18  	"errors"
    19  	"io/ioutil"
    20  	"net/http"
    21  	"net/http/httptest"
    22  	"strings"
    23  	"testing"
    24  
    25  	"github.com/pingcap/failpoint"
    26  	"github.com/stretchr/testify/require"
    27  )
    28  
    29  type badReader struct{}
    30  
    31  func (badReader) Read([]byte) (int, error) {
    32  	return 0, errors.New("mock bad read")
    33  }
    34  
    35  func TestServeHTTP(t *testing.T) {
    36  	require.NoError(t, failpoint.Serve(":23389"))
    37  
    38  	handler := &failpoint.HttpHandler{}
    39  
    40  	// PUT
    41  	req, err := http.NewRequest(http.MethodPut, "http://127.0.0.1/failpoint-name", strings.NewReader("return(1)"))
    42  	require.NoError(t, err)
    43  	res := httptest.NewRecorder()
    44  	handler.ServeHTTP(res, req)
    45  	require.Equal(t, http.StatusNoContent, res.Code)
    46  
    47  	req, err = http.NewRequest(http.MethodPut, "http://127.0.0.1", strings.NewReader("return(1)"))
    48  	require.NoError(t, err)
    49  	res = httptest.NewRecorder()
    50  	handler.ServeHTTP(res, req)
    51  	require.Equal(t, http.StatusBadRequest, res.Code)
    52  	require.Contains(t, res.Body.String(), "malformed request URI")
    53  
    54  	req, err = http.NewRequest(http.MethodPut, "http://127.0.0.1/failpoint-name", badReader{})
    55  	require.NoError(t, err)
    56  	res = httptest.NewRecorder()
    57  	handler.ServeHTTP(res, req)
    58  	require.Equal(t, http.StatusBadRequest, res.Code)
    59  	require.Contains(t, res.Body.String(), "failed ReadAll in PUT")
    60  
    61  	req, err = http.NewRequest(http.MethodPut, "http://127.0.0.1/failpoint-name", strings.NewReader("invalid"))
    62  	require.NoError(t, err)
    63  	res = httptest.NewRecorder()
    64  	handler.ServeHTTP(res, req)
    65  	require.Equal(t, http.StatusBadRequest, res.Code)
    66  	require.Contains(t, res.Body.String(), "failed to set failpoint")
    67  
    68  	// GET
    69  	req, err = http.NewRequest(http.MethodGet, "http://127.0.0.1/failpoint-name", strings.NewReader(""))
    70  	require.NoError(t, err)
    71  	res = httptest.NewRecorder()
    72  	handler.ServeHTTP(res, req)
    73  	require.Equal(t, http.StatusOK, res.Code)
    74  	require.Contains(t, res.Body.String(), "return(1)")
    75  
    76  	req, err = http.NewRequest(http.MethodGet, "http://127.0.0.1/failpoint-name-not-exists", strings.NewReader(""))
    77  	require.NoError(t, err)
    78  	res = httptest.NewRecorder()
    79  	handler.ServeHTTP(res, req)
    80  	require.Equal(t, http.StatusNotFound, res.Code)
    81  	require.Contains(t, res.Body.String(), "failed to GET")
    82  
    83  	req, err = http.NewRequest(http.MethodGet, "http://127.0.0.1/", strings.NewReader(""))
    84  	require.NoError(t, err)
    85  	res = httptest.NewRecorder()
    86  	handler.ServeHTTP(res, req)
    87  	require.Equal(t, http.StatusOK, res.Code)
    88  	require.Contains(t, res.Body.String(), "failpoint-name=return(1)")
    89  
    90  	// DELETE
    91  	req, err = http.NewRequest(http.MethodDelete, "http://127.0.0.1/failpoint-name", strings.NewReader(""))
    92  	require.NoError(t, err)
    93  	res = httptest.NewRecorder()
    94  	handler.ServeHTTP(res, req)
    95  	require.Equal(t, http.StatusNoContent, res.Code)
    96  
    97  	req, err = http.NewRequest(http.MethodDelete, "http://127.0.0.1/failpoint-name-not-exists", strings.NewReader(""))
    98  	require.NoError(t, err)
    99  	res = httptest.NewRecorder()
   100  	handler.ServeHTTP(res, req)
   101  	require.Equal(t, http.StatusBadRequest, res.Code)
   102  	require.Contains(t, res.Body.String(), "failed to delete failpoint")
   103  
   104  	// DEFAULT
   105  	req, err = http.NewRequest(http.MethodPost, "http://127.0.0.1/failpoint-name", strings.NewReader(""))
   106  	require.NoError(t, err)
   107  	res = httptest.NewRecorder()
   108  	handler.ServeHTTP(res, req)
   109  	require.Equal(t, http.StatusMethodNotAllowed, res.Code)
   110  	require.Contains(t, res.Body.String(), "Method not allowed")
   111  
   112  	// Test environment variable injection
   113  	resp, err := http.Get("http://127.0.0.1:23389/failpoint-env1")
   114  	require.NoError(t, err)
   115  	require.Equal(t, http.StatusOK, resp.StatusCode)
   116  	body, err := ioutil.ReadAll(resp.Body)
   117  	require.NoError(t, err)
   118  	require.Contains(t, string(body), "return(10)")
   119  
   120  	resp, err = http.Get("http://127.0.0.1:23389/failpoint-env2")
   121  	require.NoError(t, err)
   122  	require.Equal(t, http.StatusOK, resp.StatusCode)
   123  	body, err = ioutil.ReadAll(resp.Body)
   124  	require.NoError(t, err)
   125  	require.Contains(t, string(body), "return(true)")
   126  }