github.com/weaveworks/common@v0.0.0-20230728070032-dd9e68f319d5/server/server_test.go (about)

     1  package server
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/tls"
     6  	"crypto/x509"
     7  	"errors"
     8  	"flag"
     9  	"io"
    10  	"net/http"
    11  	"os"
    12  	"os/exec"
    13  	"strconv"
    14  	"testing"
    15  	"time"
    16  
    17  	"github.com/prometheus/client_golang/prometheus/testutil"
    18  	"google.golang.org/grpc"
    19  	"google.golang.org/grpc/credentials"
    20  	"google.golang.org/grpc/credentials/insecure"
    21  	"google.golang.org/grpc/status"
    22  
    23  	protobuf "github.com/golang/protobuf/ptypes/empty"
    24  	"github.com/gorilla/mux"
    25  	"github.com/prometheus/client_golang/prometheus"
    26  	"github.com/stretchr/testify/require"
    27  	"github.com/weaveworks/common/httpgrpc"
    28  	"github.com/weaveworks/common/logging"
    29  	"github.com/weaveworks/common/middleware"
    30  	"golang.org/x/net/context"
    31  )
    32  
    33  type FakeServer struct{}
    34  
    35  func (f FakeServer) FailWithError(_ context.Context, _ *protobuf.Empty) (*protobuf.Empty, error) {
    36  	return nil, errors.New("test error")
    37  }
    38  
    39  func (f FakeServer) FailWithHTTPError(_ context.Context, req *FailWithHTTPErrorRequest) (*protobuf.Empty, error) {
    40  	return nil, httpgrpc.Errorf(int(req.Code), strconv.Itoa(int(req.Code)))
    41  }
    42  
    43  func (f FakeServer) Succeed(_ context.Context, _ *protobuf.Empty) (*protobuf.Empty, error) {
    44  	return &protobuf.Empty{}, nil
    45  }
    46  
    47  func (f FakeServer) Sleep(ctx context.Context, _ *protobuf.Empty) (*protobuf.Empty, error) {
    48  	err := cancelableSleep(ctx, 10*time.Second)
    49  	return &protobuf.Empty{}, err
    50  }
    51  
    52  func (f FakeServer) StreamSleep(_ *protobuf.Empty, stream FakeServer_StreamSleepServer) error {
    53  	for x := 0; x < 100; x++ {
    54  		time.Sleep(time.Second / 100.0)
    55  		if err := stream.Send(&protobuf.Empty{}); err != nil {
    56  			return err
    57  		}
    58  	}
    59  	return nil
    60  }
    61  
    62  func cancelableSleep(ctx context.Context, sleep time.Duration) error {
    63  	select {
    64  	case <-time.After(sleep):
    65  	case <-ctx.Done():
    66  	}
    67  	return ctx.Err()
    68  }
    69  
    70  func TestTCPv4Network(t *testing.T) {
    71  	cfg := Config{
    72  		HTTPListenNetwork: NetworkTCPV4,
    73  		HTTPListenAddress: "localhost",
    74  		HTTPListenPort:    9290,
    75  		GRPCListenNetwork: NetworkTCPV4,
    76  		GRPCListenAddress: "localhost",
    77  		GRPCListenPort:    9291,
    78  	}
    79  	t.Run("http", func(t *testing.T) {
    80  		cfg.MetricsNamespace = "testing_http_tcp4"
    81  		srv, err := New(cfg)
    82  		require.NoError(t, err)
    83  
    84  		errChan := make(chan error, 1)
    85  		go func() {
    86  			errChan <- srv.Run()
    87  		}()
    88  
    89  		require.NoError(t, srv.httpListener.Close())
    90  		require.NotNil(t, <-errChan)
    91  
    92  		// So that address is freed for further tests.
    93  		srv.GRPC.Stop()
    94  	})
    95  
    96  	t.Run("grpc", func(t *testing.T) {
    97  		cfg.MetricsNamespace = "testing_grpc_tcp4"
    98  		srv, err := New(cfg)
    99  		require.NoError(t, err)
   100  
   101  		errChan := make(chan error, 1)
   102  		go func() {
   103  			errChan <- srv.Run()
   104  		}()
   105  
   106  		require.NoError(t, srv.grpcListener.Close())
   107  		require.NotNil(t, <-errChan)
   108  	})
   109  }
   110  
   111  // Ensure that http and grpc servers work with no overrides to config
   112  // (except http port because an ordinary user can't bind to default port 80)
   113  func TestDefaultAddresses(t *testing.T) {
   114  	var cfg Config
   115  	cfg.RegisterFlags(flag.NewFlagSet("", flag.ExitOnError))
   116  	cfg.HTTPListenPort = 9090
   117  	cfg.MetricsNamespace = "testing_addresses"
   118  
   119  	server, err := New(cfg)
   120  	require.NoError(t, err)
   121  
   122  	fakeServer := FakeServer{}
   123  	RegisterFakeServerServer(server.GRPC, fakeServer)
   124  
   125  	server.HTTP.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
   126  		w.WriteHeader(204)
   127  	})
   128  
   129  	go server.Run()
   130  	defer server.Shutdown()
   131  
   132  	conn, err := grpc.Dial("localhost:9095", grpc.WithTransportCredentials(insecure.NewCredentials()))
   133  	require.NoError(t, err)
   134  	defer conn.Close()
   135  
   136  	empty := protobuf.Empty{}
   137  	client := NewFakeServerClient(conn)
   138  	_, err = client.Succeed(context.Background(), &empty)
   139  	require.NoError(t, err)
   140  
   141  	req, err := http.NewRequest("GET", "http://127.0.0.1:9090/test", nil)
   142  	require.NoError(t, err)
   143  	_, err = http.DefaultClient.Do(req)
   144  	require.NoError(t, err)
   145  }
   146  
   147  func TestErrorInstrumentationMiddleware(t *testing.T) {
   148  	var cfg Config
   149  	cfg.RegisterFlags(flag.NewFlagSet("", flag.ExitOnError))
   150  	cfg.HTTPListenPort = 9090 // can't use 80 as ordinary user
   151  	cfg.GRPCListenAddress = "localhost"
   152  	cfg.GRPCListenPort = 1234
   153  	server, err := New(cfg)
   154  	require.NoError(t, err)
   155  
   156  	fakeServer := FakeServer{}
   157  	RegisterFakeServerServer(server.GRPC, fakeServer)
   158  
   159  	server.HTTP.HandleFunc("/succeed", func(w http.ResponseWriter, r *http.Request) {
   160  	})
   161  	server.HTTP.HandleFunc("/error500", func(w http.ResponseWriter, r *http.Request) {
   162  		w.WriteHeader(500)
   163  	})
   164  	server.HTTP.HandleFunc("/sleep10", func(w http.ResponseWriter, r *http.Request) {
   165  		_ = cancelableSleep(r.Context(), time.Second*10)
   166  	})
   167  	server.HTTP.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   168  		w.WriteHeader(http.StatusNotFound)
   169  	})
   170  
   171  	go server.Run()
   172  
   173  	conn, err := grpc.Dial("localhost:1234", grpc.WithTransportCredentials(insecure.NewCredentials()))
   174  	require.NoError(t, err)
   175  	defer conn.Close()
   176  
   177  	empty := protobuf.Empty{}
   178  	client := NewFakeServerClient(conn)
   179  	res, err := client.Succeed(context.Background(), &empty)
   180  	require.NoError(t, err)
   181  	require.EqualValues(t, &empty, res)
   182  
   183  	res, err = client.FailWithError(context.Background(), &empty)
   184  	require.Nil(t, res)
   185  	require.Error(t, err)
   186  
   187  	s, ok := status.FromError(err)
   188  	require.True(t, ok)
   189  	require.Equal(t, "test error", s.Message())
   190  
   191  	res, err = client.FailWithHTTPError(context.Background(), &FailWithHTTPErrorRequest{Code: http.StatusPaymentRequired})
   192  	require.Nil(t, res)
   193  	errResp, ok := httpgrpc.HTTPResponseFromError(err)
   194  	require.True(t, ok)
   195  	require.Equal(t, int32(http.StatusPaymentRequired), errResp.Code)
   196  	require.Equal(t, "402", string(errResp.Body))
   197  
   198  	callThenCancel := func(f func(ctx context.Context) error) error {
   199  		ctx, cancel := context.WithCancel(context.Background())
   200  		errChan := make(chan error, 1)
   201  		go func() {
   202  			errChan <- f(ctx)
   203  		}()
   204  		time.Sleep(50 * time.Millisecond) // allow the call to reach the handler
   205  		cancel()
   206  		return <-errChan
   207  	}
   208  
   209  	err = callThenCancel(func(ctx context.Context) error {
   210  		_, err = client.Sleep(ctx, &empty)
   211  		return err
   212  	})
   213  	require.Error(t, err, context.Canceled)
   214  
   215  	err = callThenCancel(func(ctx context.Context) error {
   216  		_, err = client.StreamSleep(ctx, &empty)
   217  		return err
   218  	})
   219  	require.NoError(t, err) // canceling a streaming fn doesn't generate an error
   220  
   221  	// Now test the HTTP versions of the functions
   222  	{
   223  		req, err := http.NewRequest("GET", "http://127.0.0.1:9090/succeed", nil)
   224  		require.NoError(t, err)
   225  		_, err = http.DefaultClient.Do(req)
   226  		require.NoError(t, err)
   227  	}
   228  	{
   229  		req, err := http.NewRequest("GET", "http://127.0.0.1:9090/error500", nil)
   230  		require.NoError(t, err)
   231  		_, err = http.DefaultClient.Do(req)
   232  		require.NoError(t, err)
   233  	}
   234  	{
   235  		req, err := http.NewRequest("GET", "http://127.0.0.1:9090/notfound", nil)
   236  		require.NoError(t, err)
   237  		_, err = http.DefaultClient.Do(req)
   238  		require.NoError(t, err)
   239  	}
   240  	{
   241  		req, err := http.NewRequest("GET", "http://127.0.0.1:9090/sleep10", nil)
   242  		require.NoError(t, err)
   243  		err = callThenCancel(func(ctx context.Context) error {
   244  			_, err = http.DefaultClient.Do(req.WithContext(ctx))
   245  			return err
   246  		})
   247  		require.Error(t, err, context.Canceled)
   248  	}
   249  
   250  	require.NoError(t, conn.Close())
   251  	server.Shutdown()
   252  
   253  	metrics, err := prometheus.DefaultGatherer.Gather()
   254  	require.NoError(t, err)
   255  
   256  	statuses := map[string]string{}
   257  	for _, family := range metrics {
   258  		if *family.Name == "request_duration_seconds" {
   259  			for _, metric := range family.Metric {
   260  				var route, statusCode string
   261  				for _, label := range metric.GetLabel() {
   262  					switch label.GetName() {
   263  					case "status_code":
   264  						statusCode = label.GetValue()
   265  					case "route":
   266  						route = label.GetValue()
   267  					}
   268  				}
   269  				statuses[route] = statusCode
   270  			}
   271  		}
   272  	}
   273  	require.Equal(t, map[string]string{
   274  		"/server.FakeServer/FailWithError":     "error",
   275  		"/server.FakeServer/FailWithHTTPError": "402",
   276  		"/server.FakeServer/Sleep":             "cancel",
   277  		"/server.FakeServer/StreamSleep":       "cancel",
   278  		"/server.FakeServer/Succeed":           "success",
   279  		"error500":                             "500",
   280  		"sleep10":                              "200",
   281  		"succeed":                              "200",
   282  		"notfound":                             "404",
   283  	}, statuses)
   284  }
   285  
   286  func TestHTTPInstrumentationMetrics(t *testing.T) {
   287  	reg := prometheus.NewRegistry()
   288  	prometheus.DefaultRegisterer = reg
   289  	prometheus.DefaultGatherer = reg
   290  
   291  	var cfg Config
   292  	cfg.RegisterFlags(flag.NewFlagSet("", flag.ExitOnError))
   293  	cfg.HTTPListenPort = 9090 // can't use 80 as ordinary user
   294  	cfg.GRPCListenAddress = "localhost"
   295  	cfg.GRPCListenPort = 1234
   296  	server, err := New(cfg)
   297  	require.NoError(t, err)
   298  
   299  	server.HTTP.HandleFunc("/succeed", func(w http.ResponseWriter, r *http.Request) {
   300  		_, _ = w.Write([]byte("OK"))
   301  	})
   302  	server.HTTP.HandleFunc("/error500", func(w http.ResponseWriter, r *http.Request) {
   303  		w.WriteHeader(500)
   304  	})
   305  	server.HTTP.HandleFunc("/sleep10", func(w http.ResponseWriter, r *http.Request) {
   306  		_, _ = io.Copy(io.Discard, r.Body) // Consume body, otherwise it's not counted.
   307  		_ = cancelableSleep(r.Context(), time.Second*10)
   308  	})
   309  
   310  	go server.Run()
   311  
   312  	callThenCancel := func(f func(ctx context.Context) error) error {
   313  		ctx, cancel := context.WithCancel(context.Background())
   314  		errChan := make(chan error, 1)
   315  		go func() {
   316  			errChan <- f(ctx)
   317  		}()
   318  		time.Sleep(50 * time.Millisecond) // allow the call to reach the handler
   319  		cancel()
   320  		return <-errChan
   321  	}
   322  
   323  	// Now test the HTTP versions of the functions
   324  	{
   325  		req, err := http.NewRequest("GET", "http://127.0.0.1:9090/succeed", nil)
   326  		require.NoError(t, err)
   327  		resp, err := http.DefaultClient.Do(req)
   328  		require.NoError(t, err)
   329  		body, err := io.ReadAll(resp.Body)
   330  		require.NoError(t, err)
   331  		require.Equal(t, "OK", string(body))
   332  	}
   333  	{
   334  		req, err := http.NewRequest("GET", "http://127.0.0.1:9090/error500", nil)
   335  		require.NoError(t, err)
   336  		_, err = http.DefaultClient.Do(req)
   337  		require.NoError(t, err)
   338  	}
   339  	{
   340  		req, err := http.NewRequest("POST", "http://127.0.0.1:9090/sleep10", bytes.NewReader([]byte("Body")))
   341  		require.NoError(t, err)
   342  		err = callThenCancel(func(ctx context.Context) error {
   343  			_, err = http.DefaultClient.Do(req.WithContext(ctx))
   344  			return err
   345  		})
   346  		require.Error(t, err, context.Canceled)
   347  	}
   348  
   349  	server.Shutdown()
   350  
   351  	require.NoError(t, testutil.GatherAndCompare(prometheus.DefaultGatherer, bytes.NewBufferString(`
   352  		# HELP inflight_requests Current number of inflight requests.
   353  		# TYPE inflight_requests gauge
   354  		inflight_requests{method="POST",route="sleep10"} 0
   355  		inflight_requests{method="GET",route="succeed"} 0
   356         	inflight_requests{method="GET",route="error500"} 0
   357  
   358  		# HELP request_message_bytes Size (in bytes) of messages received in the request.
   359  		# TYPE request_message_bytes histogram
   360  		request_message_bytes_bucket{method="GET",route="error500",le="1.048576e+06"} 1
   361  		request_message_bytes_bucket{method="GET",route="error500",le="2.62144e+06"} 1
   362  		request_message_bytes_bucket{method="GET",route="error500",le="5.24288e+06"} 1
   363  		request_message_bytes_bucket{method="GET",route="error500",le="1.048576e+07"} 1
   364  		request_message_bytes_bucket{method="GET",route="error500",le="2.62144e+07"} 1
   365  		request_message_bytes_bucket{method="GET",route="error500",le="5.24288e+07"} 1
   366  		request_message_bytes_bucket{method="GET",route="error500",le="1.048576e+08"} 1
   367  		request_message_bytes_bucket{method="GET",route="error500",le="2.62144e+08"} 1
   368  		request_message_bytes_bucket{method="GET",route="error500",le="+Inf"} 1
   369  		request_message_bytes_sum{method="GET",route="error500"} 0
   370  		request_message_bytes_count{method="GET",route="error500"} 1
   371  
   372  		request_message_bytes_bucket{method="POST",route="sleep10",le="1.048576e+06"} 1
   373  		request_message_bytes_bucket{method="POST",route="sleep10",le="2.62144e+06"} 1
   374  		request_message_bytes_bucket{method="POST",route="sleep10",le="5.24288e+06"} 1
   375  		request_message_bytes_bucket{method="POST",route="sleep10",le="1.048576e+07"} 1
   376  		request_message_bytes_bucket{method="POST",route="sleep10",le="2.62144e+07"} 1
   377  		request_message_bytes_bucket{method="POST",route="sleep10",le="5.24288e+07"} 1
   378  		request_message_bytes_bucket{method="POST",route="sleep10",le="1.048576e+08"} 1
   379  		request_message_bytes_bucket{method="POST",route="sleep10",le="2.62144e+08"} 1
   380  		request_message_bytes_bucket{method="POST",route="sleep10",le="+Inf"} 1
   381  		request_message_bytes_sum{method="POST",route="sleep10"} 4
   382  		request_message_bytes_count{method="POST",route="sleep10"} 1
   383  
   384  		request_message_bytes_bucket{method="GET",route="succeed",le="1.048576e+06"} 1
   385  		request_message_bytes_bucket{method="GET",route="succeed",le="2.62144e+06"} 1
   386  		request_message_bytes_bucket{method="GET",route="succeed",le="5.24288e+06"} 1
   387  		request_message_bytes_bucket{method="GET",route="succeed",le="1.048576e+07"} 1
   388  		request_message_bytes_bucket{method="GET",route="succeed",le="2.62144e+07"} 1
   389  		request_message_bytes_bucket{method="GET",route="succeed",le="5.24288e+07"} 1
   390  		request_message_bytes_bucket{method="GET",route="succeed",le="1.048576e+08"} 1
   391  		request_message_bytes_bucket{method="GET",route="succeed",le="2.62144e+08"} 1
   392  		request_message_bytes_bucket{method="GET",route="succeed",le="+Inf"} 1
   393  		request_message_bytes_sum{method="GET",route="succeed"} 0
   394  		request_message_bytes_count{method="GET",route="succeed"} 1
   395  
   396  		# HELP response_message_bytes Size (in bytes) of messages sent in response.
   397  		# TYPE response_message_bytes histogram
   398  		response_message_bytes_bucket{method="GET",route="error500",le="1.048576e+06"} 1
   399  		response_message_bytes_bucket{method="GET",route="error500",le="2.62144e+06"} 1
   400  		response_message_bytes_bucket{method="GET",route="error500",le="5.24288e+06"} 1
   401  		response_message_bytes_bucket{method="GET",route="error500",le="1.048576e+07"} 1
   402  		response_message_bytes_bucket{method="GET",route="error500",le="2.62144e+07"} 1
   403  		response_message_bytes_bucket{method="GET",route="error500",le="5.24288e+07"} 1
   404  		response_message_bytes_bucket{method="GET",route="error500",le="1.048576e+08"} 1
   405  		response_message_bytes_bucket{method="GET",route="error500",le="2.62144e+08"} 1
   406  		response_message_bytes_bucket{method="GET",route="error500",le="+Inf"} 1
   407  		response_message_bytes_sum{method="GET",route="error500"} 0
   408  		response_message_bytes_count{method="GET",route="error500"} 1
   409  
   410  		response_message_bytes_bucket{method="POST",route="sleep10",le="1.048576e+06"} 1
   411  		response_message_bytes_bucket{method="POST",route="sleep10",le="2.62144e+06"} 1
   412  		response_message_bytes_bucket{method="POST",route="sleep10",le="5.24288e+06"} 1
   413  		response_message_bytes_bucket{method="POST",route="sleep10",le="1.048576e+07"} 1
   414  		response_message_bytes_bucket{method="POST",route="sleep10",le="2.62144e+07"} 1
   415  		response_message_bytes_bucket{method="POST",route="sleep10",le="5.24288e+07"} 1
   416  		response_message_bytes_bucket{method="POST",route="sleep10",le="1.048576e+08"} 1
   417  		response_message_bytes_bucket{method="POST",route="sleep10",le="2.62144e+08"} 1
   418  		response_message_bytes_bucket{method="POST",route="sleep10",le="+Inf"} 1
   419  		response_message_bytes_sum{method="POST",route="sleep10"} 0
   420  		response_message_bytes_count{method="POST",route="sleep10"} 1
   421  
   422  		response_message_bytes_bucket{method="GET",route="succeed",le="1.048576e+06"} 1
   423  		response_message_bytes_bucket{method="GET",route="succeed",le="2.62144e+06"} 1
   424  		response_message_bytes_bucket{method="GET",route="succeed",le="5.24288e+06"} 1
   425  		response_message_bytes_bucket{method="GET",route="succeed",le="1.048576e+07"} 1
   426  		response_message_bytes_bucket{method="GET",route="succeed",le="2.62144e+07"} 1
   427  		response_message_bytes_bucket{method="GET",route="succeed",le="5.24288e+07"} 1
   428  		response_message_bytes_bucket{method="GET",route="succeed",le="1.048576e+08"} 1
   429  		response_message_bytes_bucket{method="GET",route="succeed",le="2.62144e+08"} 1
   430  		response_message_bytes_bucket{method="GET",route="succeed",le="+Inf"} 1
   431  		response_message_bytes_sum{method="GET",route="succeed"} 2
   432  		response_message_bytes_count{method="GET",route="succeed"} 1
   433  
   434  		# HELP tcp_connections Current number of accepted TCP connections.
   435  		# TYPE tcp_connections gauge
   436  		tcp_connections{protocol="http"} 0
   437  		tcp_connections{protocol="grpc"} 0
   438  	`), "request_message_bytes", "response_message_bytes", "inflight_requests", "tcp_connections"))
   439  }
   440  
   441  func TestRunReturnsError(t *testing.T) {
   442  	cfg := Config{
   443  		HTTPListenNetwork: DefaultNetwork,
   444  		HTTPListenAddress: "localhost",
   445  		HTTPListenPort:    9090,
   446  		GRPCListenNetwork: DefaultNetwork,
   447  		GRPCListenAddress: "localhost",
   448  		GRPCListenPort:    9191,
   449  	}
   450  	t.Run("http", func(t *testing.T) {
   451  		cfg.MetricsNamespace = "testing_http"
   452  		srv, err := New(cfg)
   453  		require.NoError(t, err)
   454  
   455  		errChan := make(chan error, 1)
   456  		go func() {
   457  			errChan <- srv.Run()
   458  		}()
   459  
   460  		require.NoError(t, srv.httpListener.Close())
   461  		require.NotNil(t, <-errChan)
   462  
   463  		// So that address is freed for further tests.
   464  		srv.GRPC.Stop()
   465  	})
   466  
   467  	t.Run("grpc", func(t *testing.T) {
   468  		cfg.MetricsNamespace = "testing_grpc"
   469  		srv, err := New(cfg)
   470  		require.NoError(t, err)
   471  
   472  		errChan := make(chan error, 1)
   473  		go func() {
   474  			errChan <- srv.Run()
   475  		}()
   476  
   477  		require.NoError(t, srv.grpcListener.Close())
   478  		require.NotNil(t, <-errChan)
   479  	})
   480  }
   481  
   482  // Test to see what the logging of a 500 error looks like
   483  func TestMiddlewareLogging(t *testing.T) {
   484  	var level logging.Level
   485  	require.NoError(t, level.Set("info"))
   486  	cfg := Config{
   487  		HTTPListenNetwork:             DefaultNetwork,
   488  		HTTPListenAddress:             "localhost",
   489  		HTTPListenPort:                9192,
   490  		GRPCListenNetwork:             DefaultNetwork,
   491  		GRPCListenAddress:             "localhost",
   492  		HTTPMiddleware:                []middleware.Interface{middleware.Logging},
   493  		MetricsNamespace:              "testing_logging",
   494  		LogLevel:                      level,
   495  		DoNotAddDefaultHTTPMiddleware: true,
   496  		Router:                        &mux.Router{},
   497  	}
   498  	server, err := New(cfg)
   499  	require.NoError(t, err)
   500  
   501  	server.HTTP.HandleFunc("/error500", func(w http.ResponseWriter, r *http.Request) {
   502  		w.WriteHeader(500)
   503  	})
   504  
   505  	go server.Run()
   506  	defer server.Shutdown()
   507  
   508  	req, err := http.NewRequest("GET", "http://127.0.0.1:9192/error500", nil)
   509  	require.NoError(t, err)
   510  	_, err = http.DefaultClient.Do(req)
   511  	require.NoError(t, err)
   512  }
   513  
   514  func TestTLSServer(t *testing.T) {
   515  	var level logging.Level
   516  	require.NoError(t, level.Set("info"))
   517  
   518  	cmd := exec.Command("bash", "certs/genCerts.sh", "certs", "1")
   519  	err := cmd.Run()
   520  	require.NoError(t, err)
   521  
   522  	cfg := Config{
   523  		HTTPListenNetwork: DefaultNetwork,
   524  		HTTPListenAddress: "localhost",
   525  		HTTPListenPort:    9193,
   526  		HTTPTLSConfig: TLSConfig{
   527  			TLSCertPath: "certs/server.crt",
   528  			TLSKeyPath:  "certs/server.key",
   529  			ClientAuth:  "RequireAndVerifyClientCert",
   530  			ClientCAs:   "certs/root.crt",
   531  		},
   532  		GRPCTLSConfig: TLSConfig{
   533  			TLSCertPath: "certs/server.crt",
   534  			TLSKeyPath:  "certs/server.key",
   535  			ClientAuth:  "VerifyClientCertIfGiven",
   536  			ClientCAs:   "certs/root.crt",
   537  		},
   538  		MetricsNamespace:  "testing_tls",
   539  		GRPCListenNetwork: DefaultNetwork,
   540  		GRPCListenAddress: "localhost",
   541  		GRPCListenPort:    9194,
   542  	}
   543  	server, err := New(cfg)
   544  	require.NoError(t, err)
   545  
   546  	server.HTTP.HandleFunc("/testhttps", func(w http.ResponseWriter, r *http.Request) {
   547  		w.Write([]byte("Hello World!"))
   548  	})
   549  
   550  	fakeServer := FakeServer{}
   551  	RegisterFakeServerServer(server.GRPC, fakeServer)
   552  
   553  	go server.Run()
   554  	defer server.Shutdown()
   555  
   556  	clientCert, err := tls.LoadX509KeyPair("certs/client.crt", "certs/client.key")
   557  	require.NoError(t, err)
   558  
   559  	caCert, err := os.ReadFile(cfg.HTTPTLSConfig.ClientCAs)
   560  	require.NoError(t, err)
   561  
   562  	caCertPool := x509.NewCertPool()
   563  	caCertPool.AppendCertsFromPEM(caCert)
   564  
   565  	tlsConfig := &tls.Config{
   566  		InsecureSkipVerify: true,
   567  		Certificates:       []tls.Certificate{clientCert},
   568  		RootCAs:            caCertPool,
   569  	}
   570  	tr := &http.Transport{
   571  		TLSClientConfig: tlsConfig,
   572  	}
   573  
   574  	client := &http.Client{Transport: tr}
   575  	res, err := client.Get("https://localhost:9193/testhttps")
   576  	require.NoError(t, err)
   577  	defer res.Body.Close()
   578  
   579  	require.Equal(t, res.StatusCode, http.StatusOK)
   580  
   581  	body, err := io.ReadAll(res.Body)
   582  	require.NoError(t, err)
   583  	expected := []byte("Hello World!")
   584  	require.Equal(t, expected, body)
   585  
   586  	conn, err := grpc.Dial("localhost:9194", grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig)))
   587  	require.NoError(t, err)
   588  	defer conn.Close()
   589  
   590  	empty := protobuf.Empty{}
   591  	grpcClient := NewFakeServerClient(conn)
   592  	grpcRes, err := grpcClient.Succeed(context.Background(), &empty)
   593  	require.NoError(t, err)
   594  	require.EqualValues(t, &empty, grpcRes)
   595  }
   596  
   597  type FakeLogger struct {
   598  	sourceIPs string
   599  }
   600  
   601  func (f *FakeLogger) Debugf(_ string, _ ...interface{}) {}
   602  func (f *FakeLogger) Debugln(_ ...interface{})          {}
   603  
   604  func (f *FakeLogger) Infof(_ string, _ ...interface{}) {}
   605  func (f *FakeLogger) Infoln(_ ...interface{})          {}
   606  
   607  func (f *FakeLogger) Errorf(_ string, _ ...interface{}) {}
   608  func (f *FakeLogger) Errorln(_ ...interface{})          {}
   609  
   610  func (f *FakeLogger) Warnf(_ string, _ ...interface{}) {}
   611  func (f *FakeLogger) Warnln(_ ...interface{})          {}
   612  
   613  func (f *FakeLogger) WithField(key string, value interface{}) logging.Interface {
   614  	if key == "sourceIPs" {
   615  		f.sourceIPs = value.(string)
   616  	}
   617  
   618  	return f
   619  }
   620  
   621  func (f *FakeLogger) WithFields(_ logging.Fields) logging.Interface {
   622  	return f
   623  }
   624  
   625  func TestLogSourceIPs(t *testing.T) {
   626  	var level logging.Level
   627  	require.NoError(t, level.Set("debug"))
   628  	fake := FakeLogger{}
   629  	cfg := Config{
   630  		HTTPListenNetwork: DefaultNetwork,
   631  		HTTPListenAddress: "localhost",
   632  		HTTPListenPort:    9195,
   633  		GRPCListenNetwork: DefaultNetwork,
   634  		GRPCListenAddress: "localhost",
   635  		HTTPMiddleware:    []middleware.Interface{middleware.Logging},
   636  		MetricsNamespace:  "testing_mux",
   637  		LogLevel:          level,
   638  		Log:               &fake,
   639  		LogSourceIPs:      true,
   640  	}
   641  	server, err := New(cfg)
   642  	require.NoError(t, err)
   643  
   644  	server.HTTP.HandleFunc("/error500", func(w http.ResponseWriter, r *http.Request) {
   645  		w.WriteHeader(500)
   646  	})
   647  
   648  	go server.Run()
   649  	defer server.Shutdown()
   650  
   651  	require.Empty(t, fake.sourceIPs)
   652  
   653  	req, err := http.NewRequest("GET", "http://127.0.0.1:9195/error500", nil)
   654  	require.NoError(t, err)
   655  	_, err = http.DefaultClient.Do(req)
   656  	require.NoError(t, err)
   657  
   658  	require.Equal(t, fake.sourceIPs, "127.0.0.1")
   659  }
   660  
   661  func TestStopWithDisabledSignalHandling(t *testing.T) {
   662  	cfg := Config{
   663  		HTTPListenNetwork: DefaultNetwork,
   664  		HTTPListenAddress: "localhost",
   665  		HTTPListenPort:    9198,
   666  		GRPCListenNetwork: DefaultNetwork,
   667  		GRPCListenAddress: "localhost",
   668  		GRPCListenPort:    9199,
   669  	}
   670  
   671  	var test = func(t *testing.T, metricsNamespace string, handler SignalHandler) {
   672  		cfg.SignalHandler = handler
   673  		cfg.MetricsNamespace = metricsNamespace
   674  		srv, err := New(cfg)
   675  		require.NoError(t, err)
   676  
   677  		errChan := make(chan error, 1)
   678  		go func() {
   679  			errChan <- srv.Run()
   680  		}()
   681  
   682  		srv.Stop()
   683  		require.Nil(t, <-errChan)
   684  
   685  		// So that addresses is freed for further tests.
   686  		srv.Shutdown()
   687  	}
   688  
   689  	t.Run("signals_enabled", func(t *testing.T) {
   690  		test(t, "signals_enabled", nil)
   691  	})
   692  
   693  	t.Run("signals_disabled", func(t *testing.T) {
   694  		test(t, "signals_disabled", dummyHandler{quit: make(chan struct{})})
   695  	})
   696  }
   697  
   698  type dummyHandler struct {
   699  	quit chan struct{}
   700  }
   701  
   702  func (dh dummyHandler) Loop() {
   703  	<-dh.quit
   704  }
   705  
   706  func (dh dummyHandler) Stop() {
   707  	close(dh.quit)
   708  }