1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1996-2017. 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]).
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
45groups() ->
46    [{test_all, [],
47      [add_handler, add_sup_handler, delete_handler,
48       swap_handler, swap_sup_handler, notify, sync_notify,
49       call, info]},
50     {undef_callbacks, [],
51      [undef_init, undef_handle_call, undef_handle_event, undef_handle_info,
52       undef_code_change, undef_terminate]}].
53
54init_per_suite(Config) ->
55    Config.
56
57end_per_suite(_Config) ->
58    ok.
59
60init_per_group(undef_callbacks, Config) ->
61    DataDir = ?config(data_dir, Config),
62    Event1 = filename:join(DataDir, "oc_event.erl"),
63    {ok, oc_event} = compile:file(Event1),
64    Config;
65init_per_group(_GroupName, Config) ->
66    Config.
67
68end_per_group(_GroupName, Config) ->
69    Config.
70
71init_per_testcase(Case, Config) when Case == undef_handle_call;
72                                     Case == undef_handle_info;
73                                     Case == undef_handle_event;
74                                     Case == undef_code_change;
75                                     Case == undef_terminate ->
76    {ok, Pid} = oc_event:start(),
77    [{event_pid, Pid}|Config];
78init_per_testcase(undef_init, Config) ->
79    {ok, Pid} = gen_event:start({local, oc_init_event}),
80    [{event_pid, Pid}|Config];
81init_per_testcase(_Case, Config) ->
82    Config.
83
84end_per_testcase(Case, Config) when Case == undef_init;
85                                    Case == undef_handle_call;
86                                    Case == undef_handle_info;
87                                    Case == undef_handle_event;
88                                    Case == undef_code_change;
89                                    Case == undef_terminate ->
90    Pid = ?config(event_pid, Config),
91    gen_event:stop(Pid);
92end_per_testcase(_Case, _Config) ->
93    ok.
94
95%% --------------------------------------
96%% Start an event manager.
97%% --------------------------------------
98
99-define(LMGR, {local, my_dummy_name}).
100-define(GMGR, {global, my_dummy_name}).
101
102start(Config) when is_list(Config) ->
103    OldFl = process_flag(trap_exit, true),
104
105    dummy_via:reset(),
106
107    {ok, Pid0} = gen_event:start(), %anonymous
108    [] = gen_event:which_handlers(Pid0),
109    ok = gen_event:stop(Pid0),
110
111    {ok, Pid1} = gen_event:start_link(), %anonymous
112    [] = gen_event:which_handlers(Pid1),
113    ok = gen_event:stop(Pid1),
114
115    {ok, Pid2} = gen_event:start(?LMGR),
116    [] = gen_event:which_handlers(my_dummy_name),
117    [] = gen_event:which_handlers(Pid2),
118    ok = gen_event:stop(my_dummy_name),
119
120    {ok, Pid3} = gen_event:start_link(?LMGR),
121    [] = gen_event:which_handlers(my_dummy_name),
122    [] = gen_event:which_handlers(Pid3),
123    ok = gen_event:stop(my_dummy_name),
124
125    {ok, Pid4} = gen_event:start_link(?GMGR),
126    [] = gen_event:which_handlers(?GMGR),
127    [] = gen_event:which_handlers(Pid4),
128    ok = gen_event:stop(?GMGR),
129
130    {ok, Pid5} = gen_event:start_link({via, dummy_via, my_dummy_name}),
131    [] = gen_event:which_handlers({via, dummy_via, my_dummy_name}),
132    [] = gen_event:which_handlers(Pid5),
133    ok = gen_event:stop({via, dummy_via, my_dummy_name}),
134
135    {ok, _} = gen_event:start_link(?LMGR),
136    {error, {already_started, _}} = gen_event:start_link(?LMGR),
137    {error, {already_started, _}} = gen_event:start(?LMGR),
138    ok = gen_event:stop(my_dummy_name),
139
140    {ok, Pid6} = gen_event:start_link(?GMGR),
141    {error, {already_started, _}} = gen_event:start_link(?GMGR),
142    {error, {already_started, _}} = gen_event:start(?GMGR),
143
144    ok = gen_event:stop(?GMGR, shutdown, 10000),
145    receive
146	{'EXIT', Pid6, shutdown} -> ok
147    after 10000 ->
148	    ct:fail(exit_gen_event)
149    end,
150
151    {ok, Pid7} = gen_event:start_link({via, dummy_via, my_dummy_name}),
152    {error, {already_started, _}} = gen_event:start_link({via, dummy_via, my_dummy_name}),
153    {error, {already_started, _}} = gen_event:start({via, dummy_via, my_dummy_name}),
154
155    exit(Pid7, shutdown),
156    receive
157	{'EXIT', Pid7, shutdown} -> ok
158    after 10000 ->
159	    ct:fail(exit_gen_event)
160    end,
161
162    process_flag(trap_exit, OldFl),
163    ok.
164
165start_opt(Config) when is_list(Config) ->
166    OldFl = process_flag(trap_exit, true),
167
168    dummy_via:reset(),
169
170    {ok, Pid0} = gen_event:start([]), %anonymous
171    [] = gen_event:which_handlers(Pid0),
172    ok = gen_event:stop(Pid0),
173
174    {ok, Pid1} = gen_event:start_link([]), %anonymous
175    [] = gen_event:which_handlers(Pid1),
176    ok = gen_event:stop(Pid1),
177
178    {ok, Pid2} = gen_event:start(?LMGR, []),
179    [] = gen_event:which_handlers(my_dummy_name),
180    [] = gen_event:which_handlers(Pid2),
181    ok = gen_event:stop(my_dummy_name),
182
183    {ok, Pid3} = gen_event:start_link(?LMGR, []),
184    [] = gen_event:which_handlers(my_dummy_name),
185    [] = gen_event:which_handlers(Pid3),
186    ok = gen_event:stop(my_dummy_name),
187
188    {ok, Pid4} = gen_event:start_link(?GMGR, []),
189    [] = gen_event:which_handlers(?GMGR),
190    [] = gen_event:which_handlers(Pid4),
191    ok = gen_event:stop(?GMGR),
192
193    {ok, Pid5} = gen_event:start_link({via, dummy_via, my_dummy_name}, []),
194    [] = gen_event:which_handlers({via, dummy_via, my_dummy_name}),
195    [] = gen_event:which_handlers(Pid5),
196    ok = gen_event:stop({via, dummy_via, my_dummy_name}),
197
198    {ok, _} = gen_event:start_link(?LMGR, []),
199    {error, {already_started, _}} = gen_event:start_link(?LMGR, []),
200    {error, {already_started, _}} = gen_event:start(?LMGR, []),
201    ok = gen_event:stop(my_dummy_name),
202
203    {ok, Pid7} = gen_event:start_link(?GMGR),
204    {error, {already_started, _}} = gen_event:start_link(?GMGR, []),
205    {error, {already_started, _}} = gen_event:start(?GMGR, []),
206
207    ok = gen_event:stop(?GMGR, shutdown, 10000),
208    receive
209	{'EXIT', Pid7, shutdown} -> ok
210    after 10000 ->
211	    ct:fail(exit_gen_event)
212    end,
213
214    {ok, Pid8} = gen_event:start_link({via, dummy_via, my_dummy_name}),
215    {error, {already_started, _}} = gen_event:start_link({via, dummy_via, my_dummy_name}, []),
216    {error, {already_started, _}} = gen_event:start({via, dummy_via, my_dummy_name}, []),
217
218    exit(Pid8, shutdown),
219    receive
220	{'EXIT', Pid8, shutdown} -> ok
221    after 10000 ->
222	    ct:fail(exit_gen_event)
223    end,
224
225    %% test spawn_opt
226    MinHeapSz = 10000,
227    {ok, Pid9} = gen_event:start_link(?LMGR, [{spawn_opt, [{min_heap_size, MinHeapSz}]}]),
228    {error, {already_started, _}} = gen_event:start_link(?LMGR, []),
229    {error, {already_started, _}} = gen_event:start(?LMGR, []),
230    {heap_size, HeapSz} = erlang:process_info(Pid9, heap_size),
231    true = HeapSz > MinHeapSz,
232    ok = gen_event:stop(my_dummy_name),
233
234    %% test debug opt
235    {ok, _} = gen_event:start_link(?LMGR, [{debug,[debug]}]),
236    {error, {already_started, _}} = gen_event:start_link(?LMGR, []),
237    {error, {already_started, _}} = gen_event:start(?LMGR, []),
238    ok = gen_event:stop(my_dummy_name),
239
240    process_flag(trap_exit, OldFl),
241    ok.
242
243hibernate(Config) when is_list(Config) ->
244    {ok,Pid} = gen_event:start({local, my_dummy_handler}),
245    ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
246    [dummy_h] = gen_event:which_handlers(my_dummy_handler),
247    true = gen_event:call(my_dummy_handler, dummy_h, hibernate),
248    is_in_erlang_hibernate(Pid),
249
250    Pid ! wake,
251    is_not_in_erlang_hibernate(Pid),
252    later = gen_event:call(my_dummy_handler, dummy_h, hibernate_later),
253    true = ({current_function,{erlang,hibernate,3}} =/=
254		erlang:process_info(Pid, current_function)),
255    is_in_erlang_hibernate(Pid),
256
257    Pid ! wake,
258    is_not_in_erlang_hibernate(Pid),
259    gen_event:notify(my_dummy_handler, hibernate),
260    is_in_erlang_hibernate(Pid),
261    gen_event:notify(my_dummy_handler, wakeup),
262    is_not_in_erlang_hibernate(Pid),
263    gen_event:notify(my_dummy_handler, hibernate),
264    is_in_erlang_hibernate(Pid),
265    gen_event:sync_notify(my_dummy_handler, wakeup),
266    true = ({current_function,{erlang,hibernate,3}} =/=
267		erlang:process_info(Pid, current_function)),
268    ok = gen_event:sync_notify(my_dummy_handler, hibernate),
269    is_in_erlang_hibernate(Pid),
270
271    Pid ! wake,
272    is_not_in_erlang_hibernate(Pid),
273    ok = gen_event:add_handler(my_dummy_handler, dummy1_h, [self()]),
274    [_,_] = gen_event:which_handlers(my_dummy_handler),
275    gen_event:notify(my_dummy_handler, hibernate),
276    is_in_erlang_hibernate(Pid),
277    gen_event:notify(my_dummy_handler, wakeup),
278    is_in_erlang_hibernate(Pid),
279
280    Pid ! wake,
281    is_not_in_erlang_hibernate(Pid),
282
283    Pid ! gnurf,
284    is_in_erlang_hibernate(Pid),
285
286    Pid ! sleep,
287    is_in_erlang_hibernate(Pid),
288
289    Pid ! wake,
290    is_not_in_erlang_hibernate(Pid),
291    ok = gen_event:stop(my_dummy_handler),
292
293    {ok,Pid2} = gen_event:start({local, my_dummy_handler}),
294    ok = gen_event:add_handler(my_dummy_handler, dummy_h,
295			       [self(),hibernate]),
296    is_in_erlang_hibernate(Pid2),
297    sys:suspend(my_dummy_handler),
298    is_in_erlang_hibernate(Pid2),
299    sys:resume(my_dummy_handler),
300    is_in_erlang_hibernate(Pid2),
301
302    Pid2 ! wake,
303    is_not_in_erlang_hibernate(Pid2),
304
305    ok = gen_event:stop(my_dummy_handler),
306
307    ok.
308
309auto_hibernate(Config) when is_list(Config) ->
310    HibernateAfterTimeout = 100,
311    State = {auto_hibernate_state},
312    {ok,Pid} = gen_event:start({local, auto_hibernate_handler}, [{hibernate_after, HibernateAfterTimeout}]),
313    %% After init test
314    is_not_in_erlang_hibernate(Pid),
315    timer:sleep(HibernateAfterTimeout),
316    is_in_erlang_hibernate(Pid),
317    ok = gen_event:add_handler(auto_hibernate_handler, dummy_h, [State]),
318    %% Get state test
319    [{dummy_h,false,State}] = sys:get_state(Pid),
320    is_in_erlang_hibernate(Pid),
321    %% Call test
322    {ok, hejhopp} = gen_event:call(auto_hibernate_handler, dummy_h, hejsan),
323    is_not_in_erlang_hibernate(Pid),
324    timer:sleep(HibernateAfterTimeout),
325    is_in_erlang_hibernate(Pid),
326    %% Event test
327    ok = gen_event:notify(auto_hibernate_handler, {self(), handle_event}),
328    receive
329        handled_event ->
330            ok
331    after 1000 ->
332        ct:fail(event)
333    end,
334    is_not_in_erlang_hibernate(Pid),
335    timer:sleep(HibernateAfterTimeout),
336    is_in_erlang_hibernate(Pid),
337    %% Info test
338    Pid ! {self(), handle_info},
339    receive
340        handled_info ->
341            ok
342    after 1000 ->
343        ct:fail(info)
344    end,
345    is_not_in_erlang_hibernate(Pid),
346    timer:sleep(HibernateAfterTimeout),
347    is_in_erlang_hibernate(Pid),
348    ok = gen_event:stop(auto_hibernate_handler),
349    ok.
350
351is_in_erlang_hibernate(Pid) ->
352    receive after 1 -> ok end,
353    is_in_erlang_hibernate_1(200, Pid).
354
355is_in_erlang_hibernate_1(0, Pid) ->
356    io:format("~p\n", [erlang:process_info(Pid, current_function)]),
357    ct:fail(not_in_erlang_hibernate_3);
358is_in_erlang_hibernate_1(N, Pid) ->
359    {current_function,MFA} = erlang:process_info(Pid, current_function),
360    case MFA of
361	{erlang,hibernate,3} ->
362	    ok;
363	_ ->
364	    receive after 10 -> ok end,
365	    is_in_erlang_hibernate_1(N-1, Pid)
366    end.
367
368is_not_in_erlang_hibernate(Pid) ->
369    receive after 1 -> ok end,
370    is_not_in_erlang_hibernate_1(200, Pid).
371
372is_not_in_erlang_hibernate_1(0, Pid) ->
373    io:format("~p\n", [erlang:process_info(Pid, current_function)]),
374    ct:fail(not_in_erlang_hibernate_3);
375is_not_in_erlang_hibernate_1(N, Pid) ->
376    {current_function,MFA} = erlang:process_info(Pid, current_function),
377    case MFA of
378	{erlang,hibernate,3} ->
379	    receive after 10 -> ok end,
380	    is_not_in_erlang_hibernate_1(N-1, Pid);
381	_ ->
382	    ok
383    end.
384
385
386add_handler(Config) when is_list(Config) ->
387    {ok,_} = gen_event:start({local, my_dummy_handler}),
388    {error, my_error} =
389	gen_event:add_handler(my_dummy_handler, dummy_h, make_error),
390    [] = gen_event:which_handlers(my_dummy_handler),
391    ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
392    [dummy_h] = gen_event:which_handlers(my_dummy_handler),
393
394    {error, my_error} =
395	gen_event:add_handler(my_dummy_handler, {dummy_h, self()}, make_error),
396    [dummy_h] = gen_event:which_handlers(my_dummy_handler),
397    ok = gen_event:add_handler(my_dummy_handler, {dummy_h,self()},
398			       [self()]),
399    Self = self(),
400    [{dummy_h, Self}, dummy_h] =
401	gen_event:which_handlers(my_dummy_handler),
402    ok = gen_event:stop(my_dummy_handler),
403    ok.
404
405add_sup_handler(Config) when is_list(Config) ->
406    {ok,Pid} = gen_event:start({local, my_dummy_handler}),
407    {error, my_error} =
408	gen_event:add_sup_handler(my_dummy_handler, dummy_h, make_error),
409    [] = gen_event:which_handlers(my_dummy_handler),
410    ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
411    [dummy_h] = gen_event:which_handlers(my_dummy_handler),
412    exit(Pid, sup_died),
413    ct:sleep(1000),
414    [] = gen_event:which_handlers(my_dummy_handler),
415
416    ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
417    [dummy_h] = gen_event:which_handlers(my_dummy_handler),
418
419    {error, my_error} =
420	gen_event:add_handler(my_dummy_handler, {dummy_h, self()}, make_error),
421    [dummy_h] = gen_event:which_handlers(my_dummy_handler),
422    ok = gen_event:add_sup_handler(my_dummy_handler, {dummy_h,self()},
423				   [self()]),
424    Self = self(),
425    [{dummy_h, Self}, dummy_h] =
426	gen_event:which_handlers(my_dummy_handler),
427    ok = gen_event:stop(my_dummy_handler),
428
429    receive
430	{gen_event_EXIT, dummy_h, shutdown} ->
431	    ok
432    after 1000 ->
433	    ct:fail({no,{gen_event_EXIT, dummy_h, shutdown}})
434    end,
435
436    receive
437	{gen_event_EXIT, {dummy_h,Self}, shutdown} ->
438	    ok
439    after 1000 ->
440	    ct:fail({no,{gen_event_EXIT, {dummy_h,Self},
441			 shutdown}})
442    end,
443    ok.
444
445delete_handler(Config) when is_list(Config) ->
446    {ok,_} = gen_event:start({local, my_dummy_handler}),
447    ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
448    {error, module_not_found} =
449	gen_event:delete_handler(my_dummy_handler, duuuuuuuuumy, []),
450    return_hej =
451	gen_event:delete_handler(my_dummy_handler, dummy_h, return_hej),
452    [] = gen_event:which_handlers(my_dummy_handler),
453    ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
454    ok =
455	gen_event:delete_handler(my_dummy_handler, dummy_h, []),
456    [] = gen_event:which_handlers(my_dummy_handler),
457
458    ok = gen_event:add_handler(my_dummy_handler, {dummy_h,1}, [self()]),
459    ok = gen_event:add_handler(my_dummy_handler, {dummy_h,2}, [self()]),
460    {error, module_not_found} =
461	gen_event:delete_handler(my_dummy_handler, {duuuuuuuuumy,1}, []),
462    return_hej =
463	gen_event:delete_handler(my_dummy_handler, {dummy_h,1}, return_hej),
464    return_hej =
465	gen_event:delete_handler(my_dummy_handler, {dummy_h,2}, return_hej),
466    [] = gen_event:which_handlers(my_dummy_handler),
467    ok = gen_event:add_handler(my_dummy_handler, {dummy_h,2}, [self()]),
468    ok =
469	gen_event:delete_handler(my_dummy_handler, {dummy_h,2}, []),
470    [] = gen_event:which_handlers(my_dummy_handler),
471
472    ok = gen_event:stop(my_dummy_handler),
473    ok.
474
475swap_handler(Config) when is_list(Config) ->
476    {ok,_} = gen_event:start({local, my_dummy_handler}),
477    ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
478    {error, non_existing} =
479	gen_event:swap_handler(my_dummy_handler, {faulty_h, swap},
480			       {dummy1_h, []}),
481    ok =
482	gen_event:swap_handler(my_dummy_handler, {dummy_h, swap},
483			       {dummy1_h, swap}),
484    [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
485
486    ok = gen_event:delete_handler(my_dummy_handler, dummy1_h, []),
487
488    ok = gen_event:add_handler(my_dummy_handler, {dummy_h,3}, [self()]),
489    {error, non_existing} =
490	gen_event:swap_handler(my_dummy_handler, {faulty_h, swap},
491			       {dummy1_h, []}),
492    ok =
493	gen_event:swap_handler(my_dummy_handler, {{dummy_h,3}, swap},
494			       {{dummy1_h,4}, swap}),
495    [{dummy1_h,4}] = gen_event:which_handlers(my_dummy_handler),
496
497    ok = gen_event:delete_handler(my_dummy_handler, {dummy1_h,4}, []),
498
499    ok = gen_event:stop(my_dummy_handler),
500    ok.
501
502swap_sup_handler(Config) when is_list(Config) ->
503    {ok,_} = gen_event:start({local, my_dummy_handler}),
504    ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
505    {error, non_existing} =
506	gen_event:swap_handler(my_dummy_handler, {faulty_h, swap},
507			       {dummy1_h, []}),
508    ok =
509	gen_event:swap_handler(my_dummy_handler, {dummy_h, swap},
510			       {dummy1_h, swap}),
511    [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
512
513    ok = gen_event:delete_handler(my_dummy_handler, dummy1_h, []),
514    receive
515	{gen_event_EXIT, dummy1_h, normal} ->
516	    ok
517    after 1000 ->
518	    ct:fail({no,{gen_event_EXIT, dummy1_h, normal}})
519    end,
520
521    ok = gen_event:add_sup_handler(my_dummy_handler, {dummy_h,3},
522				   [self()]),
523    {error, non_existing} =
524	gen_event:swap_sup_handler(my_dummy_handler, {faulty_h, swap},
525				   {dummy1_h, []}),
526    ok =
527	gen_event:swap_sup_handler(my_dummy_handler, {{dummy_h,3}, swap},
528				   {{dummy1_h,4}, swap}),
529    [{dummy1_h,4}] = gen_event:which_handlers(my_dummy_handler),
530
531    ok = gen_event:delete_handler(my_dummy_handler, {dummy1_h,4}, []),
532    receive
533	{gen_event_EXIT, {dummy1_h,4}, normal} ->
534	    ok
535    after 1000 ->
536	    ct:fail({no,{gen_event_EXIT, {dummy1_h,4}, normal}})
537    end,
538
539    ok = gen_event:stop(my_dummy_handler),
540    ok.
541
542notify(Config) when is_list(Config) ->
543    {ok,_} = gen_event:start({local, my_dummy_handler}),
544    ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
545    Event = {event, self()},
546    [dummy_h] = gen_event:which_handlers(my_dummy_handler),
547    ok = gen_event:notify(my_dummy_handler, Event),
548    receive
549	{dummy_h, Event} ->
550	    ok
551    end,
552    ok = gen_event:notify(my_dummy_handler, {swap_event,dummy1_h,swap}),
553    [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
554    ok = gen_event:notify(my_dummy_handler, Event),
555    receive
556	{dummy1_h, Event} ->
557	    ok
558    end,
559    ok = gen_event:notify(my_dummy_handler, delete_event),
560    receive
561	{dummy1_h, removed} ->
562	    ok
563    end,
564    [] = gen_event:which_handlers(my_dummy_handler),
565    ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
566
567    ok = gen_event:notify(my_dummy_handler, error_event),
568    receive
569	{dummy_h, returned_error} ->
570	    ok
571    end,
572    [] = gen_event:which_handlers(my_dummy_handler),
573
574    %% Handler with id, {Mod,Id}
575
576    ok = gen_event:add_handler(my_dummy_handler, {dummy_h,5}, [self()]),
577    [{dummy_h,5}] = gen_event:which_handlers(my_dummy_handler),
578    ok = gen_event:notify(my_dummy_handler, Event),
579    receive
580	{dummy_h, Event} ->
581	    ok
582    end,
583    ok = gen_event:notify(my_dummy_handler,
584			  {swap_event, {dummy1_h, 9}, swap}),
585    [{dummy1_h,9}] = gen_event:which_handlers(my_dummy_handler),
586    ok = gen_event:notify(my_dummy_handler, Event),
587    receive
588	{dummy1_h, Event} ->
589	    ok
590    end,
591    ok = gen_event:notify(my_dummy_handler, delete_event),
592    receive
593	{dummy1_h, removed} ->
594	    ok
595    end,
596    [] = gen_event:which_handlers(my_dummy_handler),
597    ok = gen_event:add_handler(my_dummy_handler, {dummy_h,a}, [self()]),
598
599    ok = gen_event:notify(my_dummy_handler, error_event),
600    receive
601	{dummy_h, returned_error} ->
602	    ok
603    end,
604    [] = gen_event:which_handlers(my_dummy_handler),
605
606    %% Supervised handler.
607
608    ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
609    [dummy_h] = gen_event:which_handlers(my_dummy_handler),
610    ok = gen_event:notify(my_dummy_handler, Event),
611    receive
612	{dummy_h, Event} ->
613	    ok
614    end,
615
616    ok = gen_event:notify(my_dummy_handler, do_crash),
617    receive
618	{gen_event_EXIT, dummy_h, {'EXIT',_}} ->
619	    ok
620    end,
621
622    ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
623    ok = gen_event:notify(my_dummy_handler, {swap_event,dummy1_h,swap}),
624    [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
625
626    ok = gen_event:notify(my_dummy_handler, do_crash),
627    receive
628	{gen_event_EXIT, dummy1_h, {'EXIT',_}} ->
629	    ok
630    end,
631
632    ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
633    ok = gen_event:notify(my_dummy_handler, {swap_event,dummy1_h,swap}),
634    [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
635
636    ok = gen_event:notify(my_dummy_handler, delete_event),
637    receive
638	{dummy1_h, removed} ->
639	    ok
640    end,
641
642    receive
643	{gen_event_EXIT, dummy1_h, normal} ->
644	    ok
645    end,
646
647    [] = gen_event:which_handlers(my_dummy_handler),
648
649    ok = gen_event:stop(my_dummy_handler),
650    ok.
651
652sync_notify(Config) when is_list(Config) ->
653    {ok,_} = gen_event:start({local, my_dummy_handler}),
654    ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
655    Event = {event, self()},
656    [dummy_h] = gen_event:which_handlers(my_dummy_handler),
657    ok = gen_event:sync_notify(my_dummy_handler, Event),
658    receive
659	{dummy_h, Event} ->
660	    ok
661    end,
662    ok = gen_event:sync_notify(my_dummy_handler,
663			       {swap_event, dummy1_h, swap}),
664    [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
665    ok = gen_event:sync_notify(my_dummy_handler, Event),
666    receive
667	{dummy1_h, Event} ->
668	    ok
669    end,
670    ok = gen_event:sync_notify(my_dummy_handler, delete_event),
671    receive
672	{dummy1_h, removed} ->
673	    ok
674    end,
675    [] = gen_event:which_handlers(my_dummy_handler),
676    ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
677
678    ok = gen_event:sync_notify(my_dummy_handler, error_event),
679    receive
680	{dummy_h, returned_error} ->
681	    ok
682    end,
683    [] = gen_event:which_handlers(my_dummy_handler),
684
685    %% Handler with id, {Mod,Id}
686
687    ok = gen_event:add_handler(my_dummy_handler, {dummy_h,5}, [self()]),
688    [{dummy_h,5}] = gen_event:which_handlers(my_dummy_handler),
689    ok = gen_event:sync_notify(my_dummy_handler, Event),
690    receive
691	{dummy_h, Event} ->
692	    ok
693    end,
694    ok = gen_event:sync_notify(my_dummy_handler,
695			       {swap_event, {dummy1_h, 9}, swap}),
696    [{dummy1_h,9}] = gen_event:which_handlers(my_dummy_handler),
697    ok = gen_event:sync_notify(my_dummy_handler, Event),
698    receive
699	{dummy1_h, Event} ->
700	    ok
701    end,
702    ok = gen_event:sync_notify(my_dummy_handler, delete_event),
703    receive
704	{dummy1_h, removed} ->
705	    ok
706    end,
707    [] = gen_event:which_handlers(my_dummy_handler),
708    ok = gen_event:add_handler(my_dummy_handler, {dummy_h,a}, [self()]),
709
710    ok = gen_event:sync_notify(my_dummy_handler, error_event),
711    receive
712	{dummy_h, returned_error} ->
713	    ok
714    end,
715    [] = gen_event:which_handlers(my_dummy_handler),
716
717    %% Supervised handler.
718
719    ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
720    [dummy_h] = gen_event:which_handlers(my_dummy_handler),
721    ok = gen_event:sync_notify(my_dummy_handler, Event),
722    receive
723	{dummy_h, Event} ->
724	    ok
725    end,
726
727    ok = gen_event:sync_notify(my_dummy_handler, do_crash),
728    receive
729	{gen_event_EXIT, dummy_h, {'EXIT',_}} ->
730	    ok
731    end,
732
733    ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
734    ok = gen_event:sync_notify(my_dummy_handler,
735			       {swap_event,dummy1_h,swap}),
736    [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
737
738    ok = gen_event:sync_notify(my_dummy_handler, do_crash),
739    receive
740	{gen_event_EXIT, dummy1_h, {'EXIT',_}} ->
741	    ok
742    end,
743
744    ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
745    ok = gen_event:sync_notify(my_dummy_handler,
746			       {swap_event,dummy1_h,swap}),
747    [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
748
749    ok = gen_event:sync_notify(my_dummy_handler, delete_event),
750    receive
751	{dummy1_h, removed} ->
752	    ok
753    end,
754
755    receive
756	{gen_event_EXIT, dummy1_h, normal} ->
757	    ok
758    end,
759
760    [] = gen_event:which_handlers(my_dummy_handler),
761
762    ok = gen_event:stop(my_dummy_handler),
763    ok.
764
765call(Config) when is_list(Config) ->
766    {ok,_} = gen_event:start({local, my_dummy_handler}),
767    ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
768    ok = gen_event:add_handler(my_dummy_handler, {dummy_h, 1}, [self()]),
769    [{dummy_h, 1}, dummy_h] = gen_event:which_handlers(my_dummy_handler),
770    {'EXIT',_} = (catch gen_event:call(non_exist, dummy_h, hejsan)),
771    {error, bad_module} =
772	gen_event:call(my_dummy_handler, bad_h, hejsan),
773    {ok, hejhopp} = gen_event:call(my_dummy_handler, dummy_h, hejsan),
774    {ok, hejhopp} = gen_event:call(my_dummy_handler, {dummy_h, 1},
775				   hejsan),
776    {ok, hejhopp} = gen_event:call(my_dummy_handler, dummy_h, hejsan,
777				   10000),
778    {'EXIT', {timeout, _}} =
779	(catch gen_event:call(my_dummy_handler, dummy_h, hejsan, 0)),
780    flush(),
781    ok = gen_event:delete_handler(my_dummy_handler, {dummy_h, 1}, []),
782    {ok, swapped} = gen_event:call(my_dummy_handler, dummy_h,
783				   {swap_call,dummy1_h,swap}),
784    [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
785    {error, bad_module} =
786	gen_event:call(my_dummy_handler, dummy_h, hejsan),
787    ok = gen_event:call(my_dummy_handler, dummy1_h, delete_call),
788    receive
789	{dummy1_h, removed} ->
790	    ok
791    end,
792    [] = gen_event:which_handlers(my_dummy_handler),
793    ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
794
795    {error, {return, faulty}} =
796	gen_event:call(my_dummy_handler, dummy_h, error_call),
797    receive
798	{dummy_h, returned_error} ->
799	    ok
800    end,
801    [] = gen_event:which_handlers(my_dummy_handler),
802    ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
803
804    {error, {'EXIT', _}} =
805	gen_event:call(my_dummy_handler, dummy_h, exit_call),
806
807    [] = gen_event:which_handlers(my_dummy_handler),
808
809    %% Handler with id, {Mod,Id}
810
811    ok = gen_event:add_handler(my_dummy_handler, {dummy_h,1}, [self()]),
812    [{dummy_h,1}] = gen_event:which_handlers(my_dummy_handler),
813    {error, bad_module} =
814	gen_event:call(my_dummy_handler, bad_h, hejsan),
815    {ok, hejhopp} = gen_event:call(my_dummy_handler, {dummy_h,1},
816				   hejsan),
817    {ok, swapped} = gen_event:call(my_dummy_handler, {dummy_h,1},
818				   {swap_call,{dummy1_h,2},swap}),
819    [{dummy1_h,2}] = gen_event:which_handlers(my_dummy_handler),
820    {error, bad_module} =
821	gen_event:call(my_dummy_handler, dummy_h, hejsan),
822    ok = gen_event:call(my_dummy_handler, {dummy1_h,2}, delete_call),
823    receive
824	{dummy1_h, removed} ->
825	    ok
826    end,
827    [] = gen_event:which_handlers(my_dummy_handler),
828    ok = gen_event:add_handler(my_dummy_handler, {dummy_h,3}, [self()]),
829
830    {error, {return, faulty}} =
831	gen_event:call(my_dummy_handler, {dummy_h,3}, error_call),
832    receive
833	{dummy_h, returned_error} ->
834	    ok
835    end,
836    [] = gen_event:which_handlers(my_dummy_handler),
837    ok = gen_event:add_handler(my_dummy_handler, {dummy_h,4}, [self()]),
838
839    {error, {'EXIT', _}} =
840	gen_event:call(my_dummy_handler, {dummy_h,4}, exit_call),
841
842    [] = gen_event:which_handlers(my_dummy_handler),
843
844    %% Supervised handler.
845
846    ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
847    [dummy_h] = gen_event:which_handlers(my_dummy_handler),
848    {error, bad_module} =
849	gen_event:call(my_dummy_handler, bad_h, hejsan),
850    {ok, hejhopp} = gen_event:call(my_dummy_handler, dummy_h, hejsan),
851    {ok, swapped} = gen_event:call(my_dummy_handler, dummy_h,
852				   {swap_call,dummy1_h,swap}),
853    [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
854    {error, bad_module} =
855	gen_event:call(my_dummy_handler, dummy_h, hejsan),
856    ok = gen_event:call(my_dummy_handler, dummy1_h, delete_call),
857    receive
858	{dummy1_h, removed} ->
859	    ok
860    end,
861
862    receive
863	{gen_event_EXIT, dummy1_h, normal} ->
864	    ok
865    end,
866
867    [] = gen_event:which_handlers(my_dummy_handler),
868    ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
869
870    {error, {return, faulty}} =
871	gen_event:call(my_dummy_handler, dummy_h, error_call),
872    receive
873	{dummy_h, returned_error} ->
874	    ok
875    end,
876
877    receive
878	{gen_event_EXIT, dummy_h, {return,faulty}} ->
879	    ok
880    after 1000 ->
881	    ct:fail({no, {gen_event_EXIT, dummy_h, {return,faulty}}})
882    end,
883
884    [] = gen_event:which_handlers(my_dummy_handler),
885    ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
886
887    {error, {'EXIT', _}} =
888	gen_event:call(my_dummy_handler, dummy_h, exit_call),
889
890    receive
891	{gen_event_EXIT, dummy_h, {'EXIT',_}} ->
892	    ok
893    after 1000 ->
894	    ct:fail({no, {gen_event_EXIT, dummy_h, {'EXIT','_'}}})
895    end,
896
897    [] = gen_event:which_handlers(my_dummy_handler),
898
899    ok = gen_event:stop(my_dummy_handler),
900    ok.
901
902flush() ->
903    receive _ -> flush() after 0 -> ok end.
904
905info(Config) when is_list(Config) ->
906    {ok,_} = gen_event:start({local, my_dummy_handler}),
907    ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
908    Info = {info, self()},
909    [dummy_h] = gen_event:which_handlers(my_dummy_handler),
910    my_dummy_handler ! Info,
911    receive
912	{dummy_h, Info} ->
913	    ok
914    end,
915    my_dummy_handler ! {swap_info,dummy1_h,swap},
916    [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
917    my_dummy_handler ! Info,
918    receive
919	{dummy1_h, Info} ->
920	    ok
921    end,
922    my_dummy_handler ! delete_info,
923    receive
924	{dummy1_h, removed} ->
925	    ok
926    end,
927    [] = gen_event:which_handlers(my_dummy_handler),
928    ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
929
930    my_dummy_handler ! error_info,
931    receive
932	{dummy_h, returned_error} ->
933	    ok
934    end,
935    [] = gen_event:which_handlers(my_dummy_handler),
936
937    %% Handler with id, {Mod,Id}
938
939    ok = gen_event:add_handler(my_dummy_handler, {dummy_h,1}, [self()]),
940    [{dummy_h,1}] = gen_event:which_handlers(my_dummy_handler),
941    my_dummy_handler ! Info,
942    receive
943	{dummy_h, Info} ->
944	    ok
945    end,
946    my_dummy_handler ! {swap_info,{dummy1_h,2},swap},
947    [{dummy1_h,2}] = gen_event:which_handlers(my_dummy_handler),
948    my_dummy_handler ! Info,
949    receive
950	{dummy1_h, Info} ->
951	    ok
952    end,
953    my_dummy_handler ! delete_info,
954    receive
955	{dummy1_h, removed} ->
956	    ok
957    end,
958    [] = gen_event:which_handlers(my_dummy_handler),
959    ok = gen_event:add_handler(my_dummy_handler, {dummy_h,3}, [self()]),
960
961    my_dummy_handler ! error_info,
962    receive
963	{dummy_h, returned_error} ->
964	    ok
965    end,
966    [] = gen_event:which_handlers(my_dummy_handler),
967
968    %% Supervised handler
969
970    ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
971    [dummy_h] = gen_event:which_handlers(my_dummy_handler),
972    my_dummy_handler ! Info,
973    receive
974	{dummy_h, Info} ->
975	    ok
976    end,
977    my_dummy_handler ! {swap_info,dummy1_h,swap},
978    [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
979    my_dummy_handler ! Info,
980    receive
981	{dummy1_h, Info} ->
982	    ok
983    end,
984    my_dummy_handler ! delete_info,
985    receive
986	{dummy1_h, removed} ->
987	    ok
988    end,
989
990    receive
991	{gen_event_EXIT, dummy1_h, normal} ->
992	    ok
993    after 1000 ->
994	    ct:fail({no, {gen_event_EXIT, dummy1_h, normal}})
995    end,
996
997    [] = gen_event:which_handlers(my_dummy_handler),
998
999    ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
1000
1001    my_dummy_handler ! error_info,
1002    receive
1003	{dummy_h, returned_error} ->
1004	    ok
1005    end,
1006
1007    receive
1008	{gen_event_EXIT, dummy_h, {return,faulty}} ->
1009	    ok
1010    after 1000 ->
1011	    ct:fail({no, {gen_event_EXIT, dummy_h, {return,faulty}}})
1012    end,
1013
1014    ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
1015    my_dummy_handler ! do_crash,
1016
1017    receive
1018	{gen_event_EXIT, dummy_h, {'EXIT',_}} ->
1019	    ok
1020    after 1000 ->
1021	    ct:fail({no, {gen_event_EXIT, dummy_h, {'EXIT','_'}}})
1022    end,
1023
1024    [] = gen_event:which_handlers(my_dummy_handler),
1025
1026    ok = gen_event:stop(my_dummy_handler),
1027    ok.
1028
1029%% Test that sys:get_status/1,2 calls format_status/2.
1030call_format_status(Config) when is_list(Config) ->
1031    {ok, Pid} = gen_event:start({local, my_dummy_handler}),
1032    %% State here intentionally differs from what we expect from format_status
1033    State = self(),
1034    FmtState = "dummy1_h handler state",
1035    ok = gen_event:add_handler(my_dummy_handler, dummy1_h, [State]),
1036    Status1 = sys:get_status(Pid),
1037    Status2 = sys:get_status(Pid, 5000),
1038    ok = gen_event:stop(Pid),
1039    {status, Pid, _, [_, _, Pid, [], Data1]} = Status1,
1040    HandlerInfo1 = proplists:get_value(items, Data1),
1041    {"Installed handlers", [{_,dummy1_h,_,FmtState,_}]} = HandlerInfo1,
1042    {status, Pid, _, [_, _, Pid, [], Data2]} = Status2,
1043    HandlerInfo2 = proplists:get_value(items, Data2),
1044    {"Installed handlers", [{_,dummy1_h,_,FmtState,_}]} = HandlerInfo2,
1045    ok.
1046
1047%% Test that sys:get_status/1,2 calls format_status/2 for anonymous
1048%% gen_event processes.
1049call_format_status_anon(Config) when is_list(Config) ->
1050    {ok, Pid} = gen_event:start(),
1051    %% The 'Name' of the gen_event process will be a pid() here, so
1052    %% the next line will crash if format_status can't string-ify pids.
1053    Status1 = sys:get_status(Pid),
1054    ok = gen_event:stop(Pid),
1055    Header = "Status for event handler " ++  pid_to_list(Pid),
1056    {status, Pid, _, [_, _, Pid, [], Data1]} = Status1,
1057    Header = proplists:get_value(header, Data1),
1058    ok.
1059
1060
1061%% Test that a handler error calls format_status/2.
1062error_format_status(Config) when is_list(Config) ->
1063    error_logger_forwarder:register(),
1064    OldFl = process_flag(trap_exit, true),
1065    State = self(),
1066    {ok, Pid} = gen_event:start({local, my_dummy_handler}),
1067    ok = gen_event:add_sup_handler(my_dummy_handler, dummy1_h, [State]),
1068    ok = gen_event:notify(my_dummy_handler, do_crash),
1069    receive
1070	{gen_event_EXIT,dummy1_h,{'EXIT',_}} -> ok
1071    after 5000 ->
1072	    ct:fail(exit_gen_event)
1073    end,
1074    FmtState = "dummy1_h handler state",
1075    receive
1076	{error,_GroupLeader, {Pid,
1077			      "** gen_event handler"++_,
1078			      [dummy1_h,my_dummy_handler,do_crash,
1079			       FmtState, _]}} ->
1080	    ok;
1081	Other ->
1082	    io:format("Unexpected: ~p", [Other]),
1083	    ct:fail(failed)
1084    end,
1085    ok = gen_event:stop(Pid),
1086    process_flag(trap_exit, OldFl),
1087    ok.
1088
1089%% Test that sys:get_state/1,2 return the gen_event state.
1090get_state(Config) when is_list(Config) ->
1091    {ok, Pid} = gen_event:start({local, my_dummy_handler}),
1092    State1 = self(),
1093    ok = gen_event:add_handler(my_dummy_handler, dummy1_h, [State1]),
1094    [{dummy1_h,false,State1}] = sys:get_state(Pid),
1095    [{dummy1_h,false,State1}] = sys:get_state(Pid, 5000),
1096    State2 = {?MODULE, self()},
1097    ok = gen_event:add_handler(my_dummy_handler, {dummy1_h,id}, [State2]),
1098    Result1 = sys:get_state(Pid),
1099    [{dummy1_h,false,State1},{dummy1_h,id,State2}] = lists:sort(Result1),
1100    Result2 = sys:get_state(Pid, 5000),
1101    [{dummy1_h,false,State1},{dummy1_h,id,State2}] = lists:sort(Result2),
1102    ok = sys:suspend(Pid),
1103    Result3 = sys:get_state(Pid),
1104    [{dummy1_h,false,State1},{dummy1_h,id,State2}] = lists:sort(Result3),
1105    ok = sys:resume(Pid),
1106    ok = gen_event:stop(Pid),
1107    ok.
1108
1109%% Test that replace_state/2,3 replace the gen_event state.
1110replace_state(Config) when is_list(Config) ->
1111    {ok, Pid} = gen_event:start({local, my_dummy_handler}),
1112    State1 = self(),
1113    ok = gen_event:add_handler(my_dummy_handler, dummy1_h, [State1]),
1114    [{dummy1_h,false,State1}] = sys:get_state(Pid),
1115    NState1 = "replaced",
1116    Replace1 = fun({dummy1_h,false,_}=S) -> setelement(3,S,NState1) end,
1117    [{dummy1_h,false,NState1}] = sys:replace_state(Pid, Replace1),
1118    [{dummy1_h,false,NState1}] = sys:get_state(Pid),
1119    NState2 = "replaced again",
1120    Replace2 = fun({dummy1_h,false,_}=S) -> setelement(3,S,NState2) end,
1121    [{dummy1_h,false,NState2}] = sys:replace_state(Pid, Replace2, 5000),
1122    [{dummy1_h,false,NState2}] = sys:get_state(Pid),
1123    %% verify no change in state if replace function crashes
1124    Replace3 = fun(_) -> exit(fail) end,
1125    [{dummy1_h,false,NState2}] = sys:replace_state(Pid, Replace3),
1126    [{dummy1_h,false,NState2}] = sys:get_state(Pid),
1127    %% verify state replaced if process sys suspended
1128    NState3 = "replaced again and again",
1129    Replace4 = fun({dummy1_h,false,_}=S) -> setelement(3,S,NState3) end,
1130    ok = sys:suspend(Pid),
1131    [{dummy1_h,false,NState3}] = sys:replace_state(Pid, Replace4),
1132    ok = sys:resume(Pid),
1133    [{dummy1_h,false,NState3}] = sys:get_state(Pid),
1134    ok.
1135
1136%% No default provided for init, so it should fail
1137undef_init(Config) ->
1138    Pid = ?config(event_pid, Config),
1139    {'EXIT', {undef, [{oc_init_event, init, [_], _}|_]}}
1140        = gen_event:add_handler(Pid, oc_init_event, []),
1141    ok.
1142
1143%% No default provided for init, so it should fail
1144undef_handle_call(Config) when is_list(Config) ->
1145    Pid = ?config(event_pid, Config),
1146    {error, {'EXIT', {undef, [{oc_event, handle_call, _, _}|_]}}}
1147        = gen_event:call(Pid, oc_event, call_msg),
1148    [] = gen_event:which_handlers(Pid),
1149    ok.
1150
1151%% No default provided for init, so it should fail
1152undef_handle_event(Config) ->
1153    Pid = ?config(event_pid, Config),
1154    ok = gen_event:sync_notify(Pid, event_msg),
1155    [] = gen_event:which_handlers(Pid),
1156
1157    gen_event:add_handler(oc_event, oc_event, []),
1158    [oc_event] = gen_event:which_handlers(Pid),
1159
1160    ok = gen_event:notify(Pid, event_msg),
1161    [] = gen_event:which_handlers(Pid),
1162    ok.
1163
1164%% Defaulting to doing nothing with a log warning.
1165undef_handle_info(Config) when is_list(Config) ->
1166    error_logger_forwarder:register(),
1167    Pid = ?config(event_pid, Config),
1168    Pid ! hej,
1169    wait_until_processed(Pid, hej, 10),
1170    [oc_event] = gen_event:which_handlers(Pid),
1171    receive
1172        {warning_msg, _GroupLeader,
1173         {Pid, "** Undefined handle_info in " ++ _, [oc_event, hej]}} ->
1174            ok;
1175        Other ->
1176            io:format("Unexpected: ~p", [Other]),
1177            ct:fail(failed)
1178    end.
1179
1180wait_until_processed(_Pid, _Message, 0) ->
1181    ct:fail(not_processed);
1182wait_until_processed(Pid, Message, N) ->
1183    {messages, Messages} = erlang:process_info(Pid, messages),
1184    case lists:member(Message, Messages) of
1185        true ->
1186            timer:sleep(100),
1187            wait_until_processed(Pid, Message, N-1);
1188        false ->
1189            ok
1190    end.
1191
1192%% No default provided for init, so it should fail
1193undef_code_change(Config) when is_list(Config) ->
1194    Pid = ?config(event_pid, Config),
1195    {error, {'EXIT', {undef, [{oc_event, code_change, [_, _, _], _}|_]}}} =
1196        fake_upgrade(Pid, oc_event),
1197    [oc_event] = gen_event:which_handlers(Pid),
1198    ok.
1199
1200%% Defaulting to doing nothing. Test that it works when not defined.
1201undef_terminate(Config) when is_list(Config) ->
1202    Pid = ?config(event_pid, Config),
1203    ok = gen_event:delete_handler(Pid, oc_event, []),
1204    [] = gen_event:which_handlers(Pid),
1205    ok.
1206
1207%% Test that the default implementation doesn't catch the wrong undef error
1208undef_in_terminate(_Config) ->
1209    {ok, Pid} = gen_event:start({local, dummy}),
1210    State = {undef_in_terminate, {dummy_h, terminate}},
1211    ok = gen_event:add_handler(Pid, dummy_h, {state, State}),
1212    [dummy_h] = gen_event:which_handlers(Pid),
1213    {'EXIT', {undef, [{dummy_h, terminate, [], []}|_]}}
1214        = gen_event:delete_handler(Pid, dummy_h, []),
1215    [] = gen_event:which_handlers(Pid),
1216    ok.
1217
1218fake_upgrade(Pid, Mod) ->
1219    sys:suspend(Pid),
1220    sys:replace_state(Pid, fun(S) -> {new, S} end),
1221    Ret = sys:change_code(Pid, Mod, old_vsn, []),
1222    ok = sys:resume(Pid),
1223    Ret.
1224