@@ -4,6 +4,10 @@ use axum_test::multipart::MultipartForm;
4
4
use axum_test:: TestServer ;
5
5
use cookie:: Cookie ;
6
6
use std:: rc:: Rc ;
7
+ use tracing_subscriber:: {
8
+ filter:: { self , LevelFilter } ,
9
+ prelude:: * ,
10
+ } ;
7
11
use trailbase_sqlite:: params;
8
12
9
13
use trailbase_core:: api:: { create_user_handler, login_with_password, CreateUserRequest } ;
@@ -15,17 +19,20 @@ use trailbase_core::AppState;
15
19
use trailbase_core:: { DataDir , Server , ServerOptions } ;
16
20
17
21
#[ test]
18
- fn test_record_apis ( ) {
22
+ fn integration_tests ( ) {
19
23
let runtime = Rc :: new (
20
24
tokio:: runtime:: Builder :: new_multi_thread ( )
21
25
. enable_all ( )
22
26
. build ( )
23
27
. unwrap ( ) ,
24
28
) ;
25
29
30
+ let _ = runtime. block_on ( test_record_apis ( ) ) ;
31
+ }
32
+
33
+ async fn test_record_apis ( ) {
26
34
let data_dir = temp_dir:: TempDir :: new ( ) . unwrap ( ) ;
27
35
28
- let _ = runtime. block_on ( async move {
29
36
let app = Server :: init ( ServerOptions {
30
37
data_dir : DataDir ( data_dir. path ( ) . to_path_buf ( ) ) ,
31
38
address : "" . to_string ( ) ,
@@ -41,137 +48,184 @@ fn test_record_apis() {
41
48
42
49
let state = app. state ( ) ;
43
50
let conn = state. conn ( ) ;
51
+ let logs_conn = state. logs_conn ( ) ;
44
52
45
53
create_chat_message_app_tables ( conn) . await . unwrap ( ) ;
46
54
state. refresh_table_cache ( ) . await . unwrap ( ) ;
47
55
48
56
let room = add_room ( conn, "room0" ) . await . unwrap ( ) ;
49
57
let password = "Secret!1!!" ;
58
+ let client_ip = "22.11.22.11" ;
50
59
51
60
// Register message table as record API with moderator read access.
52
61
add_record_api (
53
- & state,
54
- "messages_api" ,
55
- "message" ,
56
- Acls {
57
- authenticated : vec ! [ PermissionFlag :: Create , PermissionFlag :: Read ] ,
58
- ..Default :: default ( )
59
- } ,
60
- AccessRules {
61
- create : Some (
62
- "(SELECT 1 FROM room_members AS m WHERE _USER_.id = _REQ_._owner AND m.user = _USER_.id AND m.room = _REQ_.room)" . to_string ( ) ,
63
- ) ,
64
- ..Default :: default ( )
65
- } ,
66
- )
67
- . await . unwrap ( ) ;
62
+ & state,
63
+ "messages_api" ,
64
+ "message" ,
65
+ Acls {
66
+ authenticated : vec ! [ PermissionFlag :: Create , PermissionFlag :: Read ] ,
67
+ ..Default :: default ( )
68
+ } ,
69
+ AccessRules {
70
+ create : Some (
71
+ "(SELECT 1 FROM room_members AS m WHERE _USER_.id = _REQ_._owner AND m.user = _USER_.id AND m.room = _REQ_.room)" . to_string ( ) ,
72
+ ) ,
73
+ ..Default :: default ( )
74
+ } ,
75
+ )
76
+ . await . unwrap ( ) ;
68
77
69
78
let user_x_email =
"[email protected] " ;
70
79
let user_x = create_user_for_test ( & state, user_x_email, password)
71
- . await . unwrap ( )
80
+ . await
81
+ . unwrap ( )
72
82
. into_bytes ( ) ;
73
83
74
- let user_x_token = login_with_password ( & state, user_x_email, password) . await . unwrap ( ) ;
84
+ let user_x_token = login_with_password ( & state, user_x_email, password)
85
+ . await
86
+ . unwrap ( ) ;
75
87
76
88
add_user_to_room ( conn, user_x, room) . await . unwrap ( ) ;
77
89
78
- let server = TestServer :: new ( app. router ( ) . clone ( ) ) . unwrap ( ) ;
79
-
80
- {
81
- // User X can post to a JSON message.
82
- let test_response = server
83
- . post ( & format ! ( "/{RECORD_API_PATH}/messages_api" ) )
84
- . add_cookie ( Cookie :: new (
85
- COOKIE_AUTH_TOKEN ,
86
- user_x_token. auth_token . clone ( ) ,
87
- ) )
88
- . json ( & serde_json:: json!( {
89
- "_owner" : id_to_b64( & user_x) ,
90
- "room" : id_to_b64( & room) ,
91
- "data" : "user_x message to room" ,
92
- } ) )
93
- . await ;
94
-
95
- assert_eq ! (
96
- test_response. status_code( ) ,
97
- StatusCode :: OK ,
98
- "{:?}" ,
99
- test_response
100
- ) ;
101
- }
90
+ // Set up logging
91
+ let filter = || {
92
+ filter:: Targets :: new ( )
93
+ . with_target ( "tower_http::trace::on_response" , LevelFilter :: DEBUG )
94
+ . with_target ( "tower_http::trace::on_request" , LevelFilter :: DEBUG )
95
+ . with_target ( "tower_http::trace::make_span" , LevelFilter :: DEBUG )
96
+ . with_default ( LevelFilter :: INFO )
97
+ } ;
98
+
99
+ // This declares **where** tracing is being logged to, e.g. stderr, file, sqlite.
100
+ let layer = tracing_subscriber:: registry ( )
101
+ . with ( trailbase_core:: logging:: SqliteLogLayer :: new ( app. state ( ) ) . with_filter ( filter ( ) ) ) ;
102
+
103
+ let _ = layer
104
+ . with (
105
+ tracing_subscriber:: fmt:: layer ( )
106
+ . compact ( )
107
+ . with_filter ( filter ( ) ) ,
108
+ )
109
+ . try_init ( ) ;
102
110
103
111
{
104
- // User X can post a form message.
105
- let test_response = server
106
- . post ( & format ! ( "/{RECORD_API_PATH}/messages_api" ) )
107
- . add_cookie ( Cookie :: new (
108
- COOKIE_AUTH_TOKEN ,
109
- user_x_token. auth_token . clone ( ) ,
110
- ) )
111
- . form ( & serde_json:: json!( {
112
- "_owner" : id_to_b64( & user_x) ,
113
- "room" : id_to_b64( & room) ,
114
- "data" : "user_x message to room" ,
115
- } ) )
116
- . await ;
117
-
118
- assert_eq ! ( test_response. status_code( ) , StatusCode :: OK ) ;
112
+ let server = TestServer :: new ( app. router ( ) . clone ( ) ) . unwrap ( ) ;
113
+
114
+ {
115
+ // User X can post to a JSON message.
116
+ let test_response = server
117
+ . post ( & format ! ( "/{RECORD_API_PATH}/messages_api" ) )
118
+ . add_header ( "X-Forwarded-For" , client_ip)
119
+ . add_cookie ( Cookie :: new (
120
+ COOKIE_AUTH_TOKEN ,
121
+ user_x_token. auth_token . clone ( ) ,
122
+ ) )
123
+ . json ( & serde_json:: json!( {
124
+ "_owner" : id_to_b64( & user_x) ,
125
+ "room" : id_to_b64( & room) ,
126
+ "data" : "user_x message to room" ,
127
+ } ) )
128
+ . await ;
129
+
130
+ assert_eq ! (
131
+ test_response. status_code( ) ,
132
+ StatusCode :: OK ,
133
+ "{:?}" ,
134
+ test_response
135
+ ) ;
136
+ }
137
+
138
+ {
139
+ // User X can post a form message.
140
+ let test_response = server
141
+ . post ( & format ! ( "/{RECORD_API_PATH}/messages_api" ) )
142
+ . add_cookie ( Cookie :: new (
143
+ COOKIE_AUTH_TOKEN ,
144
+ user_x_token. auth_token . clone ( ) ,
145
+ ) )
146
+ . form ( & serde_json:: json!( {
147
+ "_owner" : id_to_b64( & user_x) ,
148
+ "room" : id_to_b64( & room) ,
149
+ "data" : "user_x message to room" ,
150
+ } ) )
151
+ . await ;
152
+
153
+ assert_eq ! ( test_response. status_code( ) , StatusCode :: OK ) ;
154
+ }
155
+
156
+ {
157
+ // User X can post a multipart message.
158
+ let form = MultipartForm :: new ( )
159
+ . add_text ( "_owner" , id_to_b64 ( & user_x) )
160
+ . add_text ( "room" , id_to_b64 ( & room) )
161
+ . add_text ( "data" , "user_x message to room" ) ;
162
+
163
+ let test_response = server
164
+ . post ( & format ! ( "/{RECORD_API_PATH}/messages_api" ) )
165
+ . add_cookie ( Cookie :: new (
166
+ COOKIE_AUTH_TOKEN ,
167
+ user_x_token. auth_token . clone ( ) ,
168
+ ) )
169
+ . multipart ( form)
170
+ . await ;
171
+
172
+ assert_eq ! ( test_response. status_code( ) , StatusCode :: OK ) ;
173
+ }
174
+
175
+ {
176
+ // Add a second record API for the same table
177
+ add_record_api (
178
+ & state,
179
+ "messages_api_yolo" ,
180
+ "message" ,
181
+ Acls {
182
+ world : vec ! [ PermissionFlag :: Create , PermissionFlag :: Read ] ,
183
+ ..Default :: default ( )
184
+ } ,
185
+ AccessRules :: default ( ) ,
186
+ )
187
+ . await
188
+ . unwrap ( ) ;
189
+
190
+ // Anonymous can post to a JSON message (i.e. no credentials/tokens are attached).
191
+ let test_response = server
192
+ . post ( & format ! ( "/{RECORD_API_PATH}/messages_api_yolo" ) )
193
+ . json ( & serde_json:: json!( {
194
+ // NOTE: Id must be not null and a random id would violate foreign key constraint as
195
+ // defined by the `message` table.
196
+ "_owner" : id_to_b64( & user_x) ,
197
+ "room" : id_to_b64( & room) ,
198
+ "data" : "anonymous' message to room" ,
199
+ } ) )
200
+ . await ;
201
+
202
+ assert_eq ! (
203
+ test_response. status_code( ) ,
204
+ StatusCode :: OK ,
205
+ "{test_response:?}"
206
+ ) ;
207
+ }
119
208
}
120
209
121
- {
122
- // User X can post a multipart message.
123
- let form = MultipartForm :: new ( )
124
- . add_text ( "_owner" , id_to_b64 ( & user_x) )
125
- . add_text ( "room" , id_to_b64 ( & room) )
126
- . add_text ( "data" , "user_x message to room" ) ;
127
-
128
- let test_response = server
129
- . post ( & format ! ( "/{RECORD_API_PATH}/messages_api" ) )
130
- . add_cookie ( Cookie :: new (
131
- COOKIE_AUTH_TOKEN ,
132
- user_x_token. auth_token . clone ( ) ,
133
- ) )
134
- . multipart ( form)
135
- . await ;
136
-
137
- assert_eq ! ( test_response. status_code( ) , StatusCode :: OK ) ;
138
- }
210
+ let logs_count: i64 = logs_conn
211
+ . query_row ( "SELECT COUNT(*) FROM _logs" , ( ) )
212
+ . await
213
+ . unwrap ( )
214
+ . unwrap ( )
215
+ . get ( 0 )
216
+ . unwrap ( ) ;
217
+ assert ! ( logs_count > 0 ) ;
139
218
140
- {
141
- // Add a second record API for the same table
142
- add_record_api (
143
- & state,
144
- "messages_api_yolo" ,
145
- "message" ,
146
- Acls {
147
- world : vec ! [ PermissionFlag :: Create , PermissionFlag :: Read ] ,
148
- ..Default :: default ( )
149
- } ,
150
- AccessRules :: default ( ) ,
219
+ let row = logs_conn
220
+ . query_row (
221
+ "SELECT client_ip FROM _logs WHERE client_ip = $1" ,
222
+ trailbase_sqlite:: params!( client_ip) ,
151
223
)
152
- . await . unwrap ( ) ;
153
-
154
- // Anonymous can post to a JSON message (i.e. no credentials/tokens are attached).
155
- let test_response = server
156
- . post ( & format ! ( "/{RECORD_API_PATH}/messages_api_yolo" ) )
157
- . json ( & serde_json:: json!( {
158
- // NOTE: Id must be not null and a random id would violate foreign key constraint as
159
- // defined by the `message` table.
160
- // "_owner": id_to_b64(&Uuid::now_v7().into_bytes()),
161
- "_owner" : id_to_b64( & user_x) ,
162
- "room" : id_to_b64( & room) ,
163
- "data" : "anonymous' message to room" ,
164
- } ) )
165
- . await ;
166
-
167
- assert_eq ! (
168
- test_response. status_code( ) ,
169
- StatusCode :: OK ,
170
- "{test_response:?}"
171
- ) ;
172
- }
224
+ . await
225
+ . unwrap ( )
226
+ . unwrap ( ) ;
173
227
174
- } ) ;
228
+ assert_eq ! ( row . get :: < String > ( 0 ) . unwrap ( ) , client_ip ) ;
175
229
}
176
230
177
231
pub async fn create_chat_message_app_tables (
0 commit comments