health_test.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. package health
  2. import (
  3. "net/http"
  4. "os"
  5. "strings"
  6. "sync"
  7. "testing"
  8. "time"
  9. "github.com/fatedier/frp/tests/config"
  10. "github.com/fatedier/frp/tests/consts"
  11. "github.com/fatedier/frp/tests/mock"
  12. "github.com/fatedier/frp/tests/util"
  13. "github.com/stretchr/testify/assert"
  14. )
  15. const FRPS_CONF = `
  16. [common]
  17. bind_addr = 0.0.0.0
  18. bind_port = 14000
  19. vhost_http_port = 14000
  20. log_file = console
  21. log_level = debug
  22. token = 123456
  23. `
  24. const FRPC_CONF = `
  25. [common]
  26. server_addr = 127.0.0.1
  27. server_port = 14000
  28. log_file = console
  29. log_level = debug
  30. token = 123456
  31. [tcp1]
  32. type = tcp
  33. local_port = 15001
  34. remote_port = 15000
  35. group = test
  36. group_key = 123
  37. health_check_type = tcp
  38. health_check_interval_s = 1
  39. [tcp2]
  40. type = tcp
  41. local_port = 15002
  42. remote_port = 15000
  43. group = test
  44. group_key = 123
  45. health_check_type = tcp
  46. health_check_interval_s = 1
  47. [http1]
  48. type = http
  49. local_port = 15003
  50. custom_domains = test1.com
  51. health_check_type = http
  52. health_check_interval_s = 1
  53. health_check_url = /health
  54. [http2]
  55. type = http
  56. local_port = 15004
  57. custom_domains = test2.com
  58. health_check_type = http
  59. health_check_interval_s = 1
  60. health_check_url = /health
  61. [http3]
  62. type = http
  63. local_port = 15005
  64. custom_domains = test.balancing.com
  65. group = test-balancing
  66. group_key = 123
  67. [http4]
  68. type = http
  69. local_port = 15006
  70. custom_domains = test.balancing.com
  71. group = test-balancing
  72. group_key = 123
  73. `
  74. func TestHealthCheck(t *testing.T) {
  75. assert := assert.New(t)
  76. // ****** start background services ******
  77. echoSvc1 := mock.NewEchoServer(15001, 1, "echo1")
  78. err := echoSvc1.Start()
  79. if assert.NoError(err) {
  80. defer echoSvc1.Stop()
  81. }
  82. echoSvc2 := mock.NewEchoServer(15002, 1, "echo2")
  83. err = echoSvc2.Start()
  84. if assert.NoError(err) {
  85. defer echoSvc2.Stop()
  86. }
  87. var healthMu sync.RWMutex
  88. svc1Health := true
  89. svc2Health := true
  90. httpSvc1 := mock.NewHTTPServer(15003, func(w http.ResponseWriter, r *http.Request) {
  91. if strings.Contains(r.URL.Path, "health") {
  92. healthMu.RLock()
  93. defer healthMu.RUnlock()
  94. if svc1Health {
  95. w.WriteHeader(200)
  96. } else {
  97. w.WriteHeader(500)
  98. }
  99. } else {
  100. w.Write([]byte("http1"))
  101. }
  102. })
  103. err = httpSvc1.Start()
  104. if assert.NoError(err) {
  105. defer httpSvc1.Stop()
  106. }
  107. httpSvc2 := mock.NewHTTPServer(15004, func(w http.ResponseWriter, r *http.Request) {
  108. if strings.Contains(r.URL.Path, "health") {
  109. healthMu.RLock()
  110. defer healthMu.RUnlock()
  111. if svc2Health {
  112. w.WriteHeader(200)
  113. } else {
  114. w.WriteHeader(500)
  115. }
  116. } else {
  117. w.Write([]byte("http2"))
  118. }
  119. })
  120. err = httpSvc2.Start()
  121. if assert.NoError(err) {
  122. defer httpSvc2.Stop()
  123. }
  124. httpSvc3 := mock.NewHTTPServer(15005, func(w http.ResponseWriter, r *http.Request) {
  125. time.Sleep(time.Second)
  126. w.Write([]byte("http3"))
  127. })
  128. err = httpSvc3.Start()
  129. if assert.NoError(err) {
  130. defer httpSvc3.Stop()
  131. }
  132. httpSvc4 := mock.NewHTTPServer(15006, func(w http.ResponseWriter, r *http.Request) {
  133. time.Sleep(time.Second)
  134. w.Write([]byte("http4"))
  135. })
  136. err = httpSvc4.Start()
  137. if assert.NoError(err) {
  138. defer httpSvc4.Stop()
  139. }
  140. time.Sleep(200 * time.Millisecond)
  141. // ****** start frps and frpc ******
  142. frpsCfgPath, err := config.GenerateConfigFile(consts.FRPS_NORMAL_CONFIG, FRPS_CONF)
  143. if assert.NoError(err) {
  144. defer os.Remove(frpsCfgPath)
  145. }
  146. frpcCfgPath, err := config.GenerateConfigFile(consts.FRPC_NORMAL_CONFIG, FRPC_CONF)
  147. if assert.NoError(err) {
  148. defer os.Remove(frpcCfgPath)
  149. }
  150. frpsProcess := util.NewProcess(consts.FRPS_SUB_BIN_PATH, []string{"-c", frpsCfgPath})
  151. err = frpsProcess.Start()
  152. if assert.NoError(err) {
  153. defer frpsProcess.Stop()
  154. }
  155. time.Sleep(500 * time.Millisecond)
  156. frpcProcess := util.NewProcess(consts.FRPC_SUB_BIN_PATH, []string{"-c", frpcCfgPath})
  157. err = frpcProcess.Start()
  158. if assert.NoError(err) {
  159. defer frpcProcess.Stop()
  160. }
  161. time.Sleep(1000 * time.Millisecond)
  162. // ****** healcheck type tcp ******
  163. // echo1 and echo2 is ok
  164. result := make([]string, 0)
  165. res, err := util.SendTCPMsg("127.0.0.1:15000", "echo")
  166. assert.NoError(err)
  167. result = append(result, res)
  168. res, err = util.SendTCPMsg("127.0.0.1:15000", "echo")
  169. assert.NoError(err)
  170. result = append(result, res)
  171. assert.Contains(result, "echo1")
  172. assert.Contains(result, "echo2")
  173. // close echo2 server, echo1 is work
  174. echoSvc2.Stop()
  175. time.Sleep(1200 * time.Millisecond)
  176. result = make([]string, 0)
  177. res, err = util.SendTCPMsg("127.0.0.1:15000", "echo")
  178. assert.NoError(err)
  179. result = append(result, res)
  180. res, err = util.SendTCPMsg("127.0.0.1:15000", "echo")
  181. assert.NoError(err)
  182. result = append(result, res)
  183. assert.NotContains(result, "echo2")
  184. // resume echo2 server, all services are ok
  185. echoSvc2 = mock.NewEchoServer(15002, 1, "echo2")
  186. err = echoSvc2.Start()
  187. if assert.NoError(err) {
  188. defer echoSvc2.Stop()
  189. }
  190. time.Sleep(1200 * time.Millisecond)
  191. result = make([]string, 0)
  192. res, err = util.SendTCPMsg("127.0.0.1:15000", "echo")
  193. assert.NoError(err)
  194. result = append(result, res)
  195. res, err = util.SendTCPMsg("127.0.0.1:15000", "echo")
  196. assert.NoError(err)
  197. result = append(result, res)
  198. assert.Contains(result, "echo1")
  199. assert.Contains(result, "echo2")
  200. // ****** healcheck type http ******
  201. // http1 and http2 is ok
  202. code, body, _, err := util.SendHTTPMsg("GET", "http://127.0.0.1:14000/xxx", "test1.com", nil, "")
  203. assert.NoError(err)
  204. assert.Equal(200, code)
  205. assert.Equal("http1", body)
  206. code, body, _, err = util.SendHTTPMsg("GET", "http://127.0.0.1:14000/xxx", "test2.com", nil, "")
  207. assert.NoError(err)
  208. assert.Equal(200, code)
  209. assert.Equal("http2", body)
  210. // http2 health check error
  211. healthMu.Lock()
  212. svc2Health = false
  213. healthMu.Unlock()
  214. time.Sleep(1200 * time.Millisecond)
  215. code, body, _, err = util.SendHTTPMsg("GET", "http://127.0.0.1:14000/xxx", "test1.com", nil, "")
  216. assert.NoError(err)
  217. assert.Equal(200, code)
  218. assert.Equal("http1", body)
  219. code, _, _, err = util.SendHTTPMsg("GET", "http://127.0.0.1:14000/xxx", "test2.com", nil, "")
  220. assert.NoError(err)
  221. assert.Equal(404, code)
  222. // resume http2 service, http1 and http2 are ok
  223. healthMu.Lock()
  224. svc2Health = true
  225. healthMu.Unlock()
  226. time.Sleep(1200 * time.Millisecond)
  227. code, body, _, err = util.SendHTTPMsg("GET", "http://127.0.0.1:14000/xxx", "test1.com", nil, "")
  228. assert.NoError(err)
  229. assert.Equal(200, code)
  230. assert.Equal("http1", body)
  231. code, body, _, err = util.SendHTTPMsg("GET", "http://127.0.0.1:14000/xxx", "test2.com", nil, "")
  232. assert.NoError(err)
  233. assert.Equal(200, code)
  234. assert.Equal("http2", body)
  235. // ****** load balancing type http ******
  236. result = make([]string, 0)
  237. var wait sync.WaitGroup
  238. var mu sync.Mutex
  239. wait.Add(2)
  240. go func() {
  241. defer wait.Done()
  242. code, body, _, err := util.SendHTTPMsg("GET", "http://127.0.0.1:14000/xxx", "test.balancing.com", nil, "")
  243. assert.NoError(err)
  244. assert.Equal(200, code)
  245. mu.Lock()
  246. result = append(result, body)
  247. mu.Unlock()
  248. }()
  249. go func() {
  250. defer wait.Done()
  251. code, body, _, err = util.SendHTTPMsg("GET", "http://127.0.0.1:14000/xxx", "test.balancing.com", nil, "")
  252. assert.NoError(err)
  253. assert.Equal(200, code)
  254. mu.Lock()
  255. result = append(result, body)
  256. mu.Unlock()
  257. }()
  258. wait.Wait()
  259. assert.Contains(result, "http3")
  260. assert.Contains(result, "http4")
  261. }