github.com/xzl8028/xenia-server@v0.0.0-20190809101854-18450a97da63/app/server_test.go (about) 1 // Copyright (c) 2017-present Xenia, 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/xzl8028/xenia-server/mlog" 10 "io/ioutil" 11 "net" 12 "net/http" 13 "os" 14 "path" 15 "strconv" 16 "strings" 17 "testing" 18 19 "github.com/xzl8028/xenia-server/config" 20 "github.com/xzl8028/xenia-server/model" 21 "github.com/xzl8028/xenia-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 }