trpc.group/trpc-go/trpc-go@v1.0.3/admin/router_test.go (about)

     1  //
     2  //
     3  // Tencent is pleased to support the open source community by making tRPC available.
     4  //
     5  // Copyright (C) 2023 THL A29 Limited, a Tencent company.
     6  // All rights reserved.
     7  //
     8  // If you have downloaded a copy of the tRPC source code from Tencent,
     9  // please note that tRPC source code is licensed under the  Apache 2.0 License,
    10  // A copy of the Apache 2.0 License is included in this file.
    11  //
    12  //
    13  
    14  package admin
    15  
    16  import (
    17  	"fmt"
    18  	"io"
    19  	"net"
    20  	"net/http"
    21  	"reflect"
    22  	"runtime"
    23  	"testing"
    24  	"time"
    25  
    26  	"github.com/stretchr/testify/require"
    27  )
    28  
    29  func TestRouter(t *testing.T) {
    30  	// Given a router
    31  	r := newRouter()
    32  
    33  	// And config its handler function with pattern "/index" and Desc "index page"
    34  	r.add("/index", func(w http.ResponseWriter, r *http.Request) {
    35  		w.Write([]byte(r.URL.Path))
    36  	})
    37  
    38  	// When List current handlers that have already registered from the router
    39  	handlers := r.list()
    40  
    41  	// Then the handlers should contain only the single handler function previously registered
    42  	require.Len(t, handlers, 1)
    43  	require.Equal(t, "/index", handlers[0].pattern)
    44  
    45  	// When config a testHandler with pattern "/test1", and try to find the new handler from the router
    46  	testHandler := func(w http.ResponseWriter, r *http.Request) {}
    47  	r.add("/test", testHandler)
    48  	var handler *routerHandler
    49  	for _, h := range r.list() {
    50  		if h.pattern == "/test" {
    51  			handler = h
    52  			break
    53  		}
    54  	}
    55  
    56  	// Then the handler found should be the testHandler
    57  	require.Equal(t,
    58  		runtime.FuncForPC(reflect.ValueOf(testHandler).Pointer()).Name(),
    59  		runtime.FuncForPC(reflect.ValueOf(handler.handler).Pointer()).Name(),
    60  	)
    61  
    62  	// When start a http server with the router, and send a http GET request to access index page
    63  	addr := mustListenAndServe(t, r)
    64  	resp, err := http.Get(fmt.Sprintf("http://%v%s", addr, "/index"))
    65  	require.Nil(t, err)
    66  	body, err := io.ReadAll(resp.Body)
    67  	resp.Body.Close()
    68  
    69  	// Then response body should be "/index"
    70  	require.Nil(t, err)
    71  	require.Equal(t, "/index", string(body))
    72  
    73  	// When send a http GET request to access nonexistent resource
    74  	resp, err = http.Get(fmt.Sprintf("http://%v%s", addr, "/nonexistent-resource"))
    75  	require.Nil(t, err)
    76  	body, err = io.ReadAll(resp.Body)
    77  	resp.Body.Close()
    78  
    79  	// Then the response body should contain 404 error message
    80  	require.Nil(t, err)
    81  	require.Equal(t, "404 page not found\n", string(body))
    82  }
    83  
    84  func TestRouter_ServeHTTP(t *testing.T) {
    85  	t.Run("panic but recovered", func(t *testing.T) {
    86  		// Given a router
    87  		r := newRouter()
    88  
    89  		// And config its handler function that always panic with pattern "/index"
    90  		const panicMessage = "there must be something wrong with your code"
    91  		r.add("/index", func(w http.ResponseWriter, r *http.Request) {
    92  			panic(panicMessage)
    93  		})
    94  
    95  		// When start a http server with the router, and send a http GET request to access index page
    96  		addr := mustListenAndServe(t, r)
    97  		resp, err := http.Get(fmt.Sprintf("http://%v%s", addr, "/index"))
    98  		require.Nil(t, err)
    99  		require.Nil(t, err)
   100  		body, err := io.ReadAll(resp.Body)
   101  		resp.Body.Close()
   102  
   103  		// Then response body should contain panic message
   104  		require.Nil(t, err)
   105  		require.Contains(t, string(body), "PANIC : "+panicMessage)
   106  	})
   107  }
   108  
   109  func mustListenAndServe(t *testing.T, r *router) net.Addr {
   110  	l, err := net.Listen("tcp", testAddress)
   111  	if err != nil {
   112  		t.Fatal(err)
   113  	}
   114  	go func() {
   115  		if http.Serve(l, r); err != nil && err != http.ErrServerClosed {
   116  			t.Log(err)
   117  		}
   118  	}()
   119  	time.Sleep(time.Second)
   120  	return l.Addr()
   121  }