github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/sys/it/reverseproxy_test.go (about)

     1  /*
     2   * Copyright (c) 2021-present unTill Pro, Ltd.
     3   */
     4  
     5  package sys_it
     6  
     7  import (
     8  	"context"
     9  	"errors"
    10  	"io"
    11  	"net"
    12  	"net/http"
    13  	"sync"
    14  	"testing"
    15  
    16  	"github.com/stretchr/testify/require"
    17  
    18  	coreutils "github.com/voedger/voedger/pkg/utils"
    19  	it "github.com/voedger/voedger/pkg/vit"
    20  )
    21  
    22  func TestBasicUsage_ReverseProxy(t *testing.T) {
    23  	require := require.New(t)
    24  	vit := it.NewVIT(t, &it.SharedConfig_App1)
    25  	defer vit.TearDown()
    26  
    27  	targetListener, err := net.Listen("tcp", coreutils.ServerAddress(it.TestServicePort))
    28  	require.NoError(err)
    29  	errs := make(chan error)
    30  	targetHandler := targetHandler{t, &sync.Mutex{}, "", ""}
    31  	targetServer := http.Server{
    32  		Handler: &targetHandler,
    33  	}
    34  	go func() {
    35  		errs <- targetServer.Serve(targetListener)
    36  	}()
    37  
    38  	body := `world`
    39  
    40  	cases := map[string]string{
    41  		"grafana/foo":         "/grafana/foo",
    42  		"grafana/foo/bar/":    "/grafana/foo/bar/",
    43  		"grafana-rewrite/foo": "/rewritten/foo",
    44  		"unknown/foo":         "/not-found/unknown/foo",
    45  
    46  		// https://dev.untill.com/projects/#!627070
    47  		"api/untill/airs-bp//c.air.StoreSubscriptionProfile": "/not-found/api/untill/airs-bp//c.air.StoreSubscriptionProfile",
    48  	}
    49  
    50  	for srcURL, expectedURLPath := range cases {
    51  		targetHandler.setExpectedURLPath(expectedURLPath)
    52  
    53  		// resp := vit.PostFree(fmt.Sprintf("http://127.0.0.1:%s/%s", vit.IFederation.URL().Port(), srcURL), body)
    54  		resp := vit.POST(srcURL, body)
    55  		require.Equal(`hello world`, resp.Body) // guarantees that expectedURLPath is checked by the handler
    56  	}
    57  
    58  	t.Run("route domain", func(t *testing.T) {
    59  		targetHandler.setExpectedURLPath("/grafana/foo/")
    60  		targetHandler.setExpectedHost("127.0.0.1")
    61  		// resp := vit.PostFree(fmt.Sprintf("http://localhost:%s/grafana/foo/?Datadfsdfsdfsdfdf", vit.IFederation.URL().Port()), body)
    62  		resp := vit.POST("grafana/foo/?Datadfsdfsdfsdfdf", body)
    63  		require.Equal(`hello world`, resp.Body)
    64  	})
    65  
    66  	// stop everything
    67  	require.NoError(targetServer.Shutdown(context.Background()))
    68  	err = <-errs
    69  	if !errors.Is(err, http.ErrServerClosed) {
    70  		t.Fatal(err)
    71  	}
    72  	targetListener.Close()
    73  
    74  }
    75  
    76  type targetHandler struct {
    77  	t               *testing.T
    78  	lock            sync.Locker
    79  	expectedURLPath string
    80  	expectedHost    string
    81  }
    82  
    83  func (h *targetHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
    84  	rw.WriteHeader(http.StatusOK)
    85  	body, err := io.ReadAll(req.Body)
    86  	require.NoError(h.t, err)
    87  	req.Close = true
    88  	req.Body.Close()
    89  	if len(h.expectedHost) > 0 {
    90  		require.Contains(h.t, req.Host, h.expectedHost) // check localhost->127.0.0.1 translation by RouteDomains rule
    91  	}
    92  	require.Equal(h.t, h.getExpectedURLPath(), req.URL.Path)
    93  	require.Equal(h.t, http.MethodPost, req.Method, req.URL.Path)
    94  	_, err = rw.Write([]byte("hello " + string(body))) // test will be failed in case of any error
    95  	require.NoError(h.t, err)
    96  }
    97  
    98  func (h *targetHandler) setExpectedHost(expectedHost string) {
    99  	h.lock.Lock()
   100  	h.expectedHost = expectedHost
   101  	h.lock.Unlock()
   102  }
   103  
   104  func (h *targetHandler) setExpectedURLPath(expectedURLPath string) {
   105  	h.lock.Lock()
   106  	h.expectedURLPath = expectedURLPath
   107  	h.lock.Unlock()
   108  }
   109  func (h *targetHandler) getExpectedURLPath() string {
   110  	h.lock.Lock()
   111  	defer h.lock.Unlock()
   112  	return h.expectedURLPath
   113  }
   114  
   115  // func TestHTTPS(t *testing.T) {
   116  // 	testApp := setUp(t, withCmdLineArgs("--router-port", strconv.Itoa(router.HTTPSPort), "--router-http01-challenge-host", "rtrtyry"))
   117  // 	defer tearDown(testApp)
   118  
   119  // 	resp := postURL(t, fmt.Sprintf("https://localhost:%d/unknown", router.HTTPSPort), nil)
   120  // 	defer resp.Body.Close()
   121  
   122  // 	respBody := readOK(t, resp)
   123  // 	log.Println(string(respBody))
   124  // }