1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20-module(gen_event_SUITE).
21
22-include_lib("common_test/include/ct.hrl").
23
24-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
25	 init_per_group/2,end_per_group/2, init_per_testcase/2,
26         end_per_testcase/2]).
27-export([start/1, add_handler/1, add_sup_handler/1,
28	 delete_handler/1, swap_handler/1, swap_sup_handler/1,
29	 notify/1, sync_notify/1, call/1, info/1, hibernate/1, auto_hibernate/1,
30	 call_format_status/1, call_format_status_anon/1,
31         error_format_status/1, get_state/1, replace_state/1,
32         start_opt/1,
33         undef_init/1, undef_handle_call/1, undef_handle_event/1,
34         undef_handle_info/1, undef_code_change/1, undef_terminate/1,
35         undef_in_terminate/1, format_log_1/1, format_log_2/1]).
36
37suite() -> [{ct_hooks,[ts_install_cth]}].
38
39all() ->
40    [start, {group, test_all}, hibernate, auto_hibernate,
41     call_format_status, call_format_status_anon, error_format_status,
42     get_state, replace_state,
43     start_opt, {group, undef_callbacks}, undef_in_terminate,
44     format_log_1, format_log_2].
45
46groups() ->
47    [{test_all, [],
48      [add_handler, add_sup_handler, delete_handler,
49       swap_handler, swap_sup_handler, notify, sync_notify,
50       call, info]},
51     {undef_callbacks, [],
52      [undef_init, undef_handle_call, undef_handle_event, undef_handle_info,
53       undef_code_change, undef_terminate]}].
54
55init_per_suite(Config) ->
56    Config.
57
58end_per_suite(_Config) ->
59    ok.
60
61init_per_group(undef_callbacks, Config) ->
62    DataDir = ?config(data_dir, Config),
63    Event1 = filename:join(DataDir, "oc_event.erl"),
64    {ok, oc_event} = compile:file(Event1),
65    Config;
66init_per_group(_GroupName, Config) ->
67    Config.
68
69end_per_group(_GroupName, Config) ->
70    Config.
71
72init_per_testcase(Case, Config) when Case == undef_handle_call;
73                                     Case == undef_handle_info;
74                                     Case == undef_handle_event;
75                                     Case == undef_code_change;
76                                     Case == undef_terminate ->
77    {ok, Pid} = oc_event:start(),
78    [{event_pid, Pid}|Config];
79init_per_testcase(undef_init, Config) ->
80    {ok, Pid} = gen_event:start({local, oc_init_event}),
81    [{event_pid, Pid}|Config];
82init_per_testcase(_Case, Config) ->
83    Config.
84
85end_per_testcase(Case, Config) when Case == undef_init;
86                                    Case == undef_handle_call;
87                                    Case == undef_handle_info;
88                                    Case == undef_handle_event;
89                                    Case == undef_code_change;
90                                    Case == undef_terminate ->
91    Pid = ?config(event_pid, Config),
92    gen_event:stop(Pid);
93end_per_testcase(_Case, _Config) ->
94    ok.
95
96%% --------------------------------------
97%% Start an event manager.
98%% --------------------------------------
99
100-define(LMGR, {local, my_dummy_name}).
101-define(GMGR, {global, my_dummy_name}).
102
103start(Config) when is_list(Config) ->
104    OldFl = process_flag(trap_exit, true),
105
106    dummy_via:reset(),
107
108    {ok, Pid0} = gen_event:start(), %anonymous
109    [] = gen_event:which_handlers(Pid0),
110    ok = gen_event:stop(Pid0),
111
112    {ok, Pid1} = gen_event:start_link(), %anonymous
113    [] = gen_event:which_handlers(Pid1),
114    ok = gen_event:stop(Pid1),
115
116    {ok, {Pid1b,Mon1b}} = gen_event:start_monitor(), %anonymous
117    [] = gen_event:which_handlers(Pid1b),
118    ok = gen_event:stop(Pid1b),
119    receive {'DOWN',Mon1b,process,Pid1b,_} -> ok end,
120
121    {ok, Pid2} = gen_event:start(?LMGR),
122    [] = gen_event:which_handlers(my_dummy_name),
123    [] = gen_event:which_handlers(Pid2),
124    ok = gen_event:stop(my_dummy_name),
125
126    {ok, Pid3} = gen_event:start_link(?LMGR),
127    [] = gen_event:which_handlers(my_dummy_name),
128    [] = gen_event:which_handlers(Pid3),
129    ok = gen_event:stop(my_dummy_name),
130
131    {ok, {Pid3b,Mon3b}} = gen_event:start_monitor(?LMGR),
132    [] = gen_event:which_handlers(my_dummy_name),
133    [] = gen_event:which_handlers(Pid3b),
134    ok = gen_event:stop(my_dummy_name),
135    receive {'DOWN',Mon3b,process,Pid3b,_} -> ok end,
136
137    {ok, Pid4} = gen_event:start_link(?GMGR),
138    [] = gen_event:which_handlers(?GMGR),
139    [] = gen_event:which_handlers(Pid4),
140    ok = gen_event:stop(?GMGR),
141
142    {ok, {Pid4b,Mon4b}} = gen_event:start_monitor(?GMGR),
143    [] = gen_event:which_handlers(?GMGR),
144    [] = gen_event:which_handlers(Pid4b),
145    ok = gen_event:stop(?GMGR),
146    receive {'DOWN',Mon4b,process,Pid4b,_} -> ok end,
147
148    {ok, Pid5} = gen_event:start_link({via, dummy_via, my_dummy_name}),
149    [] = gen_event:which_handlers({via, dummy_via, my_dummy_name}),
150    [] = gen_event:which_handlers(Pid5),
151    ok = gen_event:stop({via, dummy_via, my_dummy_name}),
152
153    {ok, {Pid5b,Mon5b}} = gen_event:start_monitor({via, dummy_via, my_dummy_name}),
154    [] = gen_event:which_handlers({via, dummy_via, my_dummy_name}),
155    [] = gen_event:which_handlers(Pid5b),
156    ok = gen_event:stop({via, dummy_via, my_dummy_name}),
157    receive {'DOWN',Mon5b,process,Pid5b,_} -> ok end,
158
159    {ok, _} = gen_event:start_link(?LMGR),
160    {error, {already_started, _}} = gen_event:start_link(?LMGR),
161    {error, {already_started, _}} = gen_event:start(?LMGR),
162    ok = gen_event:stop(my_dummy_name),
163
164    {ok, {Pid5c,Mon5c}} = gen_event:start_monitor(?LMGR),
165    {error, {already_started, Pid5c}} = gen_event:start_monitor(?LMGR),
166    {error, {already_started, Pid5c}} = gen_event:start(?LMGR),
167    ok = gen_event:stop(my_dummy_name),
168    receive {'DOWN',Mon5c,process,Pid5c,_} -> ok end,
169
170    {ok, Pid6} = gen_event:start_link(?GMGR),
171    {error, {already_started, _}} = gen_event:start_link(?GMGR),
172    {error, {already_started, _}} = gen_event:start(?GMGR),
173
174    ok = gen_event:stop(?GMGR, shutdown, 10000),
175    receive
176	{'EXIT', Pid6, shutdown} -> ok
177    after 10000 ->
178	    ct:fail(exit_gen_event)
179    end,
180
181    {ok, {Pid6b,Mon6b}} = gen_event:start_monitor(?GMGR),
182    {error, {already_started, _}} = gen_event:start_monitor(?GMGR),
183    {error, {already_started, _}} = gen_event:start(?GMGR),
184
185    ok = gen_event:stop(?GMGR, shutdown, 10000),
186    receive
187	{'DOWN', Mon6b, process, Pid6b, shutdown} -> ok
188    after 10000 ->
189	    ct:fail(exit_gen_event)
190    end,
191
192    {ok, Pid7} = gen_event:start_link({via, dummy_via, my_dummy_name}),
193    {error, {already_started, _}} = gen_event:start_link({via, dummy_via, my_dummy_name}),
194    {error, {already_started, _}} = gen_event:start({via, dummy_via, my_dummy_name}),
195
196    exit(Pid7, shutdown),
197    receive
198	{'EXIT', Pid7, shutdown} -> ok
199    after 10000 ->
200	    ct:fail(exit_gen_event)
201    end,
202
203    {ok, {Pid7b,Mon7b}} = gen_event:start_monitor({via, dummy_via, my_dummy_name}),
204    {error, {already_started, _}} = gen_event:start_monitor({via, dummy_via, my_dummy_name}),
205    {error, {already_started, _}} = gen_event:start({via, dummy_via, my_dummy_name}),
206
207    exit(Pid7b, shutdown),
208    receive
209	{'DOWN', Mon7b, process, Pid7b, shutdown} -> ok
210    after 10000 ->
211	    ct:fail(exit_gen_event)
212    end,
213
214    process_flag(trap_exit, OldFl),
215    ok.
216
217start_opt(Config) when is_list(Config) ->
218    OldFl = process_flag(trap_exit, true),
219
220    dummy_via:reset(),
221
222    {ok, Pid0} = gen_event:start([]), %anonymous
223    [] = gen_event:which_handlers(Pid0),
224    ok = gen_event:stop(Pid0),
225
226    {ok, Pid1} = gen_event:start_link([]), %anonymous
227    [] = gen_event:which_handlers(Pid1),
228    ok = gen_event:stop(Pid1),
229
230    {ok, Pid2} = gen_event:start(?LMGR, []),
231    [] = gen_event:which_handlers(my_dummy_name),
232    [] = gen_event:which_handlers(Pid2),
233    ok = gen_event:stop(my_dummy_name),
234
235    {ok, Pid3} = gen_event:start_link(?LMGR, []),
236    [] = gen_event:which_handlers(my_dummy_name),
237    [] = gen_event:which_handlers(Pid3),
238    ok = gen_event:stop(my_dummy_name),
239
240    {ok, Pid4} = gen_event:start_link(?GMGR, []),
241    [] = gen_event:which_handlers(?GMGR),
242    [] = gen_event:which_handlers(Pid4),
243    ok = gen_event:stop(?GMGR),
244
245    {ok, Pid5} = gen_event:start_link({via, dummy_via, my_dummy_name}, []),
246    [] = gen_event:which_handlers({via, dummy_via, my_dummy_name}),
247    [] = gen_event:which_handlers(Pid5),
248    ok = gen_event:stop({via, dummy_via, my_dummy_name}),
249
250    {ok, _} = gen_event:start_link(?LMGR, []),
251    {error, {already_started, _}} = gen_event:start_link(?LMGR, []),
252    {error, {already_started, _}} = gen_event:start(?LMGR, []),
253    ok = gen_event:stop(my_dummy_name),
254
255    {ok, Pid7} = gen_event:start_link(?GMGR),
256    {error, {already_started, _}} = gen_event:start_link(?GMGR, []),
257    {error, {already_started, _}} = gen_event:start(?GMGR, []),
258
259    ok = gen_event:stop(?GMGR, shutdown, 10000),
260    receive
261	{'EXIT', Pid7, shutdown} -> ok
262    after 10000 ->
263	    ct:fail(exit_gen_event)
264    end,
265
266    {ok, Pid8} = gen_event:start_link({via, dummy_via, my_dummy_name}),
267    {error, {already_started, _}} = gen_event:start_link({via, dummy_via, my_dummy_name}, []),
268    {error, {already_started, _}} = gen_event:start({via, dummy_via, my_dummy_name}, []),
269
270    exit(Pid8, shutdown),
271    receive
272	{'EXIT', Pid8, shutdown} -> ok
273    after 10000 ->
274	    ct:fail(exit_gen_event)
275    end,
276
277    %% test spawn_opt
278    MinHeapSz = 10000,
279    {ok, Pid9} = gen_event:start_link(?LMGR, [{spawn_opt, [{min_heap_size, MinHeapSz}]}]),
280    {error, {already_started, _}} = gen_event:start_link(?LMGR, []),
281    {error, {already_started, _}} = gen_event:start(?LMGR, []),
282    {heap_size, HeapSz} = erlang:process_info(Pid9, heap_size),
283    true = HeapSz > MinHeapSz,
284    ok = gen_event:stop(my_dummy_name),
285
286    %% test debug opt
287    {ok, _} = gen_event:start_link(?LMGR, [{debug,[debug]}]),
288    {error, {already_started, _}} = gen_event:start_link(?LMGR, []),
289    {error, {already_started, _}} = gen_event:start(?LMGR, []),
290    ok = gen_event:stop(my_dummy_name),
291
292    process_flag(trap_exit, OldFl),
293    ok.
294
295hibernate(Config) when is_list(Config) ->
296    {ok,Pid} = gen_event:start({local, my_dummy_handler}),
297    ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
298    [dummy_h] = gen_event:which_handlers(my_dummy_handler),
299    true = gen_event:call(my_dummy_handler, dummy_h, hibernate),
300    is_in_erlang_hibernate(Pid),
301
302    Pid ! wake,
303    is_not_in_erlang_hibernate(Pid),
304    later = gen_event:call(my_dummy_handler, dummy_h, hibernate_later),
305    true = ({current_function,{erlang,hibernate,3}} =/=
306		erlang:process_info(Pid, current_function)),
307    is_in_erlang_hibernate(Pid),
308
309    Pid ! wake,
310    is_not_in_erlang_hibernate(Pid),
311    gen_event:notify(my_dummy_handler, hibernate),
312    is_in_erlang_hibernate(Pid),
313    gen_event:notify(my_dummy_handler, wakeup),
314    is_not_in_erlang_hibernate(Pid),
315    gen_event:notify(my_dummy_handler, hibernate),
316    is_in_erlang_hibernate(Pid),
317    gen_event:sync_notify(my_dummy_handler, wakeup),
318    true = ({current_function,{erlang,hibernate,3}} =/=
319		erlang:process_info(Pid, current_function)),
320    ok = gen_event:sync_notify(my_dummy_handler, hibernate),
321    is_in_erlang_hibernate(Pid),
322
323    Pid ! wake,
324    is_not_in_erlang_hibernate(Pid),
325    ok = gen_event:add_handler(my_dummy_handler, dummy1_h, [self()]),
326    [_,_] = gen_event:which_handlers(my_dummy_handler),
327    gen_event:notify(my_dummy_handler, hibernate),
328    is_in_erlang_hibernate(Pid),
329    gen_event:notify(my_dummy_handler, wakeup),
330    is_in_erlang_hibernate(Pid),
331
332    Pid ! wake,
333    is_not_in_erlang_hibernate(Pid),
334
335    Pid ! gnurf,
336    is_in_erlang_hibernate(Pid),
337
338    Pid ! sleep,
339    is_in_erlang_hibernate(Pid),
340
341    Pid ! wake,
342    is_not_in_erlang_hibernate(Pid),
343    ok = gen_event:stop(my_dummy_handler),
344
345    {ok,Pid2} = gen_event:start({local, my_dummy_handler}),
346    ok = gen_event:add_handler(my_dummy_handler, dummy_h,
347			       [self(),hibernate]),
348    is_in_erlang_hibernate(Pid2),
349    sys:suspend(my_dummy_handler),
350    is_in_erlang_hibernate(Pid2),
351    sys:resume(my_dummy_handler),
352    is_in_erlang_hibernate(Pid2),
353
354    Pid2 ! wake,
355    is_not_in_erlang_hibernate(Pid2),
356
357    ok = gen_event:stop(my_dummy_handler),
358
359    ok.
360
361auto_hibernate(Config) when is_list(Config) ->
362    HibernateAfterTimeout = 100,
363    State = {auto_hibernate_state},
364    {ok,Pid} = gen_event:start({local, auto_hibernate_handler}, [{hibernate_after, HibernateAfterTimeout}]),
365    %% After init test
366    is_not_in_erlang_hibernate(Pid),
367    timer:sleep(HibernateAfterTimeout),
368    is_in_erlang_hibernate(Pid),
369    ok = gen_event:add_handler(auto_hibernate_handler, dummy_h, [State]),
370    %% Get state test
371    [{dummy_h,false,State}] = sys:get_state(Pid),
372    is_in_erlang_hibernate(Pid),
373    %% Call test
374    {ok, hejhopp} = gen_event:call(auto_hibernate_handler, dummy_h, hejsan),
375    is_not_in_erlang_hibernate(Pid),
376    timer:sleep(HibernateAfterTimeout),
377    is_in_erlang_hibernate(Pid),
378    %% Event test
379    ok = gen_event:notify(auto_hibernate_handler, {self(), handle_event}),
380    receive
381        handled_event ->
382            ok
383    after 1000 ->
384        ct:fail(event)
385    end,
386    is_not_in_erlang_hibernate(Pid),
387    timer:sleep(HibernateAfterTimeout),
388    is_in_erlang_hibernate(Pid),
389    %% Info test
390    Pid ! {self(), handle_info},
391    receive
392        handled_info ->
393            ok
394    after 1000 ->
395        ct:fail(info)
396    end,
397    is_not_in_erlang_hibernate(Pid),
398    timer:sleep(HibernateAfterTimeout),
399    is_in_erlang_hibernate(Pid),
400    ok = gen_event:stop(auto_hibernate_handler),
401    ok.
402
403is_in_erlang_hibernate(Pid) ->
404    receive after 1 -> ok end,
405    is_in_erlang_hibernate_1(200, Pid).
406
407is_in_erlang_hibernate_1(0, Pid) ->
408    io:format("~p\n", [erlang:process_info(Pid, current_function)]),
409    ct:fail(not_in_erlang_hibernate_3);
410is_in_erlang_hibernate_1(N, Pid) ->
411    {current_function,MFA} = erlang:process_info(Pid, current_function),
412    case MFA of
413	{erlang,hibernate,3} ->
414	    ok;
415	_ ->
416	    receive after 10 -> ok end,
417	    is_in_erlang_hibernate_1(N-1, Pid)
418    end.
419
420is_not_in_erlang_hibernate(Pid) ->
421    receive after 1 -> ok end,
422    is_not_in_erlang_hibernate_1(200, Pid).
423
424is_not_in_erlang_hibernate_1(0, Pid) ->
425    io:format("~p\n", [erlang:process_info(Pid, current_function)]),
426    ct:fail(not_in_erlang_hibernate_3);
427is_not_in_erlang_hibernate_1(N, Pid) ->
428    {current_function,MFA} = erlang:process_info(Pid, current_function),
429    case MFA of
430	{erlang,hibernate,3} ->
431	    receive after 10 -> ok end,
432	    is_not_in_erlang_hibernate_1(N-1, Pid);
433	_ ->
434	    ok
435    end.
436
437
438add_handler(Config) when is_list(Config) ->
439    {ok,_} = gen_event:start({local, my_dummy_handler}),
440    {error, my_error} =
441	gen_event:add_handler(my_dummy_handler, dummy_h, make_error),
442    [] = gen_event:which_handlers(my_dummy_handler),
443    ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
444    [dummy_h] = gen_event:which_handlers(my_dummy_handler),
445
446    {error, my_error} =
447	gen_event:add_handler(my_dummy_handler, {dummy_h, self()}, make_error),
448    [dummy_h] = gen_event:which_handlers(my_dummy_handler),
449    ok = gen_event:add_handler(my_dummy_handler, {dummy_h,self()},
450			       [self()]),
451    Self = self(),
452    [{dummy_h, Self}, dummy_h] =
453	gen_event:which_handlers(my_dummy_handler),
454    ok = gen_event:stop(my_dummy_handler),
455    ok.
456
457add_sup_handler(Config) when is_list(Config) ->
458    {ok,Pid} = gen_event:start({local, my_dummy_handler}),
459    {error, my_error} =
460	gen_event:add_sup_handler(my_dummy_handler, dummy_h, make_error),
461    [] = gen_event:which_handlers(my_dummy_handler),
462    ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
463    [dummy_h] = gen_event:which_handlers(my_dummy_handler),
464    exit(Pid, sup_died),
465    ct:sleep(1000),
466    [] = gen_event:which_handlers(my_dummy_handler),
467
468    ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
469    [dummy_h] = gen_event:which_handlers(my_dummy_handler),
470
471    {error, my_error} =
472	gen_event:add_handler(my_dummy_handler, {dummy_h, self()}, make_error),
473    [dummy_h] = gen_event:which_handlers(my_dummy_handler),
474    ok = gen_event:add_sup_handler(my_dummy_handler, {dummy_h,self()},
475				   [self()]),
476    Self = self(),
477    [{dummy_h, Self}, dummy_h] =
478	gen_event:which_handlers(my_dummy_handler),
479    ok = gen_event:stop(my_dummy_handler),
480
481    receive
482	{gen_event_EXIT, dummy_h, shutdown} ->
483	    ok
484    after 1000 ->
485	    ct:fail({no,{gen_event_EXIT, dummy_h, shutdown}})
486    end,
487
488    receive
489	{gen_event_EXIT, {dummy_h,Self}, shutdown} ->
490	    ok
491    after 1000 ->
492	    ct:fail({no,{gen_event_EXIT, {dummy_h,Self},
493			 shutdown}})
494    end,
495    ok.
496
497delete_handler(Config) when is_list(Config) ->
498    {ok,_} = gen_event:start({local, my_dummy_handler}),
499    ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
500    {error, module_not_found} =
501	gen_event:delete_handler(my_dummy_handler, duuuuuuuuumy, []),
502    return_hej =
503	gen_event:delete_handler(my_dummy_handler, dummy_h, return_hej),
504    [] = gen_event:which_handlers(my_dummy_handler),
505    ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
506    ok =
507	gen_event:delete_handler(my_dummy_handler, dummy_h, []),
508    [] = gen_event:which_handlers(my_dummy_handler),
509
510    ok = gen_event:add_handler(my_dummy_handler, {dummy_h,1}, [self()]),
511    ok = gen_event:add_handler(my_dummy_handler, {dummy_h,2}, [self()]),
512    {error, module_not_found} =
513	gen_event:delete_handler(my_dummy_handler, {duuuuuuuuumy,1}, []),
514    return_hej =
515	gen_event:delete_handler(my_dummy_handler, {dummy_h,1}, return_hej),
516    return_hej =
517	gen_event:delete_handler(my_dummy_handler, {dummy_h,2}, return_hej),
518    [] = gen_event:which_handlers(my_dummy_handler),
519    ok = gen_event:add_handler(my_dummy_handler, {dummy_h,2}, [self()]),
520    ok =
521	gen_event:delete_handler(my_dummy_handler, {dummy_h,2}, []),
522    [] = gen_event:which_handlers(my_dummy_handler),
523
524    ok = gen_event:stop(my_dummy_handler),
525    ok.
526
527swap_handler(Config) when is_list(Config) ->
528    {ok,_} = gen_event:start({local, my_dummy_handler}),
529    ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
530    {error, non_existing} =
531	gen_event:swap_handler(my_dummy_handler, {faulty_h, swap},
532			       {dummy1_h, []}),
533    ok =
534	gen_event:swap_handler(my_dummy_handler, {dummy_h, swap},
535			       {dummy1_h, swap}),
536    [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
537
538    ok = gen_event:delete_handler(my_dummy_handler, dummy1_h, []),
539
540    ok = gen_event:add_handler(my_dummy_handler, {dummy_h,3}, [self()]),
541    {error, non_existing} =
542	gen_event:swap_handler(my_dummy_handler, {faulty_h, swap},
543			       {dummy1_h, []}),
544    ok =
545	gen_event:swap_handler(my_dummy_handler, {{dummy_h,3}, swap},
546			       {{dummy1_h,4}, swap}),
547    [{dummy1_h,4}] = gen_event:which_handlers(my_dummy_handler),
548
549    ok = gen_event:delete_handler(my_dummy_handler, {dummy1_h,4}, []),
550
551    ok = gen_event:stop(my_dummy_handler),
552    ok.
553
554swap_sup_handler(Config) when is_list(Config) ->
555    {ok,_} = gen_event:start({local, my_dummy_handler}),
556    ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
557    {error, non_existing} =
558	gen_event:swap_handler(my_dummy_handler, {faulty_h, swap},
559			       {dummy1_h, []}),
560    ok =
561	gen_event:swap_handler(my_dummy_handler, {dummy_h, swap},
562			       {dummy1_h, swap}),
563    [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
564
565    ok = gen_event:delete_handler(my_dummy_handler, dummy1_h, []),
566    receive
567	{gen_event_EXIT, dummy1_h, normal} ->
568	    ok
569    after 1000 ->
570	    ct:fail({no,{gen_event_EXIT, dummy1_h, normal}})
571    end,
572
573    ok = gen_event:add_sup_handler(my_dummy_handler, {dummy_h,3},
574				   [self()]),
575    {error, non_existing} =
576	gen_event:swap_sup_handler(my_dummy_handler, {faulty_h, swap},
577				   {dummy1_h, []}),
578    ok =
579	gen_event:swap_sup_handler(my_dummy_handler, {{dummy_h,3}, swap},
580				   {{dummy1_h,4}, swap}),
581    [{dummy1_h,4}] = gen_event:which_handlers(my_dummy_handler),
582
583    ok = gen_event:delete_handler(my_dummy_handler, {dummy1_h,4}, []),
584    receive
585	{gen_event_EXIT, {dummy1_h,4}, normal} ->
586	    ok
587    after 1000 ->
588	    ct:fail({no,{gen_event_EXIT, {dummy1_h,4}, normal}})
589    end,
590
591    ok = gen_event:stop(my_dummy_handler),
592    ok.
593
594notify(Config) when is_list(Config) ->
595    {ok,_} = gen_event:start({local, my_dummy_handler}),
596    ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
597    Event = {event, self()},
598    [dummy_h] = gen_event:which_handlers(my_dummy_handler),
599    ok = gen_event:notify(my_dummy_handler, Event),
600    receive
601	{dummy_h, Event} ->
602	    ok
603    end,
604    ok = gen_event:notify(my_dummy_handler, {swap_event,dummy1_h,swap}),
605    [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
606    ok = gen_event:notify(my_dummy_handler, Event),
607    receive
608	{dummy1_h, Event} ->
609	    ok
610    end,
611    ok = gen_event:notify(my_dummy_handler, delete_event),
612    receive
613	{dummy1_h, removed} ->
614	    ok
615    end,
616    [] = gen_event:which_handlers(my_dummy_handler),
617    ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
618
619    ok = gen_event:notify(my_dummy_handler, error_event),
620    receive
621	{dummy_h, returned_error} ->
622	    ok
623    end,
624    [] = gen_event:which_handlers(my_dummy_handler),
625
626    %% Handler with id, {Mod,Id}
627
628    ok = gen_event:add_handler(my_dummy_handler, {dummy_h,5}, [self()]),
629    [{dummy_h,5}] = gen_event:which_handlers(my_dummy_handler),
630    ok = gen_event:notify(my_dummy_handler, Event),
631    receive
632	{dummy_h, Event} ->
633	    ok
634    end,
635    ok = gen_event:notify(my_dummy_handler,
636			  {swap_event, {dummy1_h, 9}, swap}),
637    [{dummy1_h,9}] = gen_event:which_handlers(my_dummy_handler),
638    ok = gen_event:notify(my_dummy_handler, Event),
639    receive
640	{dummy1_h, Event} ->
641	    ok
642    end,
643    ok = gen_event:notify(my_dummy_handler, delete_event),
644    receive
645	{dummy1_h, removed} ->
646	    ok
647    end,
648    [] = gen_event:which_handlers(my_dummy_handler),
649    ok = gen_event:add_handler(my_dummy_handler, {dummy_h,a}, [self()]),
650
651    ok = gen_event:notify(my_dummy_handler, error_event),
652    receive
653	{dummy_h, returned_error} ->
654	    ok
655    end,
656    [] = gen_event:which_handlers(my_dummy_handler),
657
658    %% Supervised handler.
659
660    ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
661    [dummy_h] = gen_event:which_handlers(my_dummy_handler),
662    ok = gen_event:notify(my_dummy_handler, Event),
663    receive
664	{dummy_h, Event} ->
665	    ok
666    end,
667
668    ok = gen_event:notify(my_dummy_handler, do_crash),
669    receive
670	{gen_event_EXIT, dummy_h, {'EXIT',_}} ->
671	    ok
672    end,
673
674    ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
675    ok = gen_event:notify(my_dummy_handler, {swap_event,dummy1_h,swap}),
676    [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
677
678    ok = gen_event:notify(my_dummy_handler, do_crash),
679    receive
680	{gen_event_EXIT, dummy1_h, {'EXIT',_}} ->
681	    ok
682    end,
683
684    ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
685    ok = gen_event:notify(my_dummy_handler, {swap_event,dummy1_h,swap}),
686    [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
687
688    ok = gen_event:notify(my_dummy_handler, delete_event),
689    receive
690	{dummy1_h, removed} ->
691	    ok
692    end,
693
694    receive
695	{gen_event_EXIT, dummy1_h, normal} ->
696	    ok
697    end,
698
699    [] = gen_event:which_handlers(my_dummy_handler),
700
701    ok = gen_event:stop(my_dummy_handler),
702    ok.
703
704sync_notify(Config) when is_list(Config) ->
705    {ok,_} = gen_event:start({local, my_dummy_handler}),
706    ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
707    Event = {event, self()},
708    [dummy_h] = gen_event:which_handlers(my_dummy_handler),
709    ok = gen_event:sync_notify(my_dummy_handler, Event),
710    receive
711	{dummy_h, Event} ->
712	    ok
713    end,
714    ok = gen_event:sync_notify(my_dummy_handler,
715			       {swap_event, dummy1_h, swap}),
716    [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
717    ok = gen_event:sync_notify(my_dummy_handler, Event),
718    receive
719	{dummy1_h, Event} ->
720	    ok
721    end,
722    ok = gen_event:sync_notify(my_dummy_handler, delete_event),
723    receive
724	{dummy1_h, removed} ->
725	    ok
726    end,
727    [] = gen_event:which_handlers(my_dummy_handler),
728    ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
729
730    ok = gen_event:sync_notify(my_dummy_handler, error_event),
731    receive
732	{dummy_h, returned_error} ->
733	    ok
734    end,
735    [] = gen_event:which_handlers(my_dummy_handler),
736
737    %% Handler with id, {Mod,Id}
738
739    ok = gen_event:add_handler(my_dummy_handler, {dummy_h,5}, [self()]),
740    [{dummy_h,5}] = gen_event:which_handlers(my_dummy_handler),
741    ok = gen_event:sync_notify(my_dummy_handler, Event),
742    receive
743	{dummy_h, Event} ->
744	    ok
745    end,
746    ok = gen_event:sync_notify(my_dummy_handler,
747			       {swap_event, {dummy1_h, 9}, swap}),
748    [{dummy1_h,9}] = gen_event:which_handlers(my_dummy_handler),
749    ok = gen_event:sync_notify(my_dummy_handler, Event),
750    receive
751	{dummy1_h, Event} ->
752	    ok
753    end,
754    ok = gen_event:sync_notify(my_dummy_handler, delete_event),
755    receive
756	{dummy1_h, removed} ->
757	    ok
758    end,
759    [] = gen_event:which_handlers(my_dummy_handler),
760    ok = gen_event:add_handler(my_dummy_handler, {dummy_h,a}, [self()]),
761
762    ok = gen_event:sync_notify(my_dummy_handler, error_event),
763    receive
764	{dummy_h, returned_error} ->
765	    ok
766    end,
767    [] = gen_event:which_handlers(my_dummy_handler),
768
769    %% Supervised handler.
770
771    ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
772    [dummy_h] = gen_event:which_handlers(my_dummy_handler),
773    ok = gen_event:sync_notify(my_dummy_handler, Event),
774    receive
775	{dummy_h, Event} ->
776	    ok
777    end,
778
779    ok = gen_event:sync_notify(my_dummy_handler, do_crash),
780    receive
781	{gen_event_EXIT, dummy_h, {'EXIT',_}} ->
782	    ok
783    end,
784
785    ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
786    ok = gen_event:sync_notify(my_dummy_handler,
787			       {swap_event,dummy1_h,swap}),
788    [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
789
790    ok = gen_event:sync_notify(my_dummy_handler, do_crash),
791    receive
792	{gen_event_EXIT, dummy1_h, {'EXIT',_}} ->
793	    ok
794    end,
795
796    ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
797    ok = gen_event:sync_notify(my_dummy_handler,
798			       {swap_event,dummy1_h,swap}),
799    [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
800
801    ok = gen_event:sync_notify(my_dummy_handler, delete_event),
802    receive
803	{dummy1_h, removed} ->
804	    ok
805    end,
806
807    receive
808	{gen_event_EXIT, dummy1_h, normal} ->
809	    ok
810    end,
811
812    [] = gen_event:which_handlers(my_dummy_handler),
813
814    ok = gen_event:stop(my_dummy_handler),
815    ok.
816
817call(Config) when is_list(Config) ->
818    Async = fun(Mgr,H,Req) ->
819                    try
820                        Promise = gen_event:send_request(Mgr,H,Req),
821                        gen_event:wait_response(Promise, infinity)
822                    catch _:Reason ->
823                            {'did_exit', Reason}
824                    end
825            end,
826    {ok,_} = gen_event:start({local, my_dummy_handler}),
827    ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
828    ok = gen_event:add_handler(my_dummy_handler, {dummy_h, 1}, [self()]),
829    [{dummy_h, 1}, dummy_h] = gen_event:which_handlers(my_dummy_handler),
830    {'EXIT',_} = (catch gen_event:call(non_exist, dummy_h, hejsan)),
831    {error, _} = Async(non_exist, dummy_h, hejsan),
832    {error, bad_module} = gen_event:call(my_dummy_handler, bad_h, hejsan),
833    {error, bad_module} = Async(my_dummy_handler, bad_h, hejsan),
834
835    {ok, hejhopp} = gen_event:call(my_dummy_handler, dummy_h, hejsan),
836    {reply, {ok, hejhopp}} = Async(my_dummy_handler, dummy_h, hejsan),
837    {ok, hejhopp} = gen_event:call(my_dummy_handler, {dummy_h, 1}, hejsan),
838    {reply, {ok, hejhopp}} = Async(my_dummy_handler, {dummy_h, 1}, hejsan),
839    {ok, hejhopp} = gen_event:call(my_dummy_handler, {dummy_h, 1}, hejsan),
840    {reply, {ok, hejhopp}} = Async(my_dummy_handler, {dummy_h, 1}, hejsan),
841    {ok, hejhopp} = gen_event:call(my_dummy_handler, dummy_h, hejsan, 10000),
842    {'EXIT', {timeout, _}} =
843	(catch gen_event:call(my_dummy_handler, dummy_h, hejsan, 0)),
844    flush(),
845    P1 = gen_event:send_request(my_dummy_handler, dummy_h, hejsan),
846    timeout = gen_event:wait_response(P1, 0),
847    {reply, {ok, hejhopp}} = gen_event:wait_response(P1, infinity),
848
849    flush(),
850    P2 = gen_event:send_request(my_dummy_handler, dummy_h, hejsan),
851    no_reply = gen_event:check_response({other,msg}, P2),
852    {reply, {ok, hejhopp}} = receive Msg -> gen_event:check_response(Msg, P2)
853                             after 1000 -> exit(tmo) end,
854
855    ok = gen_event:delete_handler(my_dummy_handler, {dummy_h, 1}, []),
856    {ok, swapped} = gen_event:call(my_dummy_handler, dummy_h,
857				   {swap_call,dummy1_h,swap}),
858    [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
859    {error, bad_module} = gen_event:call(my_dummy_handler, dummy_h, hejsan),
860    {error, bad_module} = Async(my_dummy_handler, dummy_h, hejsan),
861    ok = gen_event:call(my_dummy_handler, dummy1_h, delete_call),
862    receive
863	{dummy1_h, removed} ->
864	    ok
865    end,
866    [] = gen_event:which_handlers(my_dummy_handler),
867    ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
868
869    {error, {return, faulty}} =
870	gen_event:call(my_dummy_handler, dummy_h, error_call),
871    receive
872	{dummy_h, returned_error} ->
873	    ok
874    end,
875    [] = gen_event:which_handlers(my_dummy_handler),
876    ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
877
878    {error, {'EXIT', _}} =
879	gen_event:call(my_dummy_handler, dummy_h, exit_call),
880
881    [] = gen_event:which_handlers(my_dummy_handler),
882
883    %% Handler with id, {Mod,Id}
884
885    ok = gen_event:add_handler(my_dummy_handler, {dummy_h,1}, [self()]),
886    [{dummy_h,1}] = gen_event:which_handlers(my_dummy_handler),
887    {error, bad_module} =
888	gen_event:call(my_dummy_handler, bad_h, hejsan),
889    {ok, hejhopp} = gen_event:call(my_dummy_handler, {dummy_h,1},
890				   hejsan),
891    {ok, swapped} = gen_event:call(my_dummy_handler, {dummy_h,1},
892				   {swap_call,{dummy1_h,2},swap}),
893    [{dummy1_h,2}] = gen_event:which_handlers(my_dummy_handler),
894    {error, bad_module} =
895	gen_event:call(my_dummy_handler, dummy_h, hejsan),
896    ok = gen_event:call(my_dummy_handler, {dummy1_h,2}, delete_call),
897    receive
898	{dummy1_h, removed} ->
899	    ok
900    end,
901    [] = gen_event:which_handlers(my_dummy_handler),
902    ok = gen_event:add_handler(my_dummy_handler, {dummy_h,3}, [self()]),
903
904    {error, {return, faulty}} =
905	gen_event:call(my_dummy_handler, {dummy_h,3}, error_call),
906    receive
907	{dummy_h, returned_error} ->
908	    ok
909    end,
910    [] = gen_event:which_handlers(my_dummy_handler),
911    ok = gen_event:add_handler(my_dummy_handler, {dummy_h,4}, [self()]),
912
913    {error, {'EXIT', _}} =
914	gen_event:call(my_dummy_handler, {dummy_h,4}, exit_call),
915
916    [] = gen_event:which_handlers(my_dummy_handler),
917
918    %% Supervised handler.
919
920    ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
921    [dummy_h] = gen_event:which_handlers(my_dummy_handler),
922    {error, bad_module} =
923	gen_event:call(my_dummy_handler, bad_h, hejsan),
924    {ok, hejhopp} = gen_event:call(my_dummy_handler, dummy_h, hejsan),
925    {ok, swapped} = gen_event:call(my_dummy_handler, dummy_h,
926				   {swap_call,dummy1_h,swap}),
927    [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
928    {error, bad_module} =
929	gen_event:call(my_dummy_handler, dummy_h, hejsan),
930    ok = gen_event:call(my_dummy_handler, dummy1_h, delete_call),
931    receive
932	{dummy1_h, removed} ->
933	    ok
934    end,
935
936    receive
937	{gen_event_EXIT, dummy1_h, normal} ->
938	    ok
939    end,
940
941    [] = gen_event:which_handlers(my_dummy_handler),
942    ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
943
944    {error, {return, faulty}} =
945	gen_event:call(my_dummy_handler, dummy_h, error_call),
946    receive
947	{dummy_h, returned_error} ->
948	    ok
949    end,
950
951    receive
952	{gen_event_EXIT, dummy_h, {return,faulty}} ->
953	    ok
954    after 1000 ->
955	    ct:fail({no, {gen_event_EXIT, dummy_h, {return,faulty}}})
956    end,
957
958    [] = gen_event:which_handlers(my_dummy_handler),
959    ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
960
961    {error, {'EXIT', _}} =
962	gen_event:call(my_dummy_handler, dummy_h, exit_call),
963
964    receive
965	{gen_event_EXIT, dummy_h, {'EXIT',_}} ->
966	    ok
967    after 1000 ->
968	    ct:fail({no, {gen_event_EXIT, dummy_h, {'EXIT','_'}}})
969    end,
970
971    [] = gen_event:which_handlers(my_dummy_handler),
972
973    ok = gen_event:stop(my_dummy_handler),
974    ok.
975
976flush() ->
977    receive _ -> flush() after 0 -> ok end.
978
979info(Config) when is_list(Config) ->
980    {ok,_} = gen_event:start({local, my_dummy_handler}),
981    ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
982    Info = {info, self()},
983    [dummy_h] = gen_event:which_handlers(my_dummy_handler),
984    my_dummy_handler ! Info,
985    receive
986	{dummy_h, Info} ->
987	    ok
988    end,
989    my_dummy_handler ! {swap_info,dummy1_h,swap},
990    [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
991    my_dummy_handler ! Info,
992    receive
993	{dummy1_h, Info} ->
994	    ok
995    end,
996    my_dummy_handler ! delete_info,
997    receive
998	{dummy1_h, removed} ->
999	    ok
1000    end,
1001    [] = gen_event:which_handlers(my_dummy_handler),
1002    ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
1003
1004    my_dummy_handler ! error_info,
1005    receive
1006	{dummy_h, returned_error} ->
1007	    ok
1008    end,
1009    [] = gen_event:which_handlers(my_dummy_handler),
1010
1011    %% Handler with id, {Mod,Id}
1012
1013    ok = gen_event:add_handler(my_dummy_handler, {dummy_h,1}, [self()]),
1014    [{dummy_h,1}] = gen_event:which_handlers(my_dummy_handler),
1015    my_dummy_handler ! Info,
1016    receive
1017	{dummy_h, Info} ->
1018	    ok
1019    end,
1020    my_dummy_handler ! {swap_info,{dummy1_h,2},swap},
1021    [{dummy1_h,2}] = gen_event:which_handlers(my_dummy_handler),
1022    my_dummy_handler ! Info,
1023    receive
1024	{dummy1_h, Info} ->
1025	    ok
1026    end,
1027    my_dummy_handler ! delete_info,
1028    receive
1029	{dummy1_h, removed} ->
1030	    ok
1031    end,
1032    [] = gen_event:which_handlers(my_dummy_handler),
1033    ok = gen_event:add_handler(my_dummy_handler, {dummy_h,3}, [self()]),
1034
1035    my_dummy_handler ! error_info,
1036    receive
1037	{dummy_h, returned_error} ->
1038	    ok
1039    end,
1040    [] = gen_event:which_handlers(my_dummy_handler),
1041
1042    %% Supervised handler
1043
1044    ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
1045    [dummy_h] = gen_event:which_handlers(my_dummy_handler),
1046    my_dummy_handler ! Info,
1047    receive
1048	{dummy_h, Info} ->
1049	    ok
1050    end,
1051    my_dummy_handler ! {swap_info,dummy1_h,swap},
1052    [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
1053    my_dummy_handler ! Info,
1054    receive
1055	{dummy1_h, Info} ->
1056	    ok
1057    end,
1058    my_dummy_handler ! delete_info,
1059    receive
1060	{dummy1_h, removed} ->
1061	    ok
1062    end,
1063
1064    receive
1065	{gen_event_EXIT, dummy1_h, normal} ->
1066	    ok
1067    after 1000 ->
1068	    ct:fail({no, {gen_event_EXIT, dummy1_h, normal}})
1069    end,
1070
1071    [] = gen_event:which_handlers(my_dummy_handler),
1072
1073    ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
1074
1075    my_dummy_handler ! error_info,
1076    receive
1077	{dummy_h, returned_error} ->
1078	    ok
1079    end,
1080
1081    receive
1082	{gen_event_EXIT, dummy_h, {return,faulty}} ->
1083	    ok
1084    after 1000 ->
1085	    ct:fail({no, {gen_event_EXIT, dummy_h, {return,faulty}}})
1086    end,
1087
1088    ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
1089    my_dummy_handler ! do_crash,
1090
1091    receive
1092	{gen_event_EXIT, dummy_h, {'EXIT',_}} ->
1093	    ok
1094    after 1000 ->
1095	    ct:fail({no, {gen_event_EXIT, dummy_h, {'EXIT','_'}}})
1096    end,
1097
1098    [] = gen_event:which_handlers(my_dummy_handler),
1099
1100    ok = gen_event:stop(my_dummy_handler),
1101    ok.
1102
1103%% Test that sys:get_status/1,2 calls format_status/2.
1104call_format_status(Config) when is_list(Config) ->
1105    {ok, Pid} = gen_event:start({local, my_dummy_handler}),
1106    %% State here intentionally differs from what we expect from format_status
1107    State = self(),
1108    FmtState = "dummy1_h handler state",
1109    ok = gen_event:add_handler(my_dummy_handler, dummy1_h, [State]),
1110    Status1 = sys:get_status(Pid),
1111    Status2 = sys:get_status(Pid, 5000),
1112    ok = gen_event:stop(Pid),
1113    {status, Pid, _, [_, _, Pid, [], Data1]} = Status1,
1114    HandlerInfo1 = proplists:get_value(items, Data1),
1115    {"Installed handlers", [{_,dummy1_h,_,FmtState,_}]} = HandlerInfo1,
1116    {status, Pid, _, [_, _, Pid, [], Data2]} = Status2,
1117    HandlerInfo2 = proplists:get_value(items, Data2),
1118    {"Installed handlers", [{_,dummy1_h,_,FmtState,_}]} = HandlerInfo2,
1119    ok.
1120
1121%% Test that sys:get_status/1,2 calls format_status/2 for anonymous
1122%% gen_event processes.
1123call_format_status_anon(Config) when is_list(Config) ->
1124    {ok, Pid} = gen_event:start(),
1125    %% The 'Name' of the gen_event process will be a pid() here, so
1126    %% the next line will crash if format_status can't string-ify pids.
1127    Status1 = sys:get_status(Pid),
1128    ok = gen_event:stop(Pid),
1129    Header = "Status for event handler " ++  pid_to_list(Pid),
1130    {status, Pid, _, [_, _, Pid, [], Data1]} = Status1,
1131    Header = proplists:get_value(header, Data1),
1132    ok.
1133
1134
1135%% Test that a handler error calls format_status/2.
1136error_format_status(Config) when is_list(Config) ->
1137    error_logger_forwarder:register(),
1138    OldFl = process_flag(trap_exit, true),
1139    State = self(),
1140    {ok, Pid} = gen_event:start({local, my_dummy_handler}),
1141    ok = gen_event:add_sup_handler(my_dummy_handler, dummy1_h, [State]),
1142    ok = gen_event:notify(my_dummy_handler, do_crash),
1143    receive
1144	{gen_event_EXIT,dummy1_h,{'EXIT',_}} -> ok
1145    after 5000 ->
1146	    ct:fail(exit_gen_event)
1147    end,
1148    FmtState = "dummy1_h handler state",
1149    receive
1150	{error,_GroupLeader, {Pid,
1151			      "** gen_event handler"++_,
1152			      [dummy1_h,my_dummy_handler,do_crash,
1153			       FmtState, _]}} ->
1154	    ok;
1155	Other ->
1156	    io:format("Unexpected: ~p", [Other]),
1157	    ct:fail(failed)
1158    end,
1159    ok = gen_event:stop(Pid),
1160    process_flag(trap_exit, OldFl),
1161    ok.
1162
1163%% Test that sys:get_state/1,2 return the gen_event state.
1164get_state(Config) when is_list(Config) ->
1165    {ok, Pid} = gen_event:start({local, my_dummy_handler}),
1166    State1 = self(),
1167    ok = gen_event:add_handler(my_dummy_handler, dummy1_h, [State1]),
1168    [{dummy1_h,false,State1}] = sys:get_state(Pid),
1169    [{dummy1_h,false,State1}] = sys:get_state(Pid, 5000),
1170    State2 = {?MODULE, self()},
1171    ok = gen_event:add_handler(my_dummy_handler, {dummy1_h,id}, [State2]),
1172    Result1 = sys:get_state(Pid),
1173    [{dummy1_h,false,State1},{dummy1_h,id,State2}] = lists:sort(Result1),
1174    Result2 = sys:get_state(Pid, 5000),
1175    [{dummy1_h,false,State1},{dummy1_h,id,State2}] = lists:sort(Result2),
1176    ok = sys:suspend(Pid),
1177    Result3 = sys:get_state(Pid),
1178    [{dummy1_h,false,State1},{dummy1_h,id,State2}] = lists:sort(Result3),
1179    ok = sys:resume(Pid),
1180    ok = gen_event:stop(Pid),
1181    ok.
1182
1183%% Test that replace_state/2,3 replace the gen_event state.
1184replace_state(Config) when is_list(Config) ->
1185    {ok, Pid} = gen_event:start({local, my_dummy_handler}),
1186    State1 = self(),
1187    ok = gen_event:add_handler(my_dummy_handler, dummy1_h, [State1]),
1188    [{dummy1_h,false,State1}] = sys:get_state(Pid),
1189    NState1 = "replaced",
1190    Replace1 = fun({dummy1_h,false,_}=S) -> setelement(3,S,NState1) end,
1191    [{dummy1_h,false,NState1}] = sys:replace_state(Pid, Replace1),
1192    [{dummy1_h,false,NState1}] = sys:get_state(Pid),
1193    NState2 = "replaced again",
1194    Replace2 = fun({dummy1_h,false,_}=S) -> setelement(3,S,NState2) end,
1195    [{dummy1_h,false,NState2}] = sys:replace_state(Pid, Replace2, 5000),
1196    [{dummy1_h,false,NState2}] = sys:get_state(Pid),
1197    %% verify no change in state if replace function crashes
1198    Replace3 = fun(_) -> exit(fail) end,
1199    [{dummy1_h,false,NState2}] = sys:replace_state(Pid, Replace3),
1200    [{dummy1_h,false,NState2}] = sys:get_state(Pid),
1201    %% verify state replaced if process sys suspended
1202    NState3 = "replaced again and again",
1203    Replace4 = fun({dummy1_h,false,_}=S) -> setelement(3,S,NState3) end,
1204    ok = sys:suspend(Pid),
1205    [{dummy1_h,false,NState3}] = sys:replace_state(Pid, Replace4),
1206    ok = sys:resume(Pid),
1207    [{dummy1_h,false,NState3}] = sys:get_state(Pid),
1208    ok.
1209
1210%% No default provided for init, so it should fail
1211undef_init(Config) ->
1212    Pid = ?config(event_pid, Config),
1213    {'EXIT', {undef, [{oc_init_event, init, [_], _}|_]}}
1214        = gen_event:add_handler(Pid, oc_init_event, []),
1215    ok.
1216
1217%% No default provided for init, so it should fail
1218undef_handle_call(Config) when is_list(Config) ->
1219    Pid = ?config(event_pid, Config),
1220    {error, {'EXIT', {undef, [{oc_event, handle_call, _, _}|_]}}}
1221        = gen_event:call(Pid, oc_event, call_msg),
1222    [] = gen_event:which_handlers(Pid),
1223    ok.
1224
1225%% No default provided for init, so it should fail
1226undef_handle_event(Config) ->
1227    Pid = ?config(event_pid, Config),
1228    ok = gen_event:sync_notify(Pid, event_msg),
1229    [] = gen_event:which_handlers(Pid),
1230
1231    gen_event:add_handler(oc_event, oc_event, []),
1232    [oc_event] = gen_event:which_handlers(Pid),
1233
1234    ok = gen_event:notify(Pid, event_msg),
1235    [] = gen_event:which_handlers(Pid),
1236    ok.
1237
1238%% Defaulting to doing nothing with a log warning.
1239undef_handle_info(Config) when is_list(Config) ->
1240    error_logger_forwarder:register(),
1241    Pid = ?config(event_pid, Config),
1242    Pid ! hej,
1243    wait_until_processed(Pid, hej, 10),
1244    [oc_event] = gen_event:which_handlers(Pid),
1245    receive
1246        {warning_msg, _GroupLeader,
1247         {Pid, "** Undefined handle_info in " ++ _, [oc_event, hej]}} ->
1248            ok;
1249        Other ->
1250            io:format("Unexpected: ~p", [Other]),
1251            ct:fail(failed)
1252    end.
1253
1254wait_until_processed(_Pid, _Message, 0) ->
1255    ct:fail(not_processed);
1256wait_until_processed(Pid, Message, N) ->
1257    {messages, Messages} = erlang:process_info(Pid, messages),
1258    case lists:member(Message, Messages) of
1259        true ->
1260            timer:sleep(100),
1261            wait_until_processed(Pid, Message, N-1);
1262        false ->
1263            ok
1264    end.
1265
1266%% No default provided for init, so it should fail
1267undef_code_change(Config) when is_list(Config) ->
1268    Pid = ?config(event_pid, Config),
1269    {error, {'EXIT', {undef, [{oc_event, code_change, [_, _, _], _}|_]}}} =
1270        fake_upgrade(Pid, oc_event),
1271    [oc_event] = gen_event:which_handlers(Pid),
1272    ok.
1273
1274%% Defaulting to doing nothing. Test that it works when not defined.
1275undef_terminate(Config) when is_list(Config) ->
1276    Pid = ?config(event_pid, Config),
1277    ok = gen_event:delete_handler(Pid, oc_event, []),
1278    [] = gen_event:which_handlers(Pid),
1279    ok.
1280
1281%% Test that the default implementation doesn't catch the wrong undef error
1282undef_in_terminate(_Config) ->
1283    {ok, Pid} = gen_event:start({local, dummy}),
1284    State = {undef_in_terminate, {dummy_h, terminate}},
1285    ok = gen_event:add_handler(Pid, dummy_h, {state, State}),
1286    [dummy_h] = gen_event:which_handlers(Pid),
1287    {'EXIT', {undef, [{dummy_h, terminate, [], []}|_]}}
1288        = gen_event:delete_handler(Pid, dummy_h, []),
1289    [] = gen_event:which_handlers(Pid),
1290    ok.
1291
1292fake_upgrade(Pid, Mod) ->
1293    sys:suspend(Pid),
1294    sys:replace_state(Pid, fun(S) -> {new, S} end),
1295    Ret = sys:change_code(Pid, Mod, old_vsn, []),
1296    ok = sys:resume(Pid),
1297    Ret.
1298
1299%% Test report callback for Logger handler error_logger
1300format_log_1(_Config) ->
1301    FD = application:get_env(kernel, error_logger_format_depth),
1302    application:unset_env(kernel, error_logger_format_depth),
1303    Term = lists:seq(1, 15),
1304    Handler = my_handler,
1305    Name = self(),
1306    Report = #{label=>{gen_event,terminate},
1307               handler=>Handler,
1308               name=>Name,
1309               last_message=>Term,
1310               state=>Term,
1311               reason=>Term},
1312    {F1, A1} = gen_event:format_log(Report),
1313    FExpected1 = "** gen_event handler ~tp crashed.\n"
1314        "** Was installed in ~tp\n"
1315        "** Last event was: ~tp\n"
1316        "** When handler state == ~tp\n"
1317        "** Reason == ~tp\n",
1318    ct:log("F1: ~ts~nA1: ~tp", [F1,A1]),
1319    FExpected1 = F1,
1320    [Handler,Name,Term,Term,Term] = A1,
1321
1322    Warning = #{label=>{gen_event,no_handle_info},
1323                module=>?MODULE,
1324                message=>Term},
1325    {WF1,WA1} = gen_event:format_log(Warning),
1326    WFExpected1 = "** Undefined handle_info in ~p\n"
1327                  "** Unhandled message: ~tp\n",
1328    ct:log("WF1: ~ts~nWA1: ~tp", [WF1,WA1]),
1329    WFExpected1 = WF1,
1330    [?MODULE,Term] = WA1,
1331
1332    Depth = 10,
1333    ok = application:set_env(kernel, error_logger_format_depth, Depth),
1334    Limited = [1,2,3,4,5,6,7,8,9,'...'],
1335    {F2,A2} = gen_event:format_log(#{label=>{gen_event,terminate},
1336                                     handler=>Handler,
1337                                     name=>Name,
1338                                     last_message=>Term,
1339                                     state=>Term,
1340                                     reason=>Term}),
1341    FExpected2 = "** gen_event handler ~tP crashed.\n"
1342        "** Was installed in ~tP\n"
1343        "** Last event was: ~tP\n"
1344        "** When handler state == ~tP\n"
1345        "** Reason == ~tP\n",
1346    ct:log("F2: ~ts~nA2: ~tp", [F2,A2]),
1347    FExpected2 = F2,
1348    [Handler,Depth,Name,Depth,Limited,Depth,Limited,Depth,Limited,Depth] = A2,
1349
1350    {WF2,WA2} = gen_event:format_log(Warning),
1351    WFExpected2 = "** Undefined handle_info in ~p\n"
1352                  "** Unhandled message: ~tP\n",
1353    ct:log("WF2: ~ts~nWA2: ~tp", [WF2,WA2]),
1354    WFExpected2 = WF2,
1355    [?MODULE,Limited,Depth] = WA2,
1356
1357    case FD of
1358        undefined ->
1359            application:unset_env(kernel, error_logger_format_depth);
1360        _ ->
1361            application:set_env(kernel, error_logger_format_depth, FD)
1362    end,
1363    ok.
1364
1365%% Test report callback for any Logger handler
1366format_log_2(_Config) ->
1367    Term = lists:seq(1, 15),
1368    Handler = my_handler,
1369    Name = self(),
1370    NameStr = pid_to_list(Name),
1371    Report = #{label=>{gen_event,terminate},
1372               handler=>Handler,
1373               name=>Name,
1374               last_message=>Term,
1375               state=>Term,
1376               reason=>Term},
1377    FormatOpts1 = #{},
1378    Str1 = flatten_format_log(Report, FormatOpts1),
1379    L1 = length(Str1),
1380    Expected1 = "** gen_event handler my_handler crashed.\n"
1381        "** Was installed in "++NameStr++"\n"
1382        "** Last event was: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]\n"
1383        "** When handler state == [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]\n"
1384        "** Reason == [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]\n",
1385    ct:log("Str1: ~ts", [Str1]),
1386    ct:log("length(Str1): ~p", [L1]),
1387    true = Expected1 =:= Str1,
1388
1389    Warning = #{label=>{gen_event,no_handle_info},
1390                module=>?MODULE,
1391                message=>Term},
1392    WStr1 = flatten_format_log(Warning, FormatOpts1),
1393    WL1 = length(WStr1),
1394    WExpected1 = "** Undefined handle_info in gen_event_SUITE\n"
1395        "** Unhandled message: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]\n",
1396    ct:log("WStr1: ~ts", [WStr1]),
1397    ct:log("length(WStr1): ~p", [WL1]),
1398    true = WExpected1 =:= WStr1,
1399
1400    Depth = 10,
1401    FormatOpts2 = #{depth=>Depth},
1402    Str2 = flatten_format_log(Report, FormatOpts2),
1403    L2 = length(Str2),
1404    Expected2 = "** gen_event handler my_handler crashed.\n"
1405        "** Was installed in " ++ NameStr ++ "\n"
1406        "** Last event was: [1,2,3,4,5,6,7,8,9|...]\n"
1407        "** When handler state == [1,2,3,4,5,6,7,8,9|...]\n"
1408        "** Reason == [1,2,3,4,5,6,7,8,9|...]\n",
1409    ct:log("Str2: ~ts", [Str2]),
1410    ct:log("length(Str2): ~p", [L2]),
1411    true = Expected2 =:= Str2,
1412
1413    WStr2 = flatten_format_log(Warning, FormatOpts2),
1414    WL2 = length(WStr2),
1415    WExpected2 = "** Undefined handle_info in gen_event_SUITE\n"
1416        "** Unhandled message: [1,2,3,4,5,6,7,8,9|...]\n",
1417    ct:log("WStr2: ~ts", [WStr2]),
1418    ct:log("length(WStr2): ~p", [WL2]),
1419    true = WExpected2 =:= WStr2,
1420
1421    FormatOpts3 = #{chars_limit=>200},
1422    Str3 = flatten_format_log(Report, FormatOpts3),
1423    L3 = length(Str3),
1424    Expected3 = "** gen_event handler my_handler crashed.\n"
1425                "** Was installed",
1426    ct:log("Str3: ~ts", [Str3]),
1427    ct:log("length(Str3): ~p", [L3]),
1428    true = lists:prefix(Expected3, Str3),
1429    true = L3 < L1,
1430
1431    WFormatOpts3 = #{chars_limit=>80},
1432    WStr3 = flatten_format_log(Warning, WFormatOpts3),
1433    WL3 = length(WStr3),
1434    WExpected3 = "** Undefined handle_info in gen_event_SUITE\n"
1435        "** Unhandled message: ",
1436    ct:log("WStr3: ~ts", [WStr3]),
1437    ct:log("length(WStr3): ~p", [WL3]),
1438    true = lists:prefix(WExpected3, WStr3),
1439    true = WL3 < WL1,
1440
1441    FormatOpts4 = #{single_line=>true},
1442    Str4 = flatten_format_log(Report, FormatOpts4),
1443    L4 = length(Str4),
1444
1445    Expected4 = "Generic event handler my_handler crashed. "
1446        "Installed: "++NameStr++". "
1447        "Last event: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]. "
1448        "State: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]. "
1449        "Reason: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15].",
1450    ct:log("Str4: ~ts", [Str4]),
1451    ct:log("length(Str4): ~p", [L4]),
1452    true = Expected4 =:= Str4,
1453
1454    WStr4 = flatten_format_log(Warning, FormatOpts4),
1455    WL4 = length(WStr4),
1456    WExpected4 = "Undefined handle_info in gen_event_SUITE. "
1457        "Unhandled message: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15].",
1458    ct:log("WStr4: ~ts", [WStr4]),
1459    ct:log("length(WStr4): ~p", [WL4]),
1460    true = WExpected4 =:= WStr4,
1461
1462    FormatOpts5 = #{single_line=>true, depth=>Depth},
1463    Str5 = flatten_format_log(Report, FormatOpts5),
1464    L5 = length(Str5),
1465    Expected5 = "Generic event handler my_handler crashed. "
1466        "Installed: "++NameStr++". "
1467        "Last event: [1,2,3,4,5,6,7,8,9|...]. "
1468        "State: [1,2,3,4,5,6,7,8,9|...]. "
1469        "Reason: [1,2,3,4,5,6,7,8,9|...].",
1470    ct:log("Str5: ~ts", [Str5]),
1471    ct:log("length(Str5): ~p", [L5]),
1472    true = Expected5 =:= Str5,
1473
1474    WStr5 = flatten_format_log(Warning, FormatOpts5),
1475    WL5 = length(WStr5),
1476    WExpected5 = "Undefined handle_info in gen_event_SUITE. "
1477        "Unhandled message: [1,2,3,4,5,6,7,8,9|...].",
1478    ct:log("WStr5: ~ts", [WStr5]),
1479    ct:log("length(WStr5): ~p", [WL5]),
1480    true = WExpected5 =:= WStr5,
1481
1482    FormatOpts6 = #{single_line=>true, chars_limit=>200},
1483    Str6 = flatten_format_log(Report, FormatOpts6),
1484    L6 = length(Str6),
1485    Expected6 = "Generic event handler my_handler crashed. Installed: ",
1486    ct:log("Str6: ~ts", [Str6]),
1487    ct:log("length(Str6): ~p", [L6]),
1488    true = lists:prefix(Expected6, Str6),
1489    true = L6 < L4,
1490
1491    WFormatOpts6 = #{single_line=>true, chars_limit=>80},
1492    WStr6 = flatten_format_log(Warning, WFormatOpts6),
1493    WL6 = length(WStr6),
1494    WExpected6 = "Undefined handle_info in gen_event_SUITE. ",
1495    ct:log("WStr6: ~ts", [WStr6]),
1496    ct:log("length(WStr6): ~p", [WL6]),
1497    true = lists:prefix(WExpected6, WStr6),
1498    true = WL6 < WL4,
1499
1500    ok.
1501
1502flatten_format_log(Report, Format) ->
1503    lists:flatten(gen_event:format_log(Report, Format)).
1504