20
20
-include_lib (" escalus/include/escalus_xmlns.hrl" ).
21
21
-include_lib (" exml/include/exml.hrl" ).
22
22
-include_lib (" eunit/include/eunit.hrl" ).
23
+ -include_lib (" jid/include/jid.hrl" ).
24
+ % % Import LOCATION macro
25
+ -include_lib (" kernel/include/logger.hrl" ).
23
26
24
27
-import (config_parser_helper , [mod_config_with_auto_backend /2 ]).
25
28
29
32
30
33
all () ->
31
34
[{group , valid_queries },
32
- {group , invalid_queries }].
35
+ {group , invalid_queries },
36
+ {group , sessions_cleanup }].
33
37
34
38
groups () ->
35
39
[{valid_queries , [sequence ], valid_test_cases ()},
36
- {invalid_queries , invalid_test_cases ()}].
40
+ {invalid_queries , invalid_test_cases ()},
41
+ {sessions_cleanup , [], [sessions_cleanup ]}].
37
42
38
43
valid_test_cases () -> [online_user_query ,
39
44
last_online_user ,
@@ -43,9 +48,11 @@ valid_test_cases() -> [online_user_query,
43
48
invalid_test_cases () -> [user_not_subscribed_receives_error ].
44
49
45
50
suite () ->
46
- escalus :suite ().
51
+ distributed_helper : require_rpc_nodes ([ mim , mim2 ]) ++ escalus :suite ().
47
52
48
53
init_per_suite (Config0 ) ->
54
+ mongoose_helper :inject_module (distributed_helper :mim2 (), ? MODULE , reload ),
55
+ distributed_helper :add_node_to_cluster (distributed_helper :mim2 (), Config0 ),
49
56
HostType = domain_helper :host_type (),
50
57
Config1 = dynamic_modules :save_modules (HostType , Config0 ),
51
58
dynamic_modules :ensure_modules (HostType , required_modules ()),
@@ -68,6 +75,8 @@ init_per_group(valid_queries, Config0) ->
68
75
mongoose_helper :kick_everyone (),
69
76
Config2 ;
70
77
init_per_group (invalid_queries , Config ) ->
78
+ Config ;
79
+ init_per_group (sessions_cleanup , Config ) ->
71
80
Config .
72
81
73
82
end_per_group (_GroupName , _Config ) ->
@@ -170,41 +179,83 @@ user_not_subscribed_receives_error(Config) ->
170
179
ok
171
180
end ).
172
181
173
- % % This test is disabled on CI, because it puts the system in an inconsistent state.
174
- % % The sessions are created with Pids from the test node, which is incorrect.
175
- % % This incorrectly generates 'sm_session' events, leading to inconsistent session count metrics.
182
+ % % Runs sessions_cleanup and check if it was done by checking last_seen timestamp.
176
183
sessions_cleanup (_Config ) ->
177
- N = distributed_helper :mim (),
184
+ % % 345 would test 3 types of insert queries (insert 1, 10, 100).
185
+ % % For load testing, increase NumberOfUsers to big number like 500000
186
+ % % and check "node cleanup" time.
187
+ NumberOfUsers = 345 ,
188
+ Node1 = distributed_helper :mim (),
189
+ Node2 = distributed_helper :mim2 (),
190
+ #{node := Node2Atom } = Node2 ,
191
+ LongNode1 = Node1 #{timeout => timer :minutes (1 )},
192
+ LongNode2 = Node2 #{timeout => timer :minutes (1 )},
178
193
HostType = domain_helper :host_type (),
179
194
Server = domain_helper :domain (),
180
- CreateUser = fun (Name ) ->
181
- SID = {erlang :system_time (microsecond ), spawn (fun () -> ok end )},
182
- JID = mongoose_helper :make_jid (Name , Server , <<" res" >>),
183
- Priority = 0 ,
184
- Info = #{},
185
- distributed_helper :rpc (N , ejabberd_sm , open_session , [HostType , SID , JID , Priority , Info ])
186
- end ,
187
- Names = [<<" user" , (list_to_binary ((integer_to_list (X ))))/binary >> || X <- lists :seq (1 , 345 )],
188
- measure (" create users" , fun () ->
189
- lists :foreach (CreateUser , Names )
195
+ OldTS = 1714000000 ,
196
+ Jid3 = create_user_and_set_lastseen (Node1 , Server , <<" user3" >>, OldTS ),
197
+ Sessions = measure (" create users" , fun () ->
198
+ distributed_helper :rpc (LongNode2 , ? MODULE , create_sessions ,
199
+ [HostType , Server , NumberOfUsers ])
190
200
end ),
191
- % % Check that user3 is properly updated
192
- % % User should be registered if we want to use mod_last_api
193
- {ok , _ } = distributed_helper :rpc (N , mongoose_account_api , register_user , [<<" user3" >>, Server , <<" secret123" >>]),
194
- Jid3 = mongoose_helper :make_jid (<<" user3" >>, Server , <<>>),
195
- {ok , _ } = distributed_helper :rpc (N , mod_last_api , set_last , [Jid3 , 1714000000 , <<" old status" >>]),
196
- {ok , #{timestamp := 1714000000 }} = distributed_helper :rpc (N , mod_last_api , get_last , [Jid3 ]),
201
+ NumberOfUsers = length (Sessions ),
197
202
measure (" node cleanup" , fun () ->
198
- distributed_helper :rpc (N #{timeout => timer :minutes (1 )}, mongoose_hooks , node_cleanup , [node ()])
203
+ Res = distributed_helper :rpc (LongNode1 , mongoose_hooks ,
204
+ node_cleanup , [Node2Atom ]),
205
+ ct :pal (" node_cleanup result ~p " , [Res ])
199
206
end ),
200
- {ok , #{timestamp := TS , status := Status } = Data } = distributed_helper :rpc (N , mod_last_api , get_last , [Jid3 ]),
201
- ? assertNotEqual (TS , 1714000000 , Data ),
207
+ {ok , #{timestamp := TS , status := Status } = Data } =
208
+ distributed_helper :rpc (Node1 , mod_last_api , get_last , [Jid3 ]),
209
+ ? assertNotEqual (TS , OldTS , Data ),
202
210
? assertEqual (Status , <<>>, Data ),
203
- {ok , _ } = distributed_helper :rpc (N , mongoose_account_api , unregister_user , [<<" user3" >>, Server ]).
211
+ {ok , _ } = distributed_helper :rpc (Node1 , mongoose_account_api , unregister_user ,
212
+ [<<" user3" >>, Server ]),
213
+ measure (" close sessions" , fun () ->
214
+ distributed_helper :rpc (LongNode2 , ? MODULE , close_sessions ,
215
+ [HostType , Sessions ])
216
+ end ).
204
217
205
218
% %-----------------------------------------------------------------
206
219
% % Helpers
207
220
% %-----------------------------------------------------------------
221
+
222
+ create_sessions (HostType , Server , NumberOfUsers ) ->
223
+ [create_session (HostType , Server , Num )
224
+ || Num <- lists :seq (1 , NumberOfUsers )].
225
+
226
+ close_sessions (HostType , Sessions ) ->
227
+ lists :foreach (fun (Session ) -> close_session (HostType , Session ) end , Sessions ).
228
+
229
+ create_session (HostType , Server , Num ) ->
230
+ Name = <<" user" , (list_to_binary ((integer_to_list (Num ))))/binary >>,
231
+ SID = {erlang :system_time (microsecond ), spawn (fun () -> ok end )},
232
+ JID = jid :make (Name , Server , <<" res" >>),
233
+ Priority = 0 ,
234
+ Info = #{},
235
+ ejabberd_sm :open_session (HostType , SID , JID , Priority , Info ),
236
+ #{sid => SID , jid => JID }.
237
+
238
+ close_session (HostType , #{sid := SID , jid := JID }) ->
239
+ # jid {lserver = LServer } = JID ,
240
+ Reason = normal ,
241
+ Acc = mongoose_acc :new (#{location => ? LOCATION ,
242
+ host_type => HostType ,
243
+ lserver => LServer }),
244
+ Info = #{},
245
+ ejabberd_sm :close_session (Acc , SID , JID , Reason , Info ).
246
+
247
+ create_user_and_set_lastseen (Node , Server , User , TS ) ->
248
+ Jid = mongoose_helper :make_jid (User , Server , <<>>),
249
+ % % User should be registered if we want to use mod_last_api
250
+ % % Check that user3's last seen timestamp is properly updated
251
+ {ok , _ } = distributed_helper :rpc (Node , mongoose_account_api , register_user ,
252
+ [User , Server , <<" secret123" >>]),
253
+ {ok , _ } = distributed_helper :rpc (Node , mod_last_api , set_last ,
254
+ [Jid , TS , <<" old status" >>]),
255
+ {ok , #{timestamp := TS }} =
256
+ distributed_helper :rpc (Node , mod_last_api , get_last , [Jid ]),
257
+ Jid .
258
+
208
259
get_last_activity (Stanza ) ->
209
260
S = exml_query :path (Stanza , [{element , <<" query" >>}, {attr , <<" seconds" >>}]),
210
261
list_to_integer (binary_to_list (S )).
@@ -227,6 +278,6 @@ required_modules() ->
227
278
[{mod_last , mod_config_with_auto_backend (mod_last , #{iqdisc => one_queue })}].
228
279
229
280
measure (Text , F ) ->
230
- {Time , _ } = timer :tc (F ),
281
+ {Time , Val } = timer :tc (F ),
231
282
ct :pal (" Time ~ts = ~p " , [Text , Time ]),
232
- ok .
283
+ Val .
0 commit comments