github.com/vnforks/kid@v5.11.1+incompatible/app/server_test.go (about)

     1  // Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
     2  // See License.txt for license information.
     3  
     4  package app
     5  
     6  import (
     7  	"bufio"
     8  	"crypto/tls"
     9  	"github.com/mattermost/mattermost-server/mlog"
    10  	"io/ioutil"
    11  	"net"
    12  	"net/http"
    13  	"os"
    14  	"path"
    15  	"strconv"
    16  	"strings"
    17  	"testing"
    18  
    19  	"github.com/mattermost/mattermost-server/config"
    20  	"github.com/mattermost/mattermost-server/model"
    21  	"github.com/mattermost/mattermost-server/utils/fileutils"
    22  	"github.com/stretchr/testify/require"
    23  )
    24  
    25  func TestStartServerSuccess(t *testing.T) {
    26  	s, err := NewServer()
    27  	require.NoError(t, err)
    28  
    29  	s.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = ":0" })
    30  	serverErr := s.Start()
    31  
    32  	client := &http.Client{}
    33  	checkEndpoint(t, client, "http://localhost:"+strconv.Itoa(s.ListenAddr.Port)+"/", http.StatusNotFound)
    34  
    35  	s.Shutdown()
    36  	require.NoError(t, serverErr)
    37  }
    38  
    39  func TestStartServerRateLimiterCriticalError(t *testing.T) {
    40  	// Attempt to use Rate Limiter with an invalid config
    41  	ms, err := config.NewMemoryStoreWithOptions(&config.MemoryStoreOptions{
    42  		SkipValidation: true,
    43  	})
    44  	require.NoError(t, err)
    45  
    46  	config := ms.Get()
    47  	*config.RateLimitSettings.Enable = true
    48  	*config.RateLimitSettings.MaxBurst = -100
    49  	_, err = ms.Set(config)
    50  	require.NoError(t, err)
    51  
    52  	s, err := NewServer(ConfigStore(ms))
    53  	require.NoError(t, err)
    54  
    55  	serverErr := s.Start()
    56  	s.Shutdown()
    57  	require.Error(t, serverErr)
    58  }
    59  
    60  func TestStartServerPortUnavailable(t *testing.T) {
    61  	s, err := NewServer()
    62  	require.NoError(t, err)
    63  
    64  	// Listen on the next available port
    65  	listener, err := net.Listen("tcp", ":0")
    66  	require.NoError(t, err)
    67  
    68  	// Attempt to listen on the port used above.
    69  	s.UpdateConfig(func(cfg *model.Config) {
    70  		*cfg.ServiceSettings.ListenAddress = listener.Addr().String()
    71  	})
    72  
    73  	serverErr := s.Start()
    74  	s.Shutdown()
    75  	require.Error(t, serverErr)
    76  }
    77  
    78  func TestStartServerTLSSuccess(t *testing.T) {
    79  	s, err := NewServer()
    80  	require.NoError(t, err)
    81  
    82  	testDir, _ := fileutils.FindDir("tests")
    83  	s.UpdateConfig(func(cfg *model.Config) {
    84  		*cfg.ServiceSettings.ListenAddress = ":0"
    85  		*cfg.ServiceSettings.ConnectionSecurity = "TLS"
    86  		*cfg.ServiceSettings.TLSKeyFile = path.Join(testDir, "tls_test_key.pem")
    87  		*cfg.ServiceSettings.TLSCertFile = path.Join(testDir, "tls_test_cert.pem")
    88  	})
    89  	serverErr := s.Start()
    90  
    91  	tr := &http.Transport{
    92  		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
    93  	}
    94  
    95  	client := &http.Client{Transport: tr}
    96  	checkEndpoint(t, client, "https://localhost:"+strconv.Itoa(s.ListenAddr.Port)+"/", http.StatusNotFound)
    97  
    98  	s.Shutdown()
    99  	require.NoError(t, serverErr)
   100  }
   101  
   102  func TestStartServerTLSVersion(t *testing.T) {
   103  	s, err := NewServer()
   104  	require.NoError(t, err)
   105  
   106  	testDir, _ := fileutils.FindDir("tests")
   107  	s.UpdateConfig(func(cfg *model.Config) {
   108  		*cfg.ServiceSettings.ListenAddress = ":0"
   109  		*cfg.ServiceSettings.ConnectionSecurity = "TLS"
   110  		*cfg.ServiceSettings.TLSMinVer = "1.2"
   111  		*cfg.ServiceSettings.TLSKeyFile = path.Join(testDir, "tls_test_key.pem")
   112  		*cfg.ServiceSettings.TLSCertFile = path.Join(testDir, "tls_test_cert.pem")
   113  	})
   114  	serverErr := s.Start()
   115  
   116  	tr := &http.Transport{
   117  		TLSClientConfig: &tls.Config{
   118  			InsecureSkipVerify: true,
   119  			MaxVersion:         tls.VersionTLS11,
   120  		},
   121  	}
   122  
   123  	client := &http.Client{Transport: tr}
   124  	err = checkEndpoint(t, client, "https://localhost:"+strconv.Itoa(s.ListenAddr.Port)+"/", http.StatusNotFound)
   125  
   126  	if !strings.Contains(err.Error(), "remote error: tls: protocol version not supported") {
   127  		t.Errorf("Expected protocol version error, got %s", err)
   128  	}
   129  
   130  	client.Transport = &http.Transport{
   131  		TLSClientConfig: &tls.Config{
   132  			InsecureSkipVerify: true,
   133  		},
   134  	}
   135  
   136  	err = checkEndpoint(t, client, "https://localhost:"+strconv.Itoa(s.ListenAddr.Port)+"/", http.StatusNotFound)
   137  
   138  	if err != nil {
   139  		t.Errorf("Expected nil, got %s", err)
   140  	}
   141  
   142  	s.Shutdown()
   143  	require.NoError(t, serverErr)
   144  }
   145  
   146  func TestStartServerTLSOverwriteCipher(t *testing.T) {
   147  	s, err := NewServer()
   148  	require.NoError(t, err)
   149  
   150  	testDir, _ := fileutils.FindDir("tests")
   151  	s.UpdateConfig(func(cfg *model.Config) {
   152  		*cfg.ServiceSettings.ListenAddress = ":0"
   153  		*cfg.ServiceSettings.ConnectionSecurity = "TLS"
   154  		cfg.ServiceSettings.TLSOverwriteCiphers = []string{
   155  			"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
   156  			"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
   157  		}
   158  		*cfg.ServiceSettings.TLSKeyFile = path.Join(testDir, "tls_test_key.pem")
   159  		*cfg.ServiceSettings.TLSCertFile = path.Join(testDir, "tls_test_cert.pem")
   160  	})
   161  	serverErr := s.Start()
   162  
   163  	tr := &http.Transport{
   164  		TLSClientConfig: &tls.Config{
   165  			InsecureSkipVerify: true,
   166  			CipherSuites: []uint16{
   167  				tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
   168  			},
   169  		},
   170  	}
   171  
   172  	client := &http.Client{Transport: tr}
   173  	err = checkEndpoint(t, client, "https://localhost:"+strconv.Itoa(s.ListenAddr.Port)+"/", http.StatusNotFound)
   174  
   175  	if !strings.Contains(err.Error(), "remote error: tls: handshake failure") {
   176  		t.Errorf("Expected protocol version error, got %s", err)
   177  	}
   178  
   179  	client.Transport = &http.Transport{
   180  		TLSClientConfig: &tls.Config{
   181  			InsecureSkipVerify: true,
   182  			CipherSuites: []uint16{
   183  				tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
   184  				tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
   185  			},
   186  		},
   187  	}
   188  
   189  	err = checkEndpoint(t, client, "https://localhost:"+strconv.Itoa(s.ListenAddr.Port)+"/", http.StatusNotFound)
   190  
   191  	if err != nil {
   192  		t.Errorf("Expected nil, got %s", err)
   193  	}
   194  
   195  	s.Shutdown()
   196  	require.NoError(t, serverErr)
   197  }
   198  
   199  func checkEndpoint(t *testing.T, client *http.Client, url string, expectedStatus int) error {
   200  	res, err := client.Get(url)
   201  
   202  	if err != nil {
   203  		return err
   204  	}
   205  
   206  	defer res.Body.Close()
   207  
   208  	if res.StatusCode != expectedStatus {
   209  		t.Errorf("Response code was %d; want %d", res.StatusCode, expectedStatus)
   210  	}
   211  
   212  	return nil
   213  }
   214  
   215  func TestPanicLog(t *testing.T) {
   216  	// Creating a temp file to collect logs
   217  	tmpfile, err := ioutil.TempFile("", "mlog")
   218  	if err != nil {
   219  		require.NoError(t, err)
   220  	}
   221  
   222  	defer func() {
   223  		require.NoError(t, tmpfile.Close())
   224  		require.NoError(t, os.Remove(tmpfile.Name()))
   225  	}()
   226  
   227  	// Creating logger to log to console and temp file
   228  	logger := mlog.NewLogger(&mlog.LoggerConfiguration{
   229  		EnableConsole: true,
   230  		ConsoleJson:   true,
   231  		EnableFile:    true,
   232  		FileLocation:  tmpfile.Name(),
   233  		FileLevel: mlog.LevelInfo,
   234  	})
   235  
   236  	// Creating a server with logger
   237  	s, err := NewServer(SetLogger(logger))
   238  	require.NoError(t, err)
   239  
   240  	// Route for just panicing
   241  	s.Router.HandleFunc("/panic", func(writer http.ResponseWriter, request *http.Request) {
   242  		s.Log.Info("inside panic handler")
   243  		panic("log this panic")
   244  	})
   245  
   246  	s.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = ":0" })
   247  	serverErr := s.Start()
   248  	require.NoError(t, serverErr)
   249  
   250  	// Calling panic route
   251  	tr := &http.Transport{
   252  		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
   253  	}
   254  
   255  	client := &http.Client{Transport: tr}
   256  	client.Get("https://localhost:" + strconv.Itoa(s.ListenAddr.Port) + "/panic")
   257  
   258  	err = s.Shutdown()
   259  	require.NoError(t, err)
   260  
   261  	// Checking whether panic was logged
   262  	var panicLogged = false
   263  	var infoLogged = false
   264  
   265  	_, err = tmpfile.Seek(0, 0)
   266  	require.NoError(t, err)
   267  
   268  	scanner := bufio.NewScanner(tmpfile)
   269  	for scanner.Scan() {
   270  		if !infoLogged && strings.Contains(scanner.Text(), "inside panic handler") {
   271  			infoLogged = true
   272  		}
   273  		if strings.Contains(scanner.Text(), "log this panic") {
   274  			panicLogged = true
   275  			break
   276  		}
   277  	}
   278  
   279  	if !infoLogged {
   280  		t.Error("Info log line was supposed to be logged")
   281  	}
   282  
   283  	if !panicLogged {
   284  		t.Error("Panic was supposed to be logged")
   285  	}
   286  }