v2 / vlib / veb / tests / graceful_shutdown_test.v
117 lines · 98 sloc · 3.0 KB · 344b9afcfe67902dd9660bd3b077f18464d1d114
Raw
1// vtest build: !windows // fasthttp.Server.run is not implemented on windows yet
2import net
3import net.http
4import time
5import veb
6
7const graceful_shutdown_host = '127.0.0.1'
8
9struct GracefulShutdownContext {
10 veb.Context
11}
12
13struct GracefulShutdownApp {
14mut:
15 server &veb.Server = unsafe { nil }
16 slow_started chan bool = chan bool{cap: 1}
17}
18
19pub fn (mut app GracefulShutdownApp) init_server(server &veb.Server) {
20 app.server = server
21}
22
23pub fn (mut app GracefulShutdownApp) index(mut ctx GracefulShutdownContext) veb.Result {
24 return ctx.text('ready')
25}
26
27@['/slow']
28pub fn (mut app GracefulShutdownApp) slow(mut ctx GracefulShutdownContext) veb.Result {
29 app.slow_started <- true
30 time.sleep(300 * time.millisecond)
31 return ctx.text('slow done')
32}
33
34pub fn (mut app GracefulShutdownApp) shutdown(mut ctx GracefulShutdownContext) veb.Result {
35 spawn app.shutdown_now()
36 return ctx.text('shutting down')
37}
38
39fn (app &GracefulShutdownApp) shutdown_now() {
40 mut server := app.server
41 if server == unsafe { nil } {
42 panic('veb server was not initialized')
43 }
44 server.shutdown() or { panic(err) }
45}
46
47fn run_graceful_shutdown_app(mut app GracefulShutdownApp, port int) {
48 veb.run_at[GracefulShutdownApp, GracefulShutdownContext](mut app,
49 host: graceful_shutdown_host
50 port: port
51 family: .ip
52 show_startup_message: false
53 ) or { panic(err) }
54}
55
56fn send_slow_request(port int, responses chan http.Response) {
57 response := http.get('http://${graceful_shutdown_host}:${port}/slow') or { panic(err) }
58 responses <- response
59}
60
61fn wait_for_server(port int) ! {
62 url := 'http://${graceful_shutdown_host}:${port}/'
63 for _ in 0 .. 100 {
64 response := http.get(url) or {
65 time.sleep(20 * time.millisecond)
66 continue
67 }
68 if response.status() == .ok && response.body == 'ready' {
69 return
70 }
71 time.sleep(20 * time.millisecond)
72 }
73 return error('server did not start listening in time')
74}
75
76fn test_veb_graceful_shutdown_waits_for_in_flight_requests() {
77 mut listener := net.listen_tcp(.ip, '${graceful_shutdown_host}:0') or { panic(err) }
78 port := listener.addr()!.port()!
79 listener.close() or {}
80
81 mut app := &GracefulShutdownApp{}
82 server_thread := spawn run_graceful_shutdown_app(mut app, int(port))
83
84 wait_for_server(int(port)) or {
85 assert false, err.msg()
86 return
87 }
88
89 slow_responses := chan http.Response{cap: 1}
90 spawn send_slow_request(int(port), slow_responses)
91 _ := <-app.slow_started or {
92 assert false, 'slow request did not start'
93 return
94 }
95
96 shutdown_response := http.get('http://${graceful_shutdown_host}:${port}/shutdown') or {
97 assert false, err.msg()
98 return
99 }
100 assert shutdown_response.status() == .ok
101 assert shutdown_response.body == 'shutting down'
102
103 slow_response := <-slow_responses or {
104 assert false, err.msg()
105 return
106 }
107 assert slow_response.status() == .ok
108 assert slow_response.body == 'slow done'
109
110 server_thread.wait()
111
112 http.get('http://${graceful_shutdown_host}:${port}/') or {
113 assert true
114 return
115 }
116 assert false, 'server still accepts new requests after shutdown'
117}
118