v2 / vlib / x / sessions / tests / session_app_test.v
194 lines · 157 sloc · 4.34 KB · 4fa8167abbaced0ea99afe662c6ee3a2e2700f40
Raw
1// vtest retry: 2
2import net.http
3import time
4import x.sessions
5import veb
6import x.sessions.veb_middleware
7
8const port = 13010
9const localserver = 'http://127.0.0.1:${port}'
10const exit_after = time.second * 10
11const cookie_name = 'SESSION_ID'
12const max_age = time.second * 2
13
14pub struct User {
15pub mut:
16 name string
17 age int
18 verified bool
19}
20
21const default_user = User{
22 name: 'casper'
23 age: 21
24 verified: false
25}
26
27pub struct Context {
28 veb.Context
29 sessions.CurrentSession[User]
30}
31
32pub struct App {
33 veb.Middleware[Context]
34pub mut:
35 sessions &sessions.Sessions[User]
36 started chan bool
37}
38
39pub fn (mut app App) before_accept_loop() {
40 app.started <- true
41}
42
43pub fn (app &App) session_data(mut ctx Context) veb.Result {
44 return ctx.text('${ctx.session_data}')
45}
46
47pub fn (app &App) protected(mut ctx Context) veb.Result {
48 if user := ctx.session_data {
49 return ctx.json(user)
50 } else {
51 ctx.res.set_status(.unauthorized)
52 return ctx.text('No session saved!')
53 }
54}
55
56pub fn (mut app App) save_session(mut ctx Context) veb.Result {
57 app.sessions.save(mut ctx, default_user) or { return ctx.server_error(err.msg()) }
58 return ctx.ok('')
59}
60
61pub fn (mut app App) update_session(mut ctx Context) veb.Result {
62 if mut user := ctx.session_data {
63 user.age++
64 app.sessions.save(mut ctx, user) or { return ctx.server_error(err.msg()) }
65 // sessions module should also update the context
66 if new_user := ctx.session_data {
67 assert new_user == user, 'session data is not updated on the context'
68 } else {
69 assert false, 'session data should not be none'
70 }
71 }
72
73 return ctx.ok('')
74}
75
76pub fn (mut app App) destroy_session(mut ctx Context) veb.Result {
77 app.sessions.destroy(mut ctx) or { return ctx.server_error(err.msg()) }
78 // sessions module should also update the context
79 assert ctx.session_data == none
80
81 return ctx.ok('')
82}
83
84fn testsuite_begin() {
85 spawn fn () {
86 time.sleep(exit_after)
87 assert false, 'timeout reached!'
88 exit(1)
89 }()
90
91 mut app := &App{
92 sessions: &sessions.Sessions[User]{
93 store: sessions.MemoryStore[User]{}
94 secret: 'secret'.bytes()
95 cookie_options: sessions.CookieOptions{
96 cookie_name: cookie_name
97 }
98 max_age: max_age
99 }
100 }
101
102 app.use(veb_middleware.create[User, Context](mut app.sessions))
103
104 spawn veb.run_at[App, Context](mut app, port: port, family: .ip, timeout_in_seconds: 2)
105 // app startup time
106 _ := <-app.started
107 wait_for_server()!
108}
109
110fn test_empty_session() {
111 x := http.get('${localserver}/session_data')!
112
113 assert x.body == 'Option(none)'
114}
115
116fn test_protected_without_session() {
117 x := http.get('${localserver}/protected')!
118
119 assert x.status() == .unauthorized
120}
121
122fn test_save_session() {
123 sid := get_session_id()!
124 x := make_request_with_session_id(.get, '/session_data', sid)!
125
126 // cast to `?User` since, session_data is of type `?T`
127 assert x.body == '${?User(default_user)}'
128}
129
130fn test_update_session() {
131 sid := get_session_id()!
132
133 mut x := make_request_with_session_id(.get, '/update_session', sid)!
134 x = make_request_with_session_id(.get, '/session_data', sid)!
135
136 mut updated_user := default_user
137 updated_user.age++
138 assert x.body == '${?User(updated_user)}'
139}
140
141fn test_destroy_session() {
142 sid := get_session_id()!
143 mut x := make_request_with_session_id(.get, '/session_data', sid)!
144 assert x.body != 'Option(none)'
145
146 x = make_request_with_session_id(.get, '/destroy_session', sid)!
147 assert x.status() == .ok
148
149 x = make_request_with_session_id(.get, '/session_data', sid)!
150 assert x.body == 'Option(none)'
151}
152
153fn test_session_expired() {
154 sid := get_session_id()!
155 mut x := make_request_with_session_id(.get, '/session_data', sid)!
156 assert x.body != 'Option(none)'
157
158 time.sleep(max_age)
159
160 x = make_request_with_session_id(.get, '/session_data', sid)!
161 assert x.body == 'Option(none)'
162}
163
164// Utility
165
166fn get_session_id() !string {
167 x := http.get('${localserver}/save_session')!
168
169 return x.cookies()[0].value
170}
171
172fn make_request_with_session_id(method http.Method, path string, sid string) !http.Response {
173 return http.fetch(http.FetchConfig{
174 url: '${localserver}${path}'
175 method: method
176 cookies: {
177 cookie_name: sid
178 }
179 })
180}
181
182fn wait_for_server() ! {
183 for _ in 0 .. 40 {
184 response := http.get('${localserver}/session_data') or {
185 time.sleep(50 * time.millisecond)
186 continue
187 }
188 if response.status() == .ok {
189 return
190 }
191 time.sleep(50 * time.millisecond)
192 }
193 return error('session test server did not start in time')
194}
195